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

Last change on this file since 5240 was 5240, checked in by nmedfort, 18 months ago

Cleaned up memory leaks + some warning messages.

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