source: icGREP/icgrep-devel/icgrep/IR_Gen/idisa_builder.cpp @ 5795

Last change on this file since 5795 was 5774, checked in by cameron, 18 months ago

Zeroextend print register bytes to i32, before calling printf

File size: 29.1 KB
RevLine 
[4651]1/*
[5117]2 *  Copyright (c) 2016 International Characters.
[4651]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>
[5260]12#include <llvm/IR/Module.h>
[4974]13#include <llvm/Support/raw_ostream.h>
[5227]14#include <llvm/IR/TypeBuilder.h>
[5425]15#include <toolchain/toolchain.h>
[4651]16
[5260]17using namespace llvm;
18
[4665]19namespace IDISA {
[4651]20
[5377]21VectorType * IDISA_Builder::fwVectorType(const unsigned fw) {
22    return VectorType::get(getIntNTy(fw), mBitBlockWidth / fw);
[4651]23}
24
[5377]25Value * IDISA_Builder::fwCast(const unsigned fw, Value * const a) {
26    VectorType * const ty = fwVectorType(fw);
[5378]27    assert (a->getType()->getPrimitiveSizeInBits() == ty->getPrimitiveSizeInBits());
[5377]28    return CreateBitCast(a, ty);
[4651]29}
30
[4974]31void IDISA_Builder::CallPrintRegister(const std::string & name, Value * const value) {
[5440]32    Module * const m = getModule();
33    Constant * printRegister = m->getFunction("PrintRegister");
[4974]34    if (LLVM_UNLIKELY(printRegister == nullptr)) {
[5245]35        FunctionType *FT = FunctionType::get(getVoidTy(), { PointerType::get(getInt8Ty(), 0), getBitBlockType() }, false);
[5440]36        Function * function = Function::Create(FT, Function::InternalLinkage, "PrintRegister", m);
[4974]37        auto arg = function->arg_begin();
38        std::string tmp;
39        raw_string_ostream out(tmp);
40        out << "%-40s =";
41        for(unsigned i = 0; i < (mBitBlockWidth / 8); ++i) {
42            out << " %02x";
43        }
44        out << '\n';
[5440]45        BasicBlock * entry = BasicBlock::Create(m->getContext(), "entry", function);
[4974]46        IRBuilder<> builder(entry);
47        std::vector<Value *> args;
[5398]48        args.push_back(GetString(out.str().c_str()));
[5014]49        Value * const name = &*(arg++);
[4974]50        name->setName("name");
51        args.push_back(name);
[5014]52        Value * value = &*arg;
[4974]53        value->setName("value");
54        Type * const byteVectorType = VectorType::get(getInt8Ty(), (mBitBlockWidth / 8));
55        value = builder.CreateBitCast(value, byteVectorType);
56        for(unsigned i = (mBitBlockWidth / 8); i != 0; --i) {
[5774]57            args.push_back(builder.CreateZExt(builder.CreateExtractElement(value, builder.getInt32(i - 1)), builder.getInt32Ty()));
[4974]58        }
[5239]59        builder.CreateCall(GetPrintf(), args);
[4974]60        builder.CreateRetVoid();
[4942]61
[4974]62        printRegister = function;
63    }
[5398]64    CreateCall(printRegister, {GetString(name.c_str()), CreateBitCast(value, mBitBlockType)});
[4942]65}
66
67Constant * IDISA_Builder::simd_himask(unsigned fw) {
68    return Constant::getIntegerValue(getIntNTy(mBitBlockWidth), APInt::getSplat(mBitBlockWidth, APInt::getHighBitsSet(fw, fw/2)));
[4651]69}
70
[4942]71Constant * IDISA_Builder::simd_lomask(unsigned fw) {
72    return Constant::getIntegerValue(getIntNTy(mBitBlockWidth), APInt::getSplat(mBitBlockWidth, APInt::getLowBitsSet(fw, fw/2)));
73}
74
[5140]75Value * IDISA_Builder::simd_fill(unsigned fw, Value * a) {
[5729]76    if (fw < 8) report_fatal_error("Unsupported field width: simd_fill " + std::to_string(fw));
77   unsigned field_count = mBitBlockWidth/fw;
[5140]78    Type * singleFieldVecTy = VectorType::get(getIntNTy(fw), 1);
79    Value * aVec = CreateBitCast(a, singleFieldVecTy);
80    return CreateShuffleVector(aVec, UndefValue::get(singleFieldVecTy), Constant::getNullValue(VectorType::get(getInt32Ty(), field_count)));
81}
82
[4942]83Value * IDISA_Builder::simd_add(unsigned fw, Value * a, Value * b) {
[5729]84    if (fw == 1) return simd_xor(a, b);
85    if (fw < 8) {
86        Constant * hi_bit_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
87                                                           APInt::getSplat(mBitBlockWidth, APInt::getHighBitsSet(fw, 1)));
88        Constant * lo_bit_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
89                                                           APInt::getSplat(mBitBlockWidth, APInt::getLowBitsSet(fw, fw-1)));
90        Value * hi_xor = simd_xor(simd_and(a, hi_bit_mask), simd_and(b, hi_bit_mask));
91        Value * part_sum = simd_add(32, simd_and(a, lo_bit_mask), simd_and(b, lo_bit_mask));
92        return simd_xor(part_sum, hi_xor);
93    }
[5140]94    return CreateAdd(fwCast(fw, a), fwCast(fw, b));
[4942]95}
96
[4651]97Value * IDISA_Builder::simd_sub(unsigned fw, Value * a, Value * b) {
[5729]98    if (fw < 8) report_fatal_error("Unsupported field width: sub " + std::to_string(fw));
[4898]99    return CreateSub(fwCast(fw, a), fwCast(fw, b));
[4651]100}
101
102Value * IDISA_Builder::simd_mult(unsigned fw, Value * a, Value * b) {
[5729]103    if (fw < 8) report_fatal_error("Unsupported field width: mult " + std::to_string(fw));
[4898]104    return CreateMul(fwCast(fw, a), fwCast(fw, b));
[4651]105}
106
107Value * IDISA_Builder::simd_eq(unsigned fw, Value * a, Value * b) {
[5729]108    if (fw < 8) {
109        Value * eq_bits = simd_not(simd_xor(a, b));
110        if (fw == 1) return eq_bits;
111        eq_bits = simd_or(simd_and(simd_srli(32, simd_and(simd_himask(2), eq_bits), 1), eq_bits),
112                          simd_and(simd_slli(32, simd_and(simd_lomask(2), eq_bits), 1), eq_bits));
113        if (fw == 2) return eq_bits;
114        eq_bits = simd_or(simd_and(simd_srli(32, simd_and(simd_himask(4), eq_bits), 2), eq_bits),
115                          simd_and(simd_slli(32, simd_and(simd_lomask(4), eq_bits), 2), eq_bits));
116        return eq_bits;
117    }
[4898]118    return CreateSExt(CreateICmpEQ(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]119}
120
121Value * IDISA_Builder::simd_gt(unsigned fw, Value * a, Value * b) {
[5729]122    if (fw < 8) report_fatal_error("Unsupported field width: gt " + std::to_string(fw));
[4898]123    return CreateSExt(CreateICmpSGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]124}
125
126Value * IDISA_Builder::simd_ugt(unsigned fw, Value * a, Value * b) {
[5729]127    if (fw < 8) report_fatal_error("Unsupported field width: ugt " + std::to_string(fw));
[4898]128    return CreateSExt(CreateICmpUGT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]129}
130
131Value * IDISA_Builder::simd_lt(unsigned fw, Value * a, Value * b) {
[5729]132    if (fw < 8) report_fatal_error("Unsupported field width: lt " + std::to_string(fw));
[4898]133    return CreateSExt(CreateICmpSLT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]134}
135
136Value * IDISA_Builder::simd_ult(unsigned fw, Value * a, Value * b) {
[5729]137    if (fw < 8) report_fatal_error("Unsupported field width: ult " + std::to_string(fw));
[4898]138    return CreateSExt(CreateICmpULT(fwCast(fw, a), fwCast(fw, b)), fwVectorType(fw));
[4651]139}
140
141Value * IDISA_Builder::simd_max(unsigned fw, Value * a, Value * b) {
[5729]142    if (fw < 8) report_fatal_error("Unsupported field width: max " + std::to_string(fw));
[4651]143    Value * aVec = fwCast(fw, a);
144    Value * bVec = fwCast(fw, b);
[4898]145    return CreateSelect(CreateICmpSGT(aVec, bVec), aVec, bVec);
[4651]146}
147
148Value * IDISA_Builder::simd_umax(unsigned fw, Value * a, Value * b) {
[5729]149    if (fw < 8) report_fatal_error("Unsupported field width: umax " + std::to_string(fw));
[4651]150    Value * aVec = fwCast(fw, a);
151    Value * bVec = fwCast(fw, b);
[4898]152    return CreateSelect(CreateICmpUGT(aVec, bVec), aVec, bVec);
[4651]153}
154
155Value * IDISA_Builder::simd_min(unsigned fw, Value * a, Value * b) {
[5729]156    if (fw < 8) report_fatal_error("Unsupported field width: min " + std::to_string(fw));
[4651]157    Value * aVec = fwCast(fw, a);
158    Value * bVec = fwCast(fw, b);
[4898]159    return CreateSelect(CreateICmpSLT(aVec, bVec), aVec, bVec);
[4651]160}
161
162Value * IDISA_Builder::simd_umin(unsigned fw, Value * a, Value * b) {
[5729]163    if (fw < 8) report_fatal_error("Unsupported field width: umin " + std::to_string(fw));
[4651]164    Value * aVec = fwCast(fw, a);
165    Value * bVec = fwCast(fw, b);
[4898]166    return CreateSelect(CreateICmpULT(aVec, bVec), aVec, bVec);
[4651]167}
168
169Value * IDISA_Builder::simd_slli(unsigned fw, Value * a, unsigned shift) {
[5729]170    if (fw < 16) {
171        Constant * value_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
172                                                          APInt::getSplat(mBitBlockWidth, APInt::getLowBitsSet(fw, fw-shift)));
173        return CreateShl(fwCast(32, simd_and(a, value_mask)), shift);
174    }
[4898]175    return CreateShl(fwCast(fw, a), shift);
[4651]176}
177
178Value * IDISA_Builder::simd_srli(unsigned fw, Value * a, unsigned shift) {
[5729]179    if (fw < 16) {
180        Constant * value_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
181                                                          APInt::getSplat(mBitBlockWidth, APInt::getHighBitsSet(fw, fw-shift)));
182        return CreateLShr(fwCast(32, simd_and(a, value_mask)), shift);
183    }
[4898]184    return CreateLShr(fwCast(fw, a), shift);
[4651]185}
186
187Value * IDISA_Builder::simd_srai(unsigned fw, Value * a, unsigned shift) {
[5729]188    if (fw < 8) report_fatal_error("Unsupported field width: srai " + std::to_string(fw));
[4898]189    return CreateAShr(fwCast(fw, a), shift);
[4651]190}
[5729]191   
192Value * IDISA_Builder::simd_sllv(unsigned fw, Value * v, Value * shifts) {
193    if (fw >= 8) return CreateShl(fwCast(fw, v), fwCast(fw, shifts));
194    Value * w = v;
195    for (unsigned shft_amt = 1; shft_amt < fw; shft_amt *= 2) {
196        APInt bit_in_field(fw, shft_amt);
197        // To simulate shift within a fw, we need to mask off the high shft_amt bits of each element.
198        Constant * value_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
199                                                          APInt::getSplat(mBitBlockWidth, APInt::getLowBitsSet(fw, fw-shft_amt)));
200        Constant * bit_select = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
201                                                          APInt::getSplat(mBitBlockWidth, bit_in_field));
202        Value * unshifted_field_mask = simd_eq(fw, simd_and(bit_select, shifts), allZeroes());
203        Value * fieldsToShift = simd_and(w, simd_and(value_mask, simd_not(unshifted_field_mask)));
204        w = simd_or(simd_and(w, unshifted_field_mask), simd_slli(32, fieldsToShift, shft_amt));
205    }
206    return w;
207}
[4651]208
[5729]209Value * IDISA_Builder::simd_srlv(unsigned fw, Value * v, Value * shifts) {
210    if (fw >= 8) return CreateLShr(fwCast(fw, v), fwCast(fw, shifts));
211    Value * w = v;
212    for (unsigned shft_amt = 1; shft_amt < fw; shft_amt *= 2) {
213        APInt bit_in_field(fw, shft_amt);
214        // To simulate shift within a fw, we need to mask off the low shft_amt bits of each element.
215        Constant * value_mask = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
216                                                          APInt::getSplat(mBitBlockWidth, APInt::getHighBitsSet(fw, fw-shft_amt)));
217        Constant * bit_select = Constant::getIntegerValue(getIntNTy(mBitBlockWidth),
218                                                          APInt::getSplat(mBitBlockWidth, bit_in_field));
219        Value * unshifted_field_mask = simd_eq(fw, simd_and(bit_select, shifts), allZeroes());
220        Value * fieldsToShift = simd_and(w, simd_and(value_mask, simd_not(unshifted_field_mask)));
221        w = simd_or(simd_and(w, unshifted_field_mask), simd_srli(32, fieldsToShift, shft_amt));
222    }
223    return w;
224}
225
226Value * IDISA_Builder::simd_pext(unsigned fieldwidth, Value * v, Value * extract_mask) {
227    Value * delcounts = CreateNot(extract_mask);  // initially deletion counts per 1-bit field
228    Value * w = simd_and(extract_mask, v);
229    for (unsigned fw = 2; fw < fieldwidth; fw = fw * 2) {
230        Value * shift_fwd_field_mask = simd_lomask(fw*2);
231        Value * shift_back_field_mask = simd_himask(fw*2);
232        Value * shift_back_count_mask = simd_and(shift_back_field_mask, simd_lomask(fw));
233        Value * shift_fwd_amts = simd_srli(fw, simd_and(shift_fwd_field_mask, delcounts), fw/2);
234        Value * shift_back_amts = simd_and(shift_back_count_mask, delcounts);
235        w = simd_or(simd_sllv(fw, simd_and(w, shift_fwd_field_mask), shift_fwd_amts),
236                    simd_srlv(fw, simd_and(w, shift_back_field_mask), shift_back_amts));
237        delcounts = simd_add(fw, simd_and(simd_lomask(fw), delcounts), simd_srli(fw, delcounts, fw/2));
238    }
239    // Now shift back all fw fields.
240    Value * shift_back_amts = simd_and(simd_lomask(fieldwidth), delcounts);
241    w = simd_srlv(fieldwidth, w, shift_back_amts);
242    return w;
243}
244
245Value * IDISA_Builder::simd_pdep(unsigned fieldwidth, Value * v, Value * deposit_mask) {
246    // simd_pdep is implemented by reversing the process of simd_pext.
247    // First determine the deletion counts necessary for each stage of the process.
248    std::vector<Value *> delcounts;
249    delcounts.push_back(simd_not(deposit_mask)); // initially deletion counts per 1-bit field
250    for (unsigned fw = 2; fw < fieldwidth; fw = fw * 2) {
251        delcounts.push_back(simd_add(fw, simd_and(simd_lomask(fw), delcounts.back()), simd_srli(fw, delcounts.back(), fw/2)));
252    }
253    //
254    // Now reverse the pext process.  First reverse the final shift_back.
255    Value * pext_shift_back_amts = simd_and(simd_lomask(fieldwidth), delcounts.back());
256    Value * w = simd_sllv(fieldwidth, v, pext_shift_back_amts);
257   
258    //
259    // No work through the smaller field widths.
260    for (unsigned fw = fieldwidth/2; fw >= 2; fw = fw/2) {
261        delcounts.pop_back();
262        Value * pext_shift_fwd_field_mask = simd_lomask(fw*2);
263        Value * pext_shift_back_field_mask = simd_himask(fw*2);
264        Value * pext_shift_back_count_mask = simd_and(pext_shift_back_field_mask, simd_lomask(fw));
265        Value * pext_shift_fwd_amts = simd_srli(fw, simd_and(pext_shift_fwd_field_mask, delcounts.back()), fw/2);
266        Value * pext_shift_back_amts = simd_and(pext_shift_back_count_mask, delcounts.back());
267        w = simd_or(simd_srlv(fw, simd_and(w, pext_shift_fwd_field_mask), pext_shift_fwd_amts),
268                    simd_sllv(fw, simd_and(w, pext_shift_back_field_mask), pext_shift_back_amts));
269    }
270    return w;
271}
272
[4651]273Value * IDISA_Builder::simd_cttz(unsigned fw, Value * a) {
[5729]274    if (fw < 8) report_fatal_error("Unsupported field width: cttz " + std::to_string(fw));
[5440]275    Value * cttzFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::cttz, fwVectorType(fw));
[5309]276    return CreateCall(cttzFunc, {fwCast(fw, a), ConstantInt::get(getInt1Ty(), 0)});
[4651]277}
278
[4720]279Value * IDISA_Builder::simd_popcount(unsigned fw, Value * a) {
[5729]280    if (fw < 8) report_fatal_error("Unsupported field width: popcount " + std::to_string(fw));
[5440]281    Value * ctpopFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::ctpop, fwVectorType(fw));
[5309]282    return CreateCall(ctpopFunc, fwCast(fw, a));
[4720]283}
284
[5488]285Value * IDISA_Builder::simd_bitreverse(unsigned fw, Value * a) {
286    /*  Pure sequential solution too slow!
287     Value * func = Intrinsic::getDeclaration(getModule(), Intrinsic::bitreverse, fwVectorType(fw));
288     return CreateCall(func, fwCast(fw, a));
289     */
290    if (fw > 8) {
291        // Reverse the bits of each byte and then use a byte shuffle to complete the job.
292        Value * bitrev8 = fwCast(8, simd_bitreverse(8, a));
293        const auto bytes_per_field = fw/8;
294        const auto byte_count = mBitBlockWidth / 8;
295        Constant * Idxs[byte_count];
296        for (unsigned i = 0; i < byte_count; i += bytes_per_field) {
297            for (unsigned j = 0; j < bytes_per_field; j++) {
298                Idxs[i + j] = getInt32(i + bytes_per_field - j - 1);
299            }
300        }
301        return CreateShuffleVector(bitrev8, UndefValue::get(fwVectorType(8)), ConstantVector::get({Idxs, byte_count}));
302    }
303    else {
304        if (fw > 2) {
305            a = simd_bitreverse(fw/2, a);
306        }
307        return simd_or(simd_srli(16, simd_and(a, simd_himask(fw)), fw/2), simd_slli(16, simd_and(a, simd_lomask(fw)), fw/2));
308    }
309}
310
[4891]311Value * IDISA_Builder::simd_if(unsigned fw, Value * cond, Value * a, Value * b) {
[4900]312    if (fw == 1) {
[4957]313        Value * a1 = bitCast(a);
314        Value * b1 = bitCast(b);
[4900]315        Value * c = bitCast(cond);
[4957]316        return CreateOr(CreateAnd(a1, c), CreateAnd(CreateXor(c, b1), b1));
[5309]317    } else {
[5729]318        if (fw < 8) report_fatal_error("Unsupported field width: simd_if " + std::to_string(fw));
[4900]319        Value * aVec = fwCast(fw, a);
320        Value * bVec = fwCast(fw, b);
321        return CreateSelect(CreateICmpSLT(cond, mZeroInitializer), aVec, bVec);
322    }
[4891]323}
324   
[5309]325Value * IDISA_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {   
[5729]326    if (fw < 8) report_fatal_error("Unsupported field width: mergeh " + std::to_string(fw));
[5309]327    const auto field_count = mBitBlockWidth / fw;
328    Constant * Idxs[field_count];
329    for (unsigned i = 0; i < field_count / 2; i++) {
330        Idxs[2 * i] = getInt32(i + field_count / 2); // selects elements from first reg.
331        Idxs[2 * i + 1] = getInt32(i + field_count / 2 + field_count); // selects elements from second reg.
[4652]332    }
[5309]333    return CreateShuffleVector(fwCast(fw, a), fwCast(fw, b), ConstantVector::get({Idxs, field_count}));
[4652]334}
335
[5309]336Value * IDISA_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {   
[5729]337    if (fw < 8) report_fatal_error("Unsupported field width: mergel " + std::to_string(fw));
[5309]338    const auto field_count = mBitBlockWidth / fw;
339    Constant * Idxs[field_count];
340    for (unsigned i = 0; i < field_count / 2; i++) {
341        Idxs[2 * i] = getInt32(i); // selects elements from first reg.
342        Idxs[2 * i + 1] = getInt32(i + field_count); // selects elements from second reg.
[4652]343    }
[5309]344    return CreateShuffleVector(fwCast(fw, a), fwCast(fw, b), ConstantVector::get({Idxs, field_count}));
[4652]345}
346
[4892]347Value * IDISA_Builder::esimd_bitspread(unsigned fw, Value * bitmask) {
[5729]348    if (fw < 8) report_fatal_error("Unsupported field width: bitspread " + std::to_string(fw));
[5309]349    const auto field_count = mBitBlockWidth / fw;
[4898]350    Type * field_type = getIntNTy(fw);
[5309]351    Value * spread_field = CreateBitCast(CreateZExtOrTrunc(bitmask, field_type), VectorType::get(getIntNTy(fw), 1));
[4898]352    Value * undefVec = UndefValue::get(VectorType::get(getIntNTy(fw), 1));
353    Value * broadcast = CreateShuffleVector(spread_field, undefVec, Constant::getNullValue(VectorType::get(getInt32Ty(), field_count)));
[5309]354    Constant * bitSel[field_count];
355    Constant * bitShift[field_count];
[4879]356    for (unsigned i = 0; i < field_count; i++) {
[5309]357        bitSel[i] = ConstantInt::get(field_type, 1 << i);
358        bitShift[i] = ConstantInt::get(field_type, i);
[4879]359    }
[5309]360    Value * bitSelVec = ConstantVector::get({bitSel, field_count});
361    Value * bitShiftVec = ConstantVector::get({bitShift, field_count});
[4898]362    return CreateLShr(CreateAnd(bitSelVec, broadcast), bitShiftVec);
[4879]363}
364
[4653]365Value * IDISA_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
[5729]366    if (fw < 8) report_fatal_error("Unsupported field width: packh " + std::to_string(fw));
[4653]367    Value * aVec = fwCast(fw/2, a);
368    Value * bVec = fwCast(fw/2, b);
[5309]369    const auto field_count = 2 * mBitBlockWidth / fw;
370    Constant * Idxs[field_count];
[4653]371    for (unsigned i = 0; i < field_count; i++) {
[5309]372        Idxs[i] = getInt32(2 * i + 1);
[4653]373    }
[5309]374    return CreateShuffleVector(aVec, bVec, ConstantVector::get({Idxs, field_count}));
[4653]375}
[4652]376
[4653]377Value * IDISA_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
[5729]378    if (fw < 8) report_fatal_error("Unsupported field width: packl " + std::to_string(fw));
[4653]379    Value * aVec = fwCast(fw/2, a);
380    Value * bVec = fwCast(fw/2, b);
[5309]381    const auto field_count = 2 * mBitBlockWidth / fw;
382    Constant * Idxs[field_count];
[4653]383    for (unsigned i = 0; i < field_count; i++) {
[5309]384        Idxs[i] = getInt32(2 * i);
[4653]385    }
[5309]386    return CreateShuffleVector(aVec, bVec, ConstantVector::get({Idxs, field_count}));
[4653]387}
[4652]388
[4957]389Value * IDISA_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
[5729]390    if (fw < 16) report_fatal_error("Unsupported field width: packh_in_lanes " + std::to_string(fw));
[5309]391    const unsigned fw_out = fw / 2;
392    const unsigned fields_per_lane = mBitBlockWidth / (fw_out * lanes);
393    const unsigned field_offset_for_b = mBitBlockWidth / fw_out;
394    const unsigned field_count = mBitBlockWidth / fw_out;
395    Constant * Idxs[field_count];
396    for (unsigned lane = 0, j = 0; lane < lanes; lane++) {
397        const unsigned first_field_in_lane = lane * fields_per_lane; // every second field
398        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
399            Idxs[j++] = getInt32(first_field_in_lane + (2 * i) + 1);
[4957]400        }
[5309]401        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
402            Idxs[j++] = getInt32(field_offset_for_b + first_field_in_lane + (2 * i) + 1);
[4957]403        }
404    }
[5309]405    return CreateShuffleVector(fwCast(fw_out, a), fwCast(fw_out, b), ConstantVector::get({Idxs, field_count}));
[4957]406}
407
408Value * IDISA_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
[5729]409    if (fw < 16) report_fatal_error("Unsupported field width: packl_in_lanes " + std::to_string(fw));
[5309]410    const unsigned fw_out = fw / 2;
411    const unsigned fields_per_lane = mBitBlockWidth / (fw_out * lanes);
412    const unsigned field_offset_for_b = mBitBlockWidth / fw_out;
413    const unsigned field_count = mBitBlockWidth / fw_out;
414    Constant * Idxs[field_count];
415    for (unsigned lane = 0, j = 0; lane < lanes; lane++) {
416        const unsigned first_field_in_lane = lane * fields_per_lane; // every second field
417        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
418            Idxs[j++] = getInt32(first_field_in_lane + (2 * i));
[4957]419        }
[5309]420        for (unsigned i = 0; i < fields_per_lane / 2; i++) {
421            Idxs[j++] = getInt32(field_offset_for_b + first_field_in_lane + (2 * i));
[4957]422        }
423    }
[5309]424    return CreateShuffleVector(fwCast(fw_out, a), fwCast(fw_out, b), ConstantVector::get({Idxs, field_count}));
[4957]425}
426
[4653]427Value * IDISA_Builder::hsimd_signmask(unsigned fw, Value * a) {
[5729]428    if (fw < 8) report_fatal_error("Unsupported field width: hsimd_signmask " + std::to_string(fw));
[4898]429    Value * mask = CreateICmpSLT(fwCast(fw, a), ConstantAggregateZero::get(fwVectorType(fw)));
430    return CreateZExt(CreateBitCast(mask, getIntNTy(mBitBlockWidth/fw)), getInt32Ty());
[4653]431}
432
[4697]433Value * IDISA_Builder::mvmd_extract(unsigned fw, Value * a, unsigned fieldIndex) {
[5729]434    if (fw < 8) report_fatal_error("Unsupported field width: mvmd_extract " + std::to_string(fw));
[5202]435    return CreateExtractElement(fwCast(fw, a), getInt32(fieldIndex));
[4697]436}
437
[4881]438Value * IDISA_Builder::mvmd_insert(unsigned fw, Value * blk, Value * elt, unsigned fieldIndex) {
[5729]439    if (fw < 8) report_fatal_error("Unsupported field width: mvmd_insert " + std::to_string(fw));
[5309]440    return CreateInsertElement(fwCast(fw, blk), elt, getInt32(fieldIndex));
[4881]441}
442
[5007]443Value * IDISA_Builder::mvmd_slli(unsigned fw, Value * a, unsigned shift) {
[5729]444    if (fw < 8) report_fatal_error("Unsupported field width: mvmd_slli " + std::to_string(fw));
[5309]445    const auto field_count = mBitBlockWidth / fw;
[5007]446    return mvmd_dslli(fw, a, Constant::getNullValue(fwVectorType(fw)), field_count - shift);
447}
448
449Value * IDISA_Builder::mvmd_srli(unsigned fw, Value * a, unsigned shift) {
[5729]450    if (fw < 8) report_fatal_error("Unsupported field width: mvmd_srli " + std::to_string(fw));
[5007]451    return mvmd_dslli(fw, Constant::getNullValue(fwVectorType(fw)), a, shift);
452}
453
[4655]454Value * IDISA_Builder::mvmd_dslli(unsigned fw, Value * a, Value * b, unsigned shift) {
[5729]455    if (fw < 8) report_fatal_error("Unsupported field width: mvmd_dslli " + std::to_string(fw));
[5309]456    const auto field_count = mBitBlockWidth/fw;
457    Constant * Idxs[field_count];
[4845]458    for (unsigned i = 0; i < field_count; i++) {
[5309]459        Idxs[i] = getInt32(i + shift);
[4655]460    }
[5309]461    return CreateShuffleVector(fwCast(fw, b), fwCast(fw, a), ConstantVector::get({Idxs, field_count}));
[4655]462}
[4653]463
[4662]464Value * IDISA_Builder::bitblock_any(Value * a) {
[4898]465    Type * iBitBlock = getIntNTy(mBitBlockWidth);
[5309]466    return CreateICmpNE(CreateBitCast(a, iBitBlock),  ConstantInt::getNullValue(iBitBlock));
[4662]467}
[4665]468
[5114]469// full add producing {carryout, sum}
[5115]470std::pair<Value *, Value *> IDISA_Builder::bitblock_add_with_carry(Value * a, Value * b, Value * carryin) {
[5114]471    Value * carrygen = simd_and(a, b);
472    Value * carryprop = simd_or(a, b);
473    Value * sum = simd_add(mBitBlockWidth, simd_add(mBitBlockWidth, a, b), carryin);
474    Value * carryout = CreateBitCast(simd_or(carrygen, simd_and(carryprop, CreateNot(sum))), getIntNTy(mBitBlockWidth));
475    return std::pair<Value *, Value *>(bitCast(simd_srli(mBitBlockWidth, carryout, mBitBlockWidth - 1)), bitCast(sum));
476}
477
478// full shift producing {shiftout, shifted}
479std::pair<Value *, Value *> IDISA_Builder::bitblock_advance(Value * a, Value * shiftin, unsigned shift) {
480    Value * shiftin_bitblock = CreateBitCast(shiftin, getIntNTy(mBitBlockWidth));
481    Value * a_bitblock = CreateBitCast(a, getIntNTy(mBitBlockWidth));
[5117]482    Value * shifted = bitCast(CreateOr(CreateShl(a_bitblock, shift), shiftin_bitblock));
483    Value * shiftout = bitCast(CreateLShr(a_bitblock, mBitBlockWidth - shift));
[5114]484    return std::pair<Value *, Value *>(shiftout, shifted);
485}
486
[5713]487// full shift producing {shiftout, shifted}
[5730]488std::pair<Value *, Value *> IDISA_Builder::bitblock_indexed_advance(Value * strm, Value * index_strm, Value * shiftIn, unsigned shiftAmount) {
489    unsigned bitWidth = sizeof(size_t) * 8;
490    Type * iBitBlock = getIntNTy(getBitBlockWidth());
491    Value * shiftVal = getSize(shiftAmount);
492    Value * extracted_bits = simd_pext(bitWidth, strm, index_strm);
493    Value * ix_popcounts = simd_popcount(bitWidth, index_strm);
494
495   
496    if (LLVM_LIKELY(shiftAmount < bitWidth)) {
497        Value * carry = mvmd_extract(bitWidth, shiftIn, 0);
498        Value * result = allZeroes();
499        for (unsigned i = 0; i < getBitBlockWidth()/bitWidth; i++) {
500            Value * ix_popcnt = mvmd_extract(bitWidth, ix_popcounts, i);
501            Value * bits = mvmd_extract(bitWidth, extracted_bits, i);
502            Value * adv = CreateOr(CreateShl(bits, shiftAmount), carry);
503            // We have two cases depending on whether the popcount of the index pack is < shiftAmount or not.
504            Value * popcount_small = CreateICmpULT(ix_popcnt, shiftVal);
505            Value * carry_if_popcount_small = 
506                CreateOr(CreateShl(bits, CreateSub(shiftVal, ix_popcnt)),
507                            CreateLShr(carry, ix_popcnt));
508            Value * carry_if_popcount_large = CreateLShr(bits, CreateSub(ix_popcnt, shiftVal));
509            carry = CreateSelect(popcount_small, carry_if_popcount_small, carry_if_popcount_large);
510            result = mvmd_insert(bitWidth, result, adv, i);
511        }
512        Value * carryOut = mvmd_insert(bitWidth, allZeroes(), carry, 0);
513        return std::pair<Value *, Value *>{bitCast(carryOut), simd_pdep(bitWidth, result, index_strm)};
514    }
515    else if (shiftAmount <= mBitBlockWidth) {
516        // The shift amount is always greater than the popcount of the individual
517        // elements that we deal with.   This simplifies some of the logic.
518        Value * carry = CreateBitCast(shiftIn, iBitBlock);
519        Value * result = allZeroes();
520        for (unsigned i = 0; i < getBitBlockWidth()/bitWidth; i++) {
521            Value * ix_popcnt = mvmd_extract(bitWidth, ix_popcounts, i);
522            Value * bits = mvmd_extract(bitWidth, extracted_bits, i);  // All these bits are shifted out (appended to carry).
523            result = mvmd_insert(bitWidth, result, mvmd_extract(bitWidth, carry, 0), i);
524            carry = CreateLShr(carry, CreateZExt(ix_popcnt, iBitBlock)); // Remove the carry bits consumed, make room for new bits.
525            carry = CreateOr(carry, CreateShl(CreateZExt(bits, iBitBlock), CreateZExt(CreateSub(shiftVal, ix_popcnt), iBitBlock)));
526        }
527        return std::pair<Value *, Value *>{bitCast(carry), simd_pdep(bitWidth, result, index_strm)};
528    }
529    else {
530        // The shift amount is greater than the total popcount.   We will consume popcount
531        // bits from the shiftIn value only, and produce a carry out value of the selected bits.
532        // elements that we deal with.   This simplifies some of the logic.
533        Value * carry = CreateBitCast(shiftIn, iBitBlock);
534        Value * result = allZeroes();
535        Value * carryOut = CreateBitCast(allZeroes(), iBitBlock);
536        Value * generated = getSize(0);
537        for (unsigned i = 0; i < getBitBlockWidth()/bitWidth; i++) {
538            Value * ix_popcnt = mvmd_extract(bitWidth, ix_popcounts, i);
539            Value * bits = mvmd_extract(bitWidth, extracted_bits, i);  // All these bits are shifted out (appended to carry).
540            result = mvmd_insert(bitWidth, result, mvmd_extract(bitWidth, carry, 0), i);
541            carry = CreateLShr(carry, CreateZExt(ix_popcnt, iBitBlock)); // Remove the carry bits consumed.
542            carryOut = CreateOr(carryOut, CreateShl(CreateZExt(bits, iBitBlock), CreateZExt(generated, iBitBlock)));
543            generated = CreateAdd(generated, ix_popcnt);
544        }
545        return std::pair<Value *, Value *>{bitCast(carryOut), simd_pdep(bitWidth, result, index_strm)};
546    }
[5713]547}
548
[5730]549
[5121]550Value * IDISA_Builder::bitblock_mask_from(Value * pos) {
551    Type * bitBlockInt = getIntNTy(getBitBlockWidth());
552    return bitCast(CreateShl(ConstantInt::getAllOnesValue(bitBlockInt), CreateZExt(pos, bitBlockInt)));
553   
554}
555Value * IDISA_Builder::bitblock_set_bit(Value * pos) {
556    Type * bitBlockInt = getIntNTy(getBitBlockWidth());
557    return bitCast(CreateShl(ConstantInt::get(bitBlockInt, 1), CreateZExt(pos, bitBlockInt)));
558}
559
[4837]560Value * IDISA_Builder::simd_and(Value * a, Value * b) {
[4898]561    return a->getType() == b->getType() ? CreateAnd(a, b) : CreateAnd(bitCast(a), bitCast(b));
[4665]562}
[4837]563
564Value * IDISA_Builder::simd_or(Value * a, Value * b) {
[4898]565    return a->getType() == b->getType() ? CreateOr(a, b) : CreateOr(bitCast(a), bitCast(b));
[4837]566}
567   
568Value * IDISA_Builder::simd_xor(Value * a, Value * b) {
[4898]569    return a->getType() == b->getType() ? CreateXor(a, b) : CreateXor(bitCast(a), bitCast(b));
[4837]570}
571
572Value * IDISA_Builder::simd_not(Value * a) {
573    return simd_xor(a, Constant::getAllOnesValue(a->getType()));
574}
575
[5489]576IDISA_Builder::IDISA_Builder(llvm::LLVMContext & C, unsigned vectorWidth, unsigned stride)
577: CBuilder(C)
578, mBitBlockWidth(vectorWidth)
[5240]579, mStride(stride)
[5489]580, mBitBlockType(VectorType::get(IntegerType::get(C, 64), vectorWidth / 64))
[5240]581, mZeroInitializer(Constant::getNullValue(mBitBlockType))
582, mOneInitializer(Constant::getAllOnesValue(mBitBlockType))
583, mPrintRegisterFunction(nullptr) {
584
[5230]585}
[5240]586
587IDISA_Builder::~IDISA_Builder() {
[5298]588
[5240]589}
590
591}
Note: See TracBrowser for help on using the repository browser.