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

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

Changes working towards simplifying accessing stream elements + some modifications to simplify include / forward declarations within the CodeGen? library.

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