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

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

u8u16 progress

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