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

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

Moved toolchain and object_cache to kernels directory. Continued work on providing input consumed information.

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