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

Last change on this file since 5202 was 5202, checked in by nmedfort, 3 years ago

Initial work on adding types to PabloAST and mutable Var objects.

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