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

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

Merged PabloFunction? and PabloKernel? classes. Updated projects where necessary.

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