source: icGREP/icgrep-devel/icgrep/IDISA/idisa_builder.cpp @ 5076

Last change on this file since 5076 was 5076, checked in by cameron, 3 years ago

Updates for kernels with variable output length; stdout kernel

File size: 14.9 KB
Line 
1/*
2 *  Copyright (c) 2015 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 *  icgrep is a trademark of International Characters.
5 */
6
7#include "idisa_builder.h"
8#include <string>
9#include <llvm/IR/IRBuilder.h>
10#include <llvm/IR/Constants.h>
11#include <llvm/IR/Intrinsics.h>
12#include <llvm/IR/Function.h>
13#include <llvm/IR/TypeBuilder.h>
14#include <llvm/Support/raw_ostream.h>
15
16namespace IDISA {
17
18VectorType * IDISA_Builder::fwVectorType(unsigned fw) {
19    int fieldCount = mBitBlockWidth/fw;
20    return VectorType::get(getIntNTy(fw), fieldCount);
21}
22
23Value * IDISA_Builder::fwCast(unsigned fw, Value * a) {
24    return a->getType() == fwVectorType(fw) ? a : CreateBitCast(a, fwVectorType(fw));
25}
26
27std::string IDISA_Builder::getBitBlockTypeName() {
28    if (mBitBlockType->isIntegerTy()) return "i" + std::to_string(mBitBlockWidth);
29    assert(mBitBlockType->isVectorTy() || "BitBlockType is neither integer nor vector");
30    unsigned fw = mBitBlockType->getScalarSizeInBits();
31    return "v" + std::to_string(mBitBlockWidth/fw) + "i" + std::to_string(fw);
32}
33
34   
35static Function * create_printf(Module * const mod) {
36    Function * printf = mod->getFunction("printf");
37    if (printf == nullptr) {
38        FunctionType *printf_type =
39            TypeBuilder<int(char *, ...), false>::get(mod->getContext());
40        printf = cast<Function>(mod->getOrInsertFunction("printf", printf_type,
41            AttributeSet().addAttribute(mod->getContext(), 1U, Attribute::NoAlias)));
42    }
43    return printf;
44}
45
46void IDISA_Builder::CallPrintRegister(const std::string & name, Value * const value) {
47    Constant * printRegister = mMod->getFunction("PrintRegister");
48    if (LLVM_UNLIKELY(printRegister == nullptr)) {
49        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), mBitBlockType }, false);
50        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintRegister", mMod);
51        auto arg = function->arg_begin();
52        std::string tmp;
53        raw_string_ostream out(tmp);
54        out << "%-40s =";
55        for(unsigned i = 0; i < (mBitBlockWidth / 8); ++i) {
56            out << " %02x";
57        }
58        out << '\n';
59        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
60        IRBuilder<> builder(entry);
61        std::vector<Value *> args;
62        args.push_back(CreateGlobalStringPtr(out.str().c_str()));
63        Value * const name = &*(arg++);
64        name->setName("name");
65        args.push_back(name);
66        Value * value = &*arg;
67        value->setName("value");
68        Type * const byteVectorType = VectorType::get(getInt8Ty(), (mBitBlockWidth / 8));
69        value = builder.CreateBitCast(value, byteVectorType);
70        for(unsigned i = (mBitBlockWidth / 8); i != 0; --i) {
71            args.push_back(builder.CreateExtractElement(value, builder.getInt32(i - 1)));
72        }
73        builder.CreateCall(create_printf(mMod), args);
74        builder.CreateRetVoid();
75
76        printRegister = function;
77    }
78    assert (value->getType()->canLosslesslyBitCastTo(mBitBlockType));
79    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), CreateBitCast(value, mBitBlockType)});
80}
81
82void IDISA_Builder::CallPrintInt(const std::string & name, Value * const value) {
83    Constant * printRegister = mMod->getFunction("PrintInt");
84    if (LLVM_UNLIKELY(printRegister == nullptr)) {
85        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getInt64Ty() }, false);
86        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintInt", mMod);
87        auto arg = function->arg_begin();
88        std::string out = "%-40s = %" PRIi64 "\n";
89        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
90        IRBuilder<> builder(entry);
91        std::vector<Value *> args;
92        args.push_back(CreateGlobalStringPtr(out.c_str()));
93        Value * const name = &*(arg++);
94        name->setName("name");
95        args.push_back(name);
96        Value * value = &*arg;
97        value->setName("value");
98        args.push_back(value);
99        builder.CreateCall(create_printf(mMod), args);
100        builder.CreateRetVoid();
101
102        printRegister = function;
103    }
104    Value * num = nullptr;
105    if (value->getType()->isPointerTy()) {
106        num = CreatePtrToInt(value, getInt64Ty());
107    } else {
108        num = CreateZExtOrBitCast(value, getInt64Ty());
109    }
110    assert (num->getType()->isIntegerTy());
111    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), num});
112}
113
114Constant * IDISA_Builder::simd_himask(unsigned fw) {
115    return Constant::getIntegerValue(getIntNTy(mBitBlockWidth), APInt::getSplat(mBitBlockWidth, APInt::getHighBitsSet(fw, fw/2)));
116}
117
118Constant * IDISA_Builder::simd_lomask(unsigned fw) {
119    return Constant::getIntegerValue(getIntNTy(mBitBlockWidth), APInt::getSplat(mBitBlockWidth, APInt::getLowBitsSet(fw, fw/2)));
120}
121
122Value * IDISA_Builder::simd_add(unsigned fw, Value * a, Value * b) {
123return CreateAdd(fwCast(fw, a), fwCast(fw, b));
124}
125
126Value * IDISA_Builder::simd_sub(unsigned fw, Value * a, Value * b) {
127    return CreateSub(fwCast(fw, a), fwCast(fw, b));
128}
129
130Value * IDISA_Builder::simd_mult(unsigned fw, Value * a, Value * b) {
131    return CreateMul(fwCast(fw, a), fwCast(fw, b));
132}
133
134Value * IDISA_Builder::simd_eq(unsigned fw, Value * a, Value * b) {
135    return CreateSExt(CreateICmpEQ(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
136}
137
138Value * IDISA_Builder::simd_gt(unsigned fw, Value * a, Value * b) {
139    return CreateSExt(CreateICmpSGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
140}
141
142Value * IDISA_Builder::simd_ugt(unsigned fw, Value * a, Value * b) {
143    return CreateSExt(CreateICmpUGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
144}
145
146Value * IDISA_Builder::simd_lt(unsigned fw, Value * a, Value * b) {
147    return CreateSExt(CreateICmpSLT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
148}
149
150Value * IDISA_Builder::simd_ult(unsigned fw, Value * a, Value * b) {
151    return CreateSExt(CreateICmpULT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
152}
153
154Value * IDISA_Builder::simd_max(unsigned fw, Value * a, Value * b) {
155    Value * aVec = fwCast(fw, a);
156    Value * bVec = fwCast(fw, b);
157    return CreateSelect(CreateICmpSGT(aVec, bVec), aVec, bVec);
158}
159
160Value * IDISA_Builder::simd_umax(unsigned fw, Value * a, Value * b) {
161    Value * aVec = fwCast(fw, a);
162    Value * bVec = fwCast(fw, b);
163    return CreateSelect(CreateICmpUGT(aVec, bVec), aVec, bVec);
164}
165
166Value * IDISA_Builder::simd_min(unsigned fw, Value * a, Value * b) {
167    Value * aVec = fwCast(fw, a);
168    Value * bVec = fwCast(fw, b);
169    return CreateSelect(CreateICmpSLT(aVec, bVec), aVec, bVec);
170}
171
172Value * IDISA_Builder::simd_umin(unsigned fw, Value * a, Value * b) {
173    Value * aVec = fwCast(fw, a);
174    Value * bVec = fwCast(fw, b);
175    return CreateSelect(CreateICmpULT(aVec, bVec), aVec, bVec);
176}
177
178Value * IDISA_Builder::simd_slli(unsigned fw, Value * a, unsigned shift) {
179    return CreateShl(fwCast(fw, a), shift);
180}
181
182Value * IDISA_Builder::simd_srli(unsigned fw, Value * a, unsigned shift) {
183    return CreateLShr(fwCast(fw, a), shift);
184}
185
186Value * IDISA_Builder::simd_srai(unsigned fw, Value * a, unsigned shift) {
187    return CreateAShr(fwCast(fw, a), shift);
188}
189
190Value * IDISA_Builder::simd_cttz(unsigned fw, Value * a) {
191    Value * cttzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::cttz, fwVectorType(fw));
192    Value * rslt = CreateCall(cttzFunc, std::vector<Value *>({fwCast(fw, a), ConstantInt::get(getInt1Ty(), 0)}));
193    return rslt;
194}
195
196Value * IDISA_Builder::simd_popcount(unsigned fw, Value * a) {
197    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, fwVectorType(fw));
198    Value * rslt = CreateCall(ctpopFunc, std::vector<Value *>({fwCast(fw, a)}));
199    return rslt;
200}
201
202Value * IDISA_Builder::simd_if(unsigned fw, Value * cond, Value * a, Value * b) {
203    if (fw == 1) {
204        Value * a1 = bitCast(a);
205        Value * b1 = bitCast(b);
206        Value * c = bitCast(cond);
207        return CreateOr(CreateAnd(a1, c), CreateAnd(CreateXor(c, b1), b1));
208    }
209    else {
210        Value * aVec = fwCast(fw, a);
211        Value * bVec = fwCast(fw, b);
212        return CreateSelect(CreateICmpSLT(cond, mZeroInitializer), aVec, bVec);
213    }
214}
215
216   
217Value * IDISA_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {
218    unsigned field_count = mBitBlockWidth/fw;
219    Value * aVec = fwCast(fw, a);
220    Value * bVec = fwCast(fw, b);
221    std::vector<Constant*> Idxs;
222    for (unsigned i = field_count/2; i < field_count; i++) {
223        Idxs.push_back(getInt32(i));    // selects elements from first reg.
224        Idxs.push_back(getInt32(i + field_count)); // selects elements from second reg.
225    }
226    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
227}
228
229Value * IDISA_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {
230    unsigned field_count = mBitBlockWidth/fw;
231    Value * aVec = fwCast(fw, a);
232    Value * bVec = fwCast(fw, b);
233    std::vector<Constant*> Idxs;
234    for (unsigned i = 0; i < field_count/2; i++) {
235        Idxs.push_back(getInt32(i));    // selects elements from first reg.
236        Idxs.push_back(getInt32(i + field_count)); // selects elements from second reg.
237    }
238    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
239}
240
241Value * IDISA_Builder::esimd_bitspread(unsigned fw, Value * bitmask) {
242    unsigned field_count = mBitBlockWidth/fw;
243    Type * field_type = getIntNTy(fw);
244    if (bitmask->getType()->getIntegerBitWidth() < fw) {
245        bitmask = CreateZExt(bitmask, field_type);
246    }
247    else if (bitmask->getType()->getIntegerBitWidth() > fw) {
248        bitmask = CreateTrunc(bitmask, field_type);
249    }
250    Value * spread_field = CreateBitCast(bitmask, VectorType::get(getIntNTy(fw), 1));
251    Value * undefVec = UndefValue::get(VectorType::get(getIntNTy(fw), 1));
252    Value * broadcast = CreateShuffleVector(spread_field, undefVec, Constant::getNullValue(VectorType::get(getInt32Ty(), field_count)));
253    std::vector<Constant*> bitSel;
254    std::vector<Constant*> bitShift;
255    for (unsigned i = 0; i < field_count; i++) {
256        bitSel.push_back(ConstantInt::get(field_type, 1 << i));
257        bitShift.push_back(ConstantInt::get(field_type, i));
258    }
259    Value * bitSelVec = ConstantVector::get(bitSel);
260    Value * bitShiftVec = ConstantVector::get(bitShift);
261    return CreateLShr(CreateAnd(bitSelVec, broadcast), bitShiftVec);
262}
263
264Value * IDISA_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
265    unsigned field_count = 2 * mBitBlockWidth/fw;
266    Value * aVec = fwCast(fw/2, a);
267    Value * bVec = fwCast(fw/2, b);
268    std::vector<Constant*> Idxs;
269    for (unsigned i = 0; i < field_count; i++) {
270        Idxs.push_back(getInt32(2*i+1));
271    }
272    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
273}
274
275Value * IDISA_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
276    unsigned field_count = 2 * mBitBlockWidth/fw;
277    Value * aVec = fwCast(fw/2, a);
278    Value * bVec = fwCast(fw/2, b);
279    std::vector<Constant*> Idxs;
280    for (unsigned i = 0; i < field_count; i++) {
281        Idxs.push_back(getInt32(2*i));
282    }
283    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
284}
285
286   
287Value * IDISA_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
288    unsigned fw_out = fw/2;
289    unsigned fields_per_lane = mBitBlockWidth/(fw_out * lanes);
290    unsigned field_offset_for_b = mBitBlockWidth/fw_out;
291    Value * aVec = fwCast(fw_out, a);
292    Value * bVec = fwCast(fw_out, b);
293    std::vector<Constant*> Idxs;
294    for (unsigned lane = 0; lane < lanes; lane++) {
295        unsigned first_field_in_lane = lane * fields_per_lane; // every second field
296        for (unsigned i = 0; i < fields_per_lane/2; i++) {
297            Idxs.push_back(getInt32(first_field_in_lane + 2*i + 1));
298        }
299        for (unsigned i = 0; i < fields_per_lane/2; i++) {
300            Idxs.push_back(getInt32(field_offset_for_b + first_field_in_lane + 2*i + 1));
301        }
302    }
303    Value * pack = CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
304    return pack;
305}
306
307Value * IDISA_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
308    unsigned fw_out = fw/2;
309    unsigned fields_per_lane = mBitBlockWidth/(fw_out * lanes);
310    unsigned field_offset_for_b = mBitBlockWidth/fw_out;
311    Value * aVec = fwCast(fw_out, a);
312    Value * bVec = fwCast(fw_out, b);
313    std::vector<Constant*> Idxs;
314    for (unsigned lane = 0; lane < lanes; lane++) {
315        unsigned first_field_in_lane = lane * fields_per_lane; // every second field
316        for (unsigned i = 0; i < fields_per_lane/2; i++) {
317            Idxs.push_back(getInt32(first_field_in_lane + 2*i));
318        }
319        for (unsigned i = 0; i < fields_per_lane/2; i++) {
320            Idxs.push_back(getInt32(field_offset_for_b + first_field_in_lane + 2*i));
321        }
322    }
323    Value * pack = CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
324    return pack;
325}
326
327   
328Value * IDISA_Builder::hsimd_signmask(unsigned fw, Value * a) {
329    Value * mask = CreateICmpSLT(fwCast(fw, a), ConstantAggregateZero::get(fwVectorType(fw)));
330    return CreateZExt(CreateBitCast(mask, getIntNTy(mBitBlockWidth/fw)), getInt32Ty());
331}
332
333Value * IDISA_Builder::mvmd_extract(unsigned fw, Value * a, unsigned fieldIndex) {
334    Value * aVec = fwCast(fw, a);
335    return CreateExtractElement(aVec, getInt32(fieldIndex));
336}
337
338Value * IDISA_Builder::mvmd_insert(unsigned fw, Value * blk, Value * elt, unsigned fieldIndex) {
339    Value * vec = fwCast(fw, blk);
340    return CreateInsertElement(vec, elt, getInt32(fieldIndex));
341}
342
343Value * IDISA_Builder::mvmd_slli(unsigned fw, Value * a, unsigned shift) {
344    unsigned field_count = mBitBlockWidth/fw;
345    return mvmd_dslli(fw, a, Constant::getNullValue(fwVectorType(fw)), field_count - shift);
346}
347
348Value * IDISA_Builder::mvmd_srli(unsigned fw, Value * a, unsigned shift) {
349    return mvmd_dslli(fw, Constant::getNullValue(fwVectorType(fw)), a, shift);
350}
351
352Value * IDISA_Builder::mvmd_dslli(unsigned fw, Value * a, Value * b, unsigned shift) {
353    unsigned field_count = mBitBlockWidth/fw;
354    Value * aVec = fwCast(fw, a);
355    Value * bVec = fwCast(fw, b);
356    std::vector<Constant*> Idxs;
357    for (unsigned i = 0; i < field_count; i++) {
358        Idxs.push_back(getInt32(i + shift));
359    }
360    return CreateShuffleVector(bVec, aVec, ConstantVector::get(Idxs));
361}
362
363Value * IDISA_Builder::bitblock_any(Value * a) {
364    Type * iBitBlock = getIntNTy(mBitBlockWidth);
365    return CreateICmpNE(CreateBitCast(a, iBitBlock),  ConstantInt::get(iBitBlock, 0));
366}
367
368Value * IDISA_Builder::simd_and(Value * a, Value * b) {
369    return a->getType() == b->getType() ? CreateAnd(a, b) : CreateAnd(bitCast(a), bitCast(b));
370}
371
372Value * IDISA_Builder::simd_or(Value * a, Value * b) {
373    return a->getType() == b->getType() ? CreateOr(a, b) : CreateOr(bitCast(a), bitCast(b));
374}
375   
376Value * IDISA_Builder::simd_xor(Value * a, Value * b) {
377    return a->getType() == b->getType() ? CreateXor(a, b) : CreateXor(bitCast(a), bitCast(b));
378}
379
380Value * IDISA_Builder::simd_not(Value * a) {
381    return simd_xor(a, Constant::getAllOnesValue(a->getType()));
382}
383
384}
Note: See TracBrowser for help on using the repository browser.