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

Last change on this file since 4881 was 4881, checked in by cameron, 3 years ago

Parallel long addition within icgrep improves performance on AVX2

File size: 11.0 KB
RevLine 
[4651]1/*
2 *  Copyright (c) 2015 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
[4665]13namespace IDISA {
[4651]14
15VectorType * IDISA_Builder::fwVectorType(unsigned fw) {
[4827]16    int fieldCount = mBitBlockWidth/fw;
[4665]17    return VectorType::get(mLLVMBuilder->getIntNTy(fw), fieldCount);
[4651]18}
19
20Value * IDISA_Builder::fwCast(unsigned fw, Value * a) {
[4837]21    return a->getType() == fwVectorType(fw) ? a : mLLVMBuilder->CreateBitCast(a, fwVectorType(fw));
[4651]22}
23
[4843]24void IDISA_Builder::genPrintRegister(std::string regName, Value * bitblockValue) {
25    if (mPrintRegisterFunction == nullptr) {
26        mPrintRegisterFunction = mMod->getOrInsertFunction("wrapped_print_register", Type::getVoidTy(mMod->getContext()), Type::getInt8PtrTy(mMod->getContext()), mBitBlockType, NULL);
27    }
28    Constant * regNameData = ConstantDataArray::getString(mMod->getContext(), regName);
29    GlobalVariable *regStrVar = new GlobalVariable(*mMod,
30                                                   ArrayType::get(IntegerType::get(mMod->getContext(), 8), regName.length()+1),
31                                                   /*isConstant=*/ true,
32                                                   /*Linkage=*/ GlobalValue::PrivateLinkage,
33                                                   /*Initializer=*/ regNameData);
34    Value * regStrPtr = mLLVMBuilder->CreateGEP(regStrVar, std::vector<Value *>({mLLVMBuilder->getInt64(0), mLLVMBuilder->getInt32(0)}));
[4845]35    mLLVMBuilder->CreateCall(mPrintRegisterFunction, std::vector<Value *>({regStrPtr, bitCast(bitblockValue)}));
[4843]36}
37
38   
[4651]39Value * IDISA_Builder::simd_add(unsigned fw, Value * a, Value * b) {
[4837]40    return mLLVMBuilder->CreateAdd(fwCast(fw, a), fwCast(fw, b));
[4651]41}
42
43Value * IDISA_Builder::simd_sub(unsigned fw, Value * a, Value * b) {
[4837]44    return mLLVMBuilder->CreateSub(fwCast(fw, a), fwCast(fw, b));
[4651]45}
46
47Value * IDISA_Builder::simd_mult(unsigned fw, Value * a, Value * b) {
[4837]48    return mLLVMBuilder->CreateMul(fwCast(fw, a), fwCast(fw, b));
[4651]49}
50
51Value * IDISA_Builder::simd_eq(unsigned fw, Value * a, Value * b) {
[4837]52    return mLLVMBuilder->CreateSExt(mLLVMBuilder->CreateICmpEQ(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]53}
54
55Value * IDISA_Builder::simd_gt(unsigned fw, Value * a, Value * b) {
[4837]56    return mLLVMBuilder->CreateSExt(mLLVMBuilder->CreateICmpSGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]57}
58
59Value * IDISA_Builder::simd_ugt(unsigned fw, Value * a, Value * b) {
[4837]60    return mLLVMBuilder->CreateSExt(mLLVMBuilder->CreateICmpUGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]61}
62
63Value * IDISA_Builder::simd_lt(unsigned fw, Value * a, Value * b) {
[4837]64    return mLLVMBuilder->CreateSExt(mLLVMBuilder->CreateICmpSLT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]65}
66
67Value * IDISA_Builder::simd_ult(unsigned fw, Value * a, Value * b) {
[4837]68    return mLLVMBuilder->CreateSExt(mLLVMBuilder->CreateICmpULT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]69}
70
71Value * IDISA_Builder::simd_max(unsigned fw, Value * a, Value * b) {
72    Value * aVec = fwCast(fw, a);
73    Value * bVec = fwCast(fw, b);
[4837]74    return mLLVMBuilder->CreateSelect(mLLVMBuilder->CreateICmpSGT(aVec, bVec), aVec, bVec);
[4651]75}
76
77Value * IDISA_Builder::simd_umax(unsigned fw, Value * a, Value * b) {
78    Value * aVec = fwCast(fw, a);
79    Value * bVec = fwCast(fw, b);
[4837]80    return mLLVMBuilder->CreateSelect(mLLVMBuilder->CreateICmpUGT(aVec, bVec), aVec, bVec);
[4651]81}
82
83Value * IDISA_Builder::simd_min(unsigned fw, Value * a, Value * b) {
84    Value * aVec = fwCast(fw, a);
85    Value * bVec = fwCast(fw, b);
[4837]86    return mLLVMBuilder->CreateSelect(mLLVMBuilder->CreateICmpSLT(aVec, bVec), aVec, bVec);
[4651]87}
88
89Value * IDISA_Builder::simd_umin(unsigned fw, Value * a, Value * b) {
90    Value * aVec = fwCast(fw, a);
91    Value * bVec = fwCast(fw, b);
[4837]92    return mLLVMBuilder->CreateSelect(mLLVMBuilder->CreateICmpULT(aVec, bVec), aVec, bVec);
[4651]93}
94
95Value * IDISA_Builder::simd_slli(unsigned fw, Value * a, unsigned shift) {
[4837]96    return mLLVMBuilder->CreateShl(fwCast(fw, a), shift);
[4651]97}
98
99Value * IDISA_Builder::simd_srli(unsigned fw, Value * a, unsigned shift) {
[4837]100    return mLLVMBuilder->CreateLShr(fwCast(fw, a), shift);
[4651]101}
102
103Value * IDISA_Builder::simd_srai(unsigned fw, Value * a, unsigned shift) {
[4837]104    return mLLVMBuilder->CreateAShr(fwCast(fw, a), shift);
[4651]105}
106
107Value * IDISA_Builder::simd_cttz(unsigned fw, Value * a) {
108    Value * cttzFunc = Intrinsic::getDeclaration(mMod, Intrinsic::cttz, fwVectorType(fw));
[4750]109    Value * rslt = mLLVMBuilder->CreateCall(cttzFunc, std::vector<Value *>({fwCast(fw, a), ConstantInt::get(mLLVMBuilder->getInt1Ty(), 0)}));
[4837]110    return rslt;
[4651]111}
112
[4720]113Value * IDISA_Builder::simd_popcount(unsigned fw, Value * a) {
114    Value * ctpopFunc = Intrinsic::getDeclaration(mMod, Intrinsic::ctpop, fwVectorType(fw));
[4750]115    Value * rslt = mLLVMBuilder->CreateCall(ctpopFunc, std::vector<Value *>({fwCast(fw, a)}));
[4837]116    return rslt;
[4720]117}
118
[4652]119Value * IDISA_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {
[4827]120    unsigned field_count = mBitBlockWidth/fw;
[4652]121    Value * aVec = fwCast(fw, a);
122    Value * bVec = fwCast(fw, b);
123    std::vector<Constant*> Idxs;
124    for (unsigned i = field_count/2; i < field_count; i++) {
[4665]125        Idxs.push_back(mLLVMBuilder->getInt32(i));    // selects elements from first reg.
126        Idxs.push_back(mLLVMBuilder->getInt32(i + field_count)); // selects elements from second reg.
[4652]127    }
[4837]128    return mLLVMBuilder->CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
[4652]129}
130
131Value * IDISA_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {
[4827]132    unsigned field_count = mBitBlockWidth/fw;
[4652]133    Value * aVec = fwCast(fw, a);
134    Value * bVec = fwCast(fw, b);
135    std::vector<Constant*> Idxs;
136    for (unsigned i = 0; i < field_count/2; i++) {
[4665]137        Idxs.push_back(mLLVMBuilder->getInt32(i));    // selects elements from first reg.
138        Idxs.push_back(mLLVMBuilder->getInt32(i + field_count)); // selects elements from second reg.
[4652]139    }
[4837]140    return mLLVMBuilder->CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
[4652]141}
142
[4879]143Value * IDISA_Builder:: esimd_bitspread(unsigned fw, Value * bitmask) {
144    unsigned field_count = mBitBlockWidth/fw;
145    Type * field_type = mLLVMBuilder->getIntNTy(fw);
146    if (bitmask->getType()->getIntegerBitWidth() < fw) {
147        bitmask = mLLVMBuilder->CreateZExt(bitmask, field_type);
148    }
149    else if (bitmask->getType()->getIntegerBitWidth() > fw) {
150        bitmask = mLLVMBuilder->CreateTrunc(bitmask, field_type);
151    }
152    Value * spread_field = mLLVMBuilder->CreateBitCast(bitmask, VectorType::get(mLLVMBuilder->getIntNTy(fw), 1));
153    Value * undefVec = UndefValue::get(VectorType::get(mLLVMBuilder->getIntNTy(fw), 1));
154    Value * broadcast = mLLVMBuilder->CreateShuffleVector(spread_field, undefVec, Constant::getNullValue(VectorType::get(mLLVMBuilder->getInt32Ty(), field_count)));
155    std::vector<Constant*> bitSel;
156    std::vector<Constant*> bitShift;
157    for (unsigned i = 0; i < field_count; i++) {
158        bitSel.push_back(ConstantInt::get(field_type, 1 << i));
159        bitShift.push_back(ConstantInt::get(field_type, i));
160    }
161    Value * bitSelVec = ConstantVector::get(bitSel);
162    Value * bitShiftVec = ConstantVector::get(bitShift);
163    return mLLVMBuilder->CreateLShr(mLLVMBuilder->CreateAnd(bitSelVec, broadcast), bitShiftVec);
164}
165
[4653]166Value * IDISA_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
[4827]167    unsigned field_count = 2 * mBitBlockWidth/fw;
[4653]168    Value * aVec = fwCast(fw/2, a);
169    Value * bVec = fwCast(fw/2, b);
170    std::vector<Constant*> Idxs;
171    for (unsigned i = 0; i < field_count; i++) {
[4665]172        Idxs.push_back(mLLVMBuilder->getInt32(2*i));
[4653]173    }
[4837]174    return mLLVMBuilder->CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
[4653]175}
[4652]176
[4653]177Value * IDISA_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
[4827]178    unsigned field_count = 2 * mBitBlockWidth/fw;
[4653]179    Value * aVec = fwCast(fw/2, a);
180    Value * bVec = fwCast(fw/2, b);
181    std::vector<Constant*> Idxs;
182    for (unsigned i = 0; i < field_count; i++) {
[4665]183        Idxs.push_back(mLLVMBuilder->getInt32(2*i+1));
[4653]184    }
[4837]185    return mLLVMBuilder->CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
[4653]186}
[4652]187
[4881]188#if (BLOCK_SIZE==256)
189#define SIGNMASK_AVX2
190#endif
191
[4653]192Value * IDISA_Builder::hsimd_signmask(unsigned fw, Value * a) {
[4881]193#ifdef SIGNMASK_AVX2
194    if (fw == 64) {
195        Value * signmask_f64func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx_movmsk_pd_256);
196        Type * bitBlock_f64type = VectorType::get(mLLVMBuilder->getDoubleTy(), mBitBlockWidth/64);
197        Value * a_as_pd = mLLVMBuilder->CreateBitCast(a, bitBlock_f64type);
198        Value * mask = mLLVMBuilder->CreateCall(signmask_f64func, std::vector<Value *>({a_as_pd}));
199        return mask;
200    }
201    else if (fw == 32) {
202        Value * signmask_f32func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx_movmsk_ps_256);
203        Type * bitBlock_f32type = VectorType::get(mLLVMBuilder->getFloatTy(), mBitBlockWidth/32);
204        Value * a_as_ps = mLLVMBuilder->CreateBitCast(a, bitBlock_f32type);
205        Value * mask = mLLVMBuilder->CreateCall(signmask_f32func, std::vector<Value *>({a_as_ps}));
206        return mask;
207    }
208#endif
[4665]209    Value * mask = mLLVMBuilder->CreateICmpSLT(fwCast(fw, a), ConstantAggregateZero::get(fwVectorType(fw)));
[4827]210    return mLLVMBuilder->CreateBitCast(mask, mLLVMBuilder->getIntNTy(mBitBlockWidth/fw));
[4653]211}
212
[4697]213Value * IDISA_Builder::mvmd_extract(unsigned fw, Value * a, unsigned fieldIndex) {
214    Value * aVec = fwCast(fw, a);
215    return mLLVMBuilder->CreateExtractElement(aVec, mLLVMBuilder->getInt32(fieldIndex));
216}
217
[4881]218Value * IDISA_Builder::mvmd_insert(unsigned fw, Value * blk, Value * elt, unsigned fieldIndex) {
219    Value * vec = fwCast(fw, blk);
220    return mLLVMBuilder->CreateInsertElement(vec, elt, mLLVMBuilder->getInt32(fieldIndex));
221}
222
[4655]223Value * IDISA_Builder::mvmd_dslli(unsigned fw, Value * a, Value * b, unsigned shift) {
[4827]224    unsigned field_count = mBitBlockWidth/fw;
[4655]225    Value * aVec = fwCast(fw, a);
226    Value * bVec = fwCast(fw, b);
227    std::vector<Constant*> Idxs;
[4845]228    for (unsigned i = 0; i < field_count; i++) {
229        Idxs.push_back(mLLVMBuilder->getInt32(i + shift));
[4655]230    }
[4845]231    return mLLVMBuilder->CreateShuffleVector(bVec, aVec, ConstantVector::get(Idxs));
[4655]232}
[4653]233
[4662]234Value * IDISA_Builder::bitblock_any(Value * a) {
[4827]235    Type * iBitBlock = mLLVMBuilder->getIntNTy(mBitBlockWidth);
[4665]236    return mLLVMBuilder->CreateICmpNE(mLLVMBuilder->CreateBitCast(a, iBitBlock),  ConstantInt::get(iBitBlock, 0));
[4662]237}
[4665]238
[4837]239Value * IDISA_Builder::simd_and(Value * a, Value * b) {
[4845]240    return a->getType() == b->getType() ? mLLVMBuilder->CreateAnd(a, b) : mLLVMBuilder->CreateAnd(bitCast(a), bitCast(b));
[4665]241}
[4837]242
243Value * IDISA_Builder::simd_or(Value * a, Value * b) {
[4845]244    return a->getType() == b->getType() ? mLLVMBuilder->CreateOr(a, b) : mLLVMBuilder->CreateOr(bitCast(a), bitCast(b));
[4837]245}
246   
247Value * IDISA_Builder::simd_xor(Value * a, Value * b) {
[4845]248    return a->getType() == b->getType() ? mLLVMBuilder->CreateXor(a, b) : mLLVMBuilder->CreateXor(bitCast(a), bitCast(b));
[4837]249}
250
251Value * IDISA_Builder::simd_not(Value * a) {
252    return simd_xor(a, Constant::getAllOnesValue(a->getType()));
253}
254
255}
Note: See TracBrowser for help on using the repository browser.