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

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

First attempt at inlining all DoBlock? and FinalBlock? functions by using indirect jumps. Disabled for NVPTX until Linda can check whether they're supported by the LLVM NVPTX library.

File size: 15.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
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
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
358IDISA_Builder::IDISA_Builder(Module * m, unsigned archBitWidth, unsigned bitBlockWidth, unsigned stride, const bool SupportsIndirectBr, unsigned CacheAlignment)
359: CBuilder(m, archBitWidth, SupportsIndirectBr, CacheAlignment)
360, mBitBlockWidth(bitBlockWidth)
361, mStride(stride)
362, mBitBlockType(VectorType::get(IntegerType::get(getContext(), 64), bitBlockWidth / 64))
363, mZeroInitializer(Constant::getNullValue(mBitBlockType))
364, mOneInitializer(Constant::getAllOnesValue(mBitBlockType))
365, mPrintRegisterFunction(nullptr) {
366
367}
368
369IDISA_Builder::~IDISA_Builder() {
370
371}
372
373}
Note: See TracBrowser for help on using the repository browser.