source: icGREP/icgrep-devel/icgrep/IR_Gen/idisa_builder.cpp @ 5486

Last change on this file since 5486 was 5454, checked in by nmedfort, 2 years ago

Bug fix check in for DumpTrace?, compilation of DoBlock? / DoFinalBlock? functions. Pablo CodeMotionPass? optimized and enabled by default.

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