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

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

Bitstream and byte space character class kernels - initial check-in

File size: 16.8 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    assert (value->getType()->canLosslesslyBitCastTo(mBitBlockType));
80    CreateCall(printRegister, {CreateGlobalStringPtr(name.c_str()), CreateBitCast(value, mBitBlockType)});
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), 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    Value * aVec = fwCast(fw, a);
343    return CreateExtractElement(aVec, 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
421}
Note: See TracBrowser for help on using the repository browser.