source: icGREP/icgrep-devel/icgrep/IDISA/idisa_builder.cpp @ 5204

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

More 32-bit fixes.

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