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

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

Bug fix for last checkin: canLosslesslyBitCastTo does not think i128 can losslessly bit cast to <1 xi128>

File size: 15.4 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(const unsigned fw) {
21    return VectorType::get(getIntNTy(fw), mBitBlockWidth / fw);
22}
23
24Value * IDISA_Builder::fwCast(const unsigned fw, Value * const a) {
25    VectorType * const ty = fwVectorType(fw);
26    assert (a->getType()->getPrimitiveSizeInBits() == ty->getPrimitiveSizeInBits());
27    return CreateBitCast(a, ty);
28}
29
30std::string IDISA_Builder::getBitBlockTypeName() const {
31    const auto type = getBitBlockType();
32    if (type->isIntegerTy()) {
33        return "i" + std::to_string(getBitBlockWidth());
34    }
35    assert("BitBlockType is neither integer nor vector" && type->isVectorTy());
36    const auto fw = type->getScalarSizeInBits();
37    return "v" + std::to_string(getBitBlockWidth() / fw) + "i" + std::to_string(fw);
38}
39
40
41void IDISA_Builder::CallPrintRegister(const std::string & name, Value * const value) {
42    Constant * printRegister = mMod->getFunction("PrintRegister");
43    if (LLVM_UNLIKELY(printRegister == nullptr)) {
44        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getBitBlockType() }, false);
45        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintRegister", mMod);
46        auto arg = function->arg_begin();
47        std::string tmp;
48        raw_string_ostream out(tmp);
49        out << "%-40s =";
50        for(unsigned i = 0; i < (mBitBlockWidth / 8); ++i) {
51            out << " %02x";
52        }
53        out << '\n';
54        BasicBlock * entry = BasicBlock::Create(mMod->getContext(), "entry", function);
55        IRBuilder<> builder(entry);
56        std::vector<Value *> args;
57        args.push_back(CreateGlobalStringPtr(out.str().c_str()));
58        Value * const name = &*(arg++);
59        name->setName("name");
60        args.push_back(name);
61        Value * value = &*arg;
62        value->setName("value");
63        Type * const byteVectorType = VectorType::get(getInt8Ty(), (mBitBlockWidth / 8));
64        value = builder.CreateBitCast(value, byteVectorType);
65        for(unsigned i = (mBitBlockWidth / 8); i != 0; --i) {
66            args.push_back(builder.CreateExtractElement(value, builder.getInt32(i - 1)));
67        }
68        builder.CreateCall(GetPrintf(), args);
69        builder.CreateRetVoid();
70
71        printRegister = function;
72    }
73    if (value->getType()->canLosslesslyBitCastTo(mBitBlockType)) {
74        CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), CreateBitCast(value, mBitBlockType)});
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    return CreateCall(cttzFunc, {fwCast(fw, a), ConstantInt::get(getInt1Ty(), 0)});
164}
165
166Value * IDISA_Builder::simd_popcount(unsigned fw, Value * a) {
167    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, fwVectorType(fw));
168    return CreateCall(ctpopFunc, fwCast(fw, a));
169}
170
171Value * IDISA_Builder::simd_if(unsigned fw, Value * cond, Value * a, Value * b) {
172    if (fw == 1) {
173        Value * a1 = bitCast(a);
174        Value * b1 = bitCast(b);
175        Value * c = bitCast(cond);
176        return CreateOr(CreateAnd(a1, c), CreateAnd(CreateXor(c, b1), b1));
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   
184Value * IDISA_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {   
185    const auto field_count = mBitBlockWidth / fw;
186    Constant * Idxs[field_count];
187    for (unsigned i = 0; i < field_count / 2; i++) {
188        Idxs[2 * i] = getInt32(i + field_count / 2); // selects elements from first reg.
189        Idxs[2 * i + 1] = getInt32(i + field_count / 2 + field_count); // selects elements from second reg.
190    }
191    return CreateShuffleVector(fwCast(fw, a), fwCast(fw, b), ConstantVector::get({Idxs, field_count}));
192}
193
194Value * IDISA_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {   
195    const auto field_count = mBitBlockWidth / fw;
196    Constant * Idxs[field_count];
197    for (unsigned i = 0; i < field_count / 2; i++) {
198        Idxs[2 * i] = getInt32(i); // selects elements from first reg.
199        Idxs[2 * i + 1] = getInt32(i + field_count); // selects elements from second reg.
200    }
201    return CreateShuffleVector(fwCast(fw, a), fwCast(fw, b), ConstantVector::get({Idxs, field_count}));
202}
203
204Value * IDISA_Builder::esimd_bitspread(unsigned fw, Value * bitmask) {
205    const auto field_count = mBitBlockWidth / fw;
206    Type * field_type = getIntNTy(fw);
207    Value * spread_field = CreateBitCast(CreateZExtOrTrunc(bitmask, field_type), VectorType::get(getIntNTy(fw), 1));
208    Value * undefVec = UndefValue::get(VectorType::get(getIntNTy(fw), 1));
209    Value * broadcast = CreateShuffleVector(spread_field, undefVec, Constant::getNullValue(VectorType::get(getInt32Ty(), field_count)));
210    Constant * bitSel[field_count];
211    Constant * bitShift[field_count];
212    for (unsigned i = 0; i < field_count; i++) {
213        bitSel[i] = ConstantInt::get(field_type, 1 << i);
214        bitShift[i] = ConstantInt::get(field_type, i);
215    }
216    Value * bitSelVec = ConstantVector::get({bitSel, field_count});
217    Value * bitShiftVec = ConstantVector::get({bitShift, field_count});
218    return CreateLShr(CreateAnd(bitSelVec, broadcast), bitShiftVec);
219}
220
221Value * IDISA_Builder::hsimd_packh(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 + 1);
228    }
229    return CreateShuffleVector(aVec, bVec, ConstantVector::get({Idxs, field_count}));
230}
231
232Value * IDISA_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
233    Value * aVec = fwCast(fw/2, a);
234    Value * bVec = fwCast(fw/2, b);
235    const auto field_count = 2 * mBitBlockWidth / fw;
236    Constant * Idxs[field_count];
237    for (unsigned i = 0; i < field_count; i++) {
238        Idxs[i] = getInt32(2 * i);
239    }
240    return CreateShuffleVector(aVec, bVec, ConstantVector::get({Idxs, field_count}));
241}
242
243Value * IDISA_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
244    const unsigned fw_out = fw / 2;
245    const unsigned fields_per_lane = mBitBlockWidth / (fw_out * lanes);
246    const unsigned field_offset_for_b = mBitBlockWidth / fw_out;
247    const unsigned field_count = mBitBlockWidth / fw_out;
248    Constant * Idxs[field_count];
249    for (unsigned lane = 0, j = 0; lane < lanes; lane++) {
250        const unsigned first_field_in_lane = lane * fields_per_lane; // every second field
251        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
252            Idxs[j++] = getInt32(first_field_in_lane + (2 * i) + 1);
253        }
254        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
255            Idxs[j++] = getInt32(field_offset_for_b + first_field_in_lane + (2 * i) + 1);
256        }
257    }
258    return CreateShuffleVector(fwCast(fw_out, a), fwCast(fw_out, b), ConstantVector::get({Idxs, field_count}));
259}
260
261Value * IDISA_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
262    const unsigned fw_out = fw / 2;
263    const unsigned fields_per_lane = mBitBlockWidth / (fw_out * lanes);
264    const unsigned field_offset_for_b = mBitBlockWidth / fw_out;
265    const unsigned field_count = mBitBlockWidth / fw_out;
266    Constant * Idxs[field_count];
267    for (unsigned lane = 0, j = 0; lane < lanes; lane++) {
268        const unsigned first_field_in_lane = lane * fields_per_lane; // every second field
269        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
270            Idxs[j++] = getInt32(first_field_in_lane + (2 * i));
271        }
272        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
273            Idxs[j++] = getInt32(field_offset_for_b + first_field_in_lane + (2 * i));
274        }
275    }
276    return CreateShuffleVector(fwCast(fw_out, a), fwCast(fw_out, b), ConstantVector::get({Idxs, field_count}));
277}
278
279Value * IDISA_Builder::hsimd_signmask(unsigned fw, Value * a) {
280    Value * mask = CreateICmpSLT(fwCast(fw, a), ConstantAggregateZero::get(fwVectorType(fw)));
281    return CreateZExt(CreateBitCast(mask, getIntNTy(mBitBlockWidth/fw)), getInt32Ty());
282}
283
284Value * IDISA_Builder::mvmd_extract(unsigned fw, Value * a, unsigned fieldIndex) {
285    return CreateExtractElement(fwCast(fw, a), getInt32(fieldIndex));
286}
287
288Value * IDISA_Builder::mvmd_insert(unsigned fw, Value * blk, Value * elt, unsigned fieldIndex) {
289    return CreateInsertElement(fwCast(fw, blk), elt, getInt32(fieldIndex));
290}
291
292Value * IDISA_Builder::mvmd_slli(unsigned fw, Value * a, unsigned shift) {
293    const auto field_count = mBitBlockWidth / fw;
294    return mvmd_dslli(fw, a, Constant::getNullValue(fwVectorType(fw)), field_count - shift);
295}
296
297Value * IDISA_Builder::mvmd_srli(unsigned fw, Value * a, unsigned shift) {
298    return mvmd_dslli(fw, Constant::getNullValue(fwVectorType(fw)), a, shift);
299}
300
301Value * IDISA_Builder::mvmd_dslli(unsigned fw, Value * a, Value * b, unsigned shift) {
302    const auto field_count = mBitBlockWidth/fw;
303    Constant * Idxs[field_count];
304    for (unsigned i = 0; i < field_count; i++) {
305        Idxs[i] = getInt32(i + shift);
306    }
307    return CreateShuffleVector(fwCast(fw, b), fwCast(fw, a), ConstantVector::get({Idxs, field_count}));
308}
309
310Value * IDISA_Builder::bitblock_any(Value * a) {
311    Type * iBitBlock = getIntNTy(mBitBlockWidth);
312    return CreateICmpNE(CreateBitCast(a, iBitBlock),  ConstantInt::getNullValue(iBitBlock));
313}
314
315// full add producing {carryout, sum}
316std::pair<Value *, Value *> IDISA_Builder::bitblock_add_with_carry(Value * a, Value * b, Value * carryin) {
317    Value * carrygen = simd_and(a, b);
318    Value * carryprop = simd_or(a, b);
319    Value * sum = simd_add(mBitBlockWidth, simd_add(mBitBlockWidth, a, b), carryin);
320    Value * carryout = CreateBitCast(simd_or(carrygen, simd_and(carryprop, CreateNot(sum))), getIntNTy(mBitBlockWidth));
321    return std::pair<Value *, Value *>(bitCast(simd_srli(mBitBlockWidth, carryout, mBitBlockWidth - 1)), bitCast(sum));
322}
323
324// full shift producing {shiftout, shifted}
325std::pair<Value *, Value *> IDISA_Builder::bitblock_advance(Value * a, Value * shiftin, unsigned shift) {
326    Value * shiftin_bitblock = CreateBitCast(shiftin, getIntNTy(mBitBlockWidth));
327    Value * a_bitblock = CreateBitCast(a, getIntNTy(mBitBlockWidth));
328    Value * shifted = bitCast(CreateOr(CreateShl(a_bitblock, shift), shiftin_bitblock));
329    Value * shiftout = bitCast(CreateLShr(a_bitblock, mBitBlockWidth - shift));
330    return std::pair<Value *, Value *>(shiftout, shifted);
331}
332
333Value * IDISA_Builder::bitblock_mask_from(Value * pos) {
334    Type * bitBlockInt = getIntNTy(getBitBlockWidth());
335    return bitCast(CreateShl(ConstantInt::getAllOnesValue(bitBlockInt), CreateZExt(pos, bitBlockInt)));
336   
337}
338Value * IDISA_Builder::bitblock_set_bit(Value * pos) {
339    Type * bitBlockInt = getIntNTy(getBitBlockWidth());
340    return bitCast(CreateShl(ConstantInt::get(bitBlockInt, 1), CreateZExt(pos, bitBlockInt)));
341}
342
343Value * IDISA_Builder::simd_and(Value * a, Value * b) {
344    return a->getType() == b->getType() ? CreateAnd(a, b) : CreateAnd(bitCast(a), bitCast(b));
345}
346
347Value * IDISA_Builder::simd_or(Value * a, Value * b) {
348    return a->getType() == b->getType() ? CreateOr(a, b) : CreateOr(bitCast(a), bitCast(b));
349}
350   
351Value * IDISA_Builder::simd_xor(Value * a, Value * b) {
352    return a->getType() == b->getType() ? CreateXor(a, b) : CreateXor(bitCast(a), bitCast(b));
353}
354
355Value * IDISA_Builder::simd_not(Value * a) {
356    return simd_xor(a, Constant::getAllOnesValue(a->getType()));
357}
358
359IDISA_Builder::IDISA_Builder(Module * m, unsigned archBitWidth, unsigned bitBlockWidth, unsigned stride, const bool SupportsIndirectBr, unsigned CacheAlignment)
360: CBuilder(m, archBitWidth, SupportsIndirectBr, CacheAlignment)
361, mBitBlockWidth(bitBlockWidth)
362, mStride(stride)
363, mBitBlockType(VectorType::get(IntegerType::get(getContext(), 64), bitBlockWidth / 64))
364, mZeroInitializer(Constant::getNullValue(mBitBlockType))
365, mOneInitializer(Constant::getAllOnesValue(mBitBlockType))
366, mPrintRegisterFunction(nullptr) {
367
368}
369
370IDISA_Builder::~IDISA_Builder() {
371
372}
373
374}
Note: See TracBrowser for help on using the repository browser.