source: icGREP/icgrep-devel/icgrep/IR_Gen/idisa_avx_builder.cpp @ 6046

Last change on this file since 6046 was 6046, checked in by cameron, 13 months ago

Some fixes

File size: 37.1 KB
Line 
1/*
2 *  Copyright (c) 2018 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_avx_builder.h"
8#include <toolchain/toolchain.h>
9#include <llvm/Support/raw_ostream.h>
10
11using namespace llvm;
12
13namespace IDISA {
14
15std::string IDISA_AVX_Builder::getBuilderUniqueName() {
16    return mBitBlockWidth != 256 ? "AVX_" + std::to_string(mBitBlockWidth) : "AVX";
17}
18
19Value * IDISA_AVX_Builder::hsimd_signmask(unsigned fw, Value * a) {
20    // AVX2 special cases
21    if (mBitBlockWidth == 256) {
22        if (fw == 64) {
23            Value * signmask_f64func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_pd_256);
24            Type * bitBlock_f64type = VectorType::get(getDoubleTy(), mBitBlockWidth/64);
25            Value * a_as_pd = CreateBitCast(a, bitBlock_f64type);
26            return CreateCall(signmask_f64func, a_as_pd);
27        } else if (fw == 32) {
28            Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_ps_256);
29            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
30            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
31            return CreateCall(signmask_f32func, a_as_ps);
32        }
33    } else if (mBitBlockWidth == 512) {
34        if (fw == 64) {
35            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth / 32);
36            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
37            Constant * indicies[8];
38            for (unsigned i = 0; i < 8; i++) {
39                indicies[i] = getInt32(2 * i + 1);
40            }
41            Value * packh = CreateShuffleVector(a_as_ps, UndefValue::get(bitBlock_f32type), ConstantVector::get({indicies, 8}));
42            Type * halfBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/64);
43            Value * pack_as_ps = CreateBitCast(packh, halfBlock_f32type);
44            Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_ps_256);
45            return CreateCall(signmask_f32func, pack_as_ps);
46        }
47    }
48    // Otherwise use default SSE logic.
49    return IDISA_SSE_Builder::hsimd_signmask(fw, a);
50}
51
52std::string IDISA_AVX2_Builder::getBuilderUniqueName() {
53    return mBitBlockWidth != 256 ? "AVX2_" + std::to_string(mBitBlockWidth) : "AVX2";
54}
55
56Value * IDISA_AVX2_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
57    if ((fw > 8) && (fw <= 64)) {
58        Value * aVec = fwCast(fw / 2, a);
59        Value * bVec = fwCast(fw / 2, b);
60        const auto field_count = 2 * mBitBlockWidth / fw;
61        Constant * Idxs[field_count];
62        const auto H = (field_count / 2);
63        const auto Q = (field_count / 4);
64        for (unsigned i = 0; i < Q; i++) {
65            Idxs[i] = getInt32(2 * i);
66            Idxs[i + Q] = getInt32((2 * i) + 1);
67            Idxs[i + H] = getInt32((2 * i) + H);
68            Idxs[i + H + Q] = getInt32((2 * i) + 1 + H);
69        }
70        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get({Idxs, field_count}));
71        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get({Idxs, field_count}));
72        return hsimd_packh(mBitBlockWidth / 2, shufa, shufb);
73    }
74    // Otherwise use default SSE logic.
75    return IDISA_SSE_Builder::hsimd_packh(fw, a, b);
76}
77
78Value * IDISA_AVX2_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
79    if ((fw > 8) && (fw <= 64)) {
80        Value * aVec = fwCast(fw / 2, a);
81        Value * bVec = fwCast(fw / 2, b);
82        const auto field_count = 2 * mBitBlockWidth / fw;
83        Constant * Idxs[field_count];
84        const auto H = (field_count / 2);
85        const auto Q = (field_count / 4);
86        for (unsigned i = 0; i < Q; i++) {
87            Idxs[i] = getInt32(2 * i);
88            Idxs[i + Q] = getInt32((2 * i) + 1);
89            Idxs[i + H] = getInt32((2 * i) + H);
90            Idxs[i + H + Q] = getInt32((2 * i) + H + 1);
91        }
92        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get({Idxs, field_count}));
93        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get({Idxs, field_count}));
94        return hsimd_packl(mBitBlockWidth / 2, shufa, shufb);
95    }
96    // Otherwise use default SSE logic.
97    return IDISA_SSE_Builder::hsimd_packl(fw, a, b);
98}
99
100Value * IDISA_AVX2_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {
101#if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(6, 0, 0)
102    if ((fw == 128) && (mBitBlockWidth == 256)) {
103        Value * vperm2i128func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_vperm2i128);
104        return CreateCall(vperm2i128func, {fwCast(64, a), fwCast(64, b), getInt8(0x31)});
105    }
106#endif
107    // Otherwise use default SSE logic.
108    return IDISA_SSE_Builder::esimd_mergeh(fw, a, b);
109}
110
111Value * IDISA_AVX2_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {
112#if LLVM_VERSION_INTEGER < LLVM_VERSION_CODE(6, 0, 0)
113    if ((fw == 128) && (mBitBlockWidth == 256)) {
114        Value * vperm2i128func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_vperm2i128);
115        return CreateCall(vperm2i128func, {fwCast(64, a), fwCast(64, b), getInt8(0x20)});
116    }
117#endif
118    // Otherwise use default SSE logic.
119    return IDISA_SSE_Builder::esimd_mergel(fw, a, b);
120}
121
122Value * IDISA_AVX2_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
123    if ((fw == 16)  && (lanes == 2)) {
124        Value * vpackuswbfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_packuswb);
125        Value * a_low = fwCast(16, simd_and(a, simd_lomask(fw)));
126        Value * b_low = fwCast(16, simd_and(b, simd_lomask(fw)));
127        return CreateCall(vpackuswbfunc, {a_low, b_low});
128    }
129    // Otherwise use default SSE logic.
130    return IDISA_SSE_Builder::hsimd_packl_in_lanes(lanes, fw, a, b);
131}
132
133Value * IDISA_AVX2_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
134    if ((fw == 16)  && (lanes == 2)) {
135        Value * vpackuswbfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_packuswb);
136        Value * a_low = simd_srli(fw, a, fw/2);
137        Value * b_low = simd_srli(fw, b, fw/2);
138        return CreateCall(vpackuswbfunc, {a_low, b_low});
139    }
140    // Otherwise use default SSE logic.
141    return IDISA_SSE_Builder::hsimd_packh_in_lanes(lanes, fw, a, b);
142}
143
144std::pair<Value *, Value *> IDISA_AVX2_Builder::bitblock_add_with_carry(Value * e1, Value * e2, Value * carryin) {
145    // using LONG_ADD
146    Type * carryTy = carryin->getType();
147    if (carryTy == mBitBlockType) {
148        carryin = mvmd_extract(32, carryin, 0);
149    }
150    Value * carrygen = simd_and(e1, e2);
151    Value * carryprop = simd_or(e1, e2);
152    Value * digitsum = simd_add(64, e1, e2);
153    Value * digitcarry = simd_or(carrygen, simd_and(carryprop, CreateNot(digitsum)));
154    Value * carryMask = hsimd_signmask(64, digitcarry);
155    Value * carryMask2 = CreateOr(CreateAdd(carryMask, carryMask), carryin);
156    Value * bubble = simd_eq(64, digitsum, allOnes());
157    Value * bubbleMask = hsimd_signmask(64, bubble);
158    Value * incrementMask = CreateXor(CreateAdd(bubbleMask, carryMask2), bubbleMask);
159    Value * increments = esimd_bitspread(64,incrementMask);
160    Value * sum = simd_add(64, digitsum, increments);
161    Value * carry_out = CreateLShr(incrementMask, mBitBlockWidth / 64);
162    if (carryTy == mBitBlockType) {
163        carry_out = bitCast(CreateZExt(carry_out, getIntNTy(mBitBlockWidth)));
164    }
165    return std::pair<Value *, Value *>{carry_out, bitCast(sum)};
166}
167
168Value * IDISA_AVX2_Builder::simd_pext(unsigned fieldwidth, Value * v, Value * extract_mask) {
169    if ((fieldwidth == 64) || (fieldwidth == 32)) {
170        Value * PEXT_f = (fieldwidth == 64) ? Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pext_64)
171                                            : Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pext_32);
172        const auto n = getBitBlockWidth() / fieldwidth;
173        Value * result = UndefValue::get(fwVectorType(fieldwidth));
174        for (unsigned i = 0; i < n; i++) {
175            Value * v_i = mvmd_extract(fieldwidth, v, i);
176            Value * mask_i = mvmd_extract(fieldwidth, extract_mask, i);
177            Value * bits = CreateCall(PEXT_f, {v_i, mask_i});
178            result = mvmd_insert(fieldwidth, result, bits, i);
179        }
180        return bitCast(result);
181    }
182    return IDISA_Builder::simd_pext(fieldwidth, v, extract_mask);
183}
184
185Value * IDISA_AVX2_Builder::simd_pdep(unsigned fieldwidth, Value * v, Value * deposit_mask) {
186    if ((fieldwidth == 64) || (fieldwidth == 32)) {
187        Value * PDEP_f = (fieldwidth == 64) ? Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_64)
188                                            : Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_32);
189        const auto n = getBitBlockWidth() / fieldwidth;
190        Value * result = UndefValue::get(fwVectorType(fieldwidth));
191        for (unsigned i = 0; i < n; i++) {
192            Value * v_i = mvmd_extract(fieldwidth, v, i);
193            Value * mask_i = mvmd_extract(fieldwidth, deposit_mask, i);
194            Value * bits = CreateCall(PDEP_f, {v_i, mask_i});
195            result = mvmd_insert(fieldwidth, result, bits, i);
196        }
197        return bitCast(result);
198    }
199    return IDISA_Builder::simd_pdep(fieldwidth, v, deposit_mask);
200}
201
202std::pair<Value *, Value *> IDISA_AVX2_Builder::bitblock_indexed_advance(Value * strm, Value * index_strm, Value * shiftIn, unsigned shiftAmount) {
203    const unsigned bitWidth = getSizeTy()->getBitWidth();
204    if ((bitWidth == 64) || (bitWidth == 32)) {
205        Value * PEXT_f = (bitWidth == 64) ? Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pext_64)
206                                          : Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pext_32);
207        Value * PDEP_f = (bitWidth == 64) ? Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_64)
208                                          : Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_32);
209        Value * const popcount = Intrinsic::getDeclaration(getModule(), Intrinsic::ctpop, getSizeTy());
210        Type * iBitBlock = getIntNTy(getBitBlockWidth());
211        Value * shiftVal = getSize(shiftAmount);
212        const auto n = getBitBlockWidth() / bitWidth;
213        VectorType * const vecTy = VectorType::get(getSizeTy(), n);
214        if (LLVM_LIKELY(shiftAmount < bitWidth)) {
215            Value * carry = mvmd_extract(bitWidth, shiftIn, 0);
216            Value * result = UndefValue::get(vecTy);
217            for (unsigned i = 0; i < n; i++) {
218                Value * s = mvmd_extract(bitWidth, strm, i);
219                Value * ix = mvmd_extract(bitWidth, index_strm, i);
220                Value * ix_popcnt = CreateCall(popcount, {ix});
221                Value * bits = CreateCall(PEXT_f, {s, ix});
222                Value * adv = CreateOr(CreateShl(bits, shiftAmount), carry);
223                // We have two cases depending on whether the popcount of the index pack is < shiftAmount or not.
224                Value * popcount_small = CreateICmpULT(ix_popcnt, shiftVal);
225                Value * carry_if_popcount_small =
226                    CreateOr(CreateShl(bits, CreateSub(shiftVal, ix_popcnt)),
227                                CreateLShr(carry, ix_popcnt));
228                Value * carry_if_popcount_large = CreateLShr(bits, CreateSub(ix_popcnt, shiftVal));
229                carry = CreateSelect(popcount_small, carry_if_popcount_small, carry_if_popcount_large);
230                result = mvmd_insert(bitWidth, result, CreateCall(PDEP_f, {adv, ix}), i);
231            }
232            Value * carryOut = mvmd_insert(bitWidth, allZeroes(), carry, 0);
233            return std::pair<Value *, Value *>{bitCast(carryOut), bitCast(result)};
234        }
235        else if (shiftAmount <= mBitBlockWidth) {
236            // The shift amount is always greater than the popcount of the individual
237            // elements that we deal with.   This simplifies some of the logic.
238            Value * carry = CreateBitCast(shiftIn, iBitBlock);
239            Value * result = UndefValue::get(vecTy);
240            for (unsigned i = 0; i < n; i++) {
241                Value * s = mvmd_extract(bitWidth, strm, i);
242                Value * ix = mvmd_extract(bitWidth, index_strm, i);
243                Value * ix_popcnt = CreateCall(popcount, {ix});
244                Value * bits = CreateCall(PEXT_f, {s, ix});  // All these bits are shifted out (appended to carry).
245                result = mvmd_insert(bitWidth, result, CreateCall(PDEP_f, {mvmd_extract(bitWidth, carry, 0), ix}), i);
246                carry = CreateLShr(carry, CreateZExt(ix_popcnt, iBitBlock)); // Remove the carry bits consumed, make room for new bits.
247                carry = CreateOr(carry, CreateShl(CreateZExt(bits, iBitBlock), CreateZExt(CreateSub(shiftVal, ix_popcnt), iBitBlock)));
248            }
249            return std::pair<Value *, Value *>{bitCast(carry), bitCast(result)};
250        }
251        else {
252            // The shift amount is greater than the total popcount.   We will consume popcount
253            // bits from the shiftIn value only, and produce a carry out value of the selected bits.
254            // elements that we deal with.   This simplifies some of the logic.
255            Value * carry = CreateBitCast(shiftIn, iBitBlock);
256            Value * result = UndefValue::get(vecTy);
257            Value * carryOut = ConstantInt::getNullValue(iBitBlock);
258            Value * generated = getSize(0);
259            for (unsigned i = 0; i < n; i++) {
260                Value * s = mvmd_extract(bitWidth, strm, i);
261                Value * ix = mvmd_extract(bitWidth, index_strm, i);
262                Value * ix_popcnt = CreateCall(popcount, {ix});
263                Value * bits = CreateCall(PEXT_f, {s, ix});  // All these bits are shifted out (appended to carry).
264                result = mvmd_insert(bitWidth, result, CreateCall(PDEP_f, {mvmd_extract(bitWidth, carry, 0), ix}), i);
265                carry = CreateLShr(carry, CreateZExt(ix_popcnt, iBitBlock)); // Remove the carry bits consumed.
266                carryOut = CreateOr(carryOut, CreateShl(CreateZExt(bits, iBitBlock), CreateZExt(generated, iBitBlock)));
267                generated = CreateAdd(generated, ix_popcnt);
268            }
269            return std::pair<Value *, Value *>{bitCast(carryOut), bitCast(result)};
270        }
271    }
272    return IDISA_Builder::bitblock_indexed_advance(strm, index_strm, shiftIn, shiftAmount);
273}
274
275Value * IDISA_AVX2_Builder::hsimd_signmask(unsigned fw, Value * a) {
276    // AVX2 special cases
277    if (mBitBlockWidth == 256) {
278        if (fw == 8) {
279            Value * signmask_f8func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_pmovmskb);
280            Type * bitBlock_i8type = VectorType::get(getInt8Ty(), mBitBlockWidth/8);
281            Value * a_as_ps = CreateBitCast(a, bitBlock_i8type);
282            return CreateCall(signmask_f8func, a_as_ps);
283        }
284    }
285    // Otherwise use default SSE logic.
286    return IDISA_AVX_Builder::hsimd_signmask(fw, a);
287}
288
289llvm::Value * IDISA_AVX2_Builder::mvmd_srl(unsigned fw, llvm::Value * a, llvm::Value * shift) {
290    // Intrinsic::x86_avx2_permd) allows an efficient implementation for field width 32.
291    // Translate larger field widths to 32 bits.
292    if (fw > 32) {
293        return fwCast(fw, mvmd_srl(32, a, CreateMul(shift, ConstantInt::get(shift->getType(), fw/32))));
294    }
295    if ((mBitBlockWidth == 256) && (fw == 32)) {
296        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_permd);
297        const unsigned fieldCount = mBitBlockWidth/fw;
298        Type * fieldTy = getIntNTy(fw);
299        Constant * indexes[fieldCount];
300        for (unsigned int i = 0; i < fieldCount; i++) {
301            indexes[i] = ConstantInt::get(fieldTy, i);
302        }
303        Constant * indexVec = ConstantVector::get({indexes, fieldCount});
304        Constant * fieldCountSplat = ConstantVector::getSplat(fieldCount, ConstantInt::get(fieldTy, fieldCount));
305        Value * shiftSplat = simd_fill(fw, CreateZExtOrTrunc(shift, fieldTy));
306        Value * permuteVec = CreateAdd(indexVec, shiftSplat);
307        // Zero out fields that are above the max.
308        permuteVec = simd_and(permuteVec, simd_ult(fw, permuteVec, fieldCountSplat));
309        // Insert a zero value at position 0 (OK for shifts > 0)
310        Value * a0 = mvmd_insert(fw, a, Constant::getNullValue(fieldTy), 0);
311        Value * shifted = CreateCall(permuteFunc, {a0, permuteVec});
312        return simd_if(1, simd_eq(fw, shiftSplat, allZeroes()), a, shifted);
313    }
314    return IDISA_Builder::mvmd_srl(fw, a, shift);
315}
316
317llvm::Value * IDISA_AVX2_Builder::mvmd_sll(unsigned fw, llvm::Value * a, llvm::Value * shift) {
318    // Intrinsic::x86_avx2_permd) allows an efficient implementation for field width 32.
319    // Translate larger field widths to 32 bits.
320    if (fw > 32) {
321        return fwCast(fw, mvmd_sll(32, a, CreateMul(shift, ConstantInt::get(shift->getType(), fw/32))));
322    }
323    if ((mBitBlockWidth == 256) && (fw == 32)) {
324        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_permd);
325        const unsigned fieldCount = mBitBlockWidth/fw;
326        Type * fieldTy = getIntNTy(fw);
327        Constant * indexes[fieldCount];
328        for (unsigned int i = 0; i < fieldCount; i++) {
329            indexes[i] = ConstantInt::get(fieldTy, i);
330        }
331        Constant * indexVec = ConstantVector::get({indexes, fieldCount});
332        Value * shiftSplat = simd_fill(fw, CreateZExtOrTrunc(shift, fieldTy));
333        Value * permuteVec = CreateSub(indexVec, shiftSplat);
334        // Negative indexes are for fields that must be zeroed.  Convert the
335        // permute constant to an all ones value, that will select item 7.
336        permuteVec = simd_or(permuteVec, simd_lt(fw, permuteVec, fwCast(fw, allZeroes())));
337        // Insert a zero value at position 7 (OK for shifts > 0)
338        Value * a0 = mvmd_insert(fw, a, Constant::getNullValue(fieldTy), 7);
339        Value * shifted = CreateCall(permuteFunc, {a0, permuteVec});
340        return simd_if(1, simd_eq(fw, shiftSplat, allZeroes()), a, shifted);
341    }
342    return IDISA_Builder::mvmd_sll(fw, a, shift);
343}
344
345   
346llvm::Value * IDISA_AVX2_Builder::mvmd_shuffle(unsigned fw, llvm::Value * a, llvm::Value * shuffle_table) {
347    if (mBitBlockWidth == 256 && fw > 32) {
348        // Create a table for shuffling with smaller field widths.
349        unsigned half_fw = fw/2;
350        unsigned field_count = mBitBlockWidth/half_fw;
351        // Build a ConstantVector of alternating 0 and 1 values.
352        Constant * Idxs[field_count];
353        for (unsigned int i = 0; i < field_count; i++) {
354            Idxs[i] = getInt32(i & 1);
355        }
356        Constant * splat01 = ConstantVector::get({Idxs, field_count});
357        Value * half_shuffle_table = simd_or(shuffle_table, mvmd_slli(half_fw, shuffle_table, 1));
358        half_shuffle_table = simd_add(fw, simd_add(fw, half_shuffle_table, half_shuffle_table), splat01);
359        Value * rslt = mvmd_shuffle(half_fw, a, half_shuffle_table);
360        return rslt;
361    }
362    if (mBitBlockWidth == 256 && fw == 32) {
363        Value * shuf32Func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_permd);
364        return CreateCall(shuf32Func, {fwCast(32, a), fwCast(32, shuffle_table)});
365    }
366    return IDISA_Builder::mvmd_shuffle(fw, a, shuffle_table);
367}
368
369llvm::Value * IDISA_AVX2_Builder::mvmd_compress(unsigned fw, llvm::Value * a, llvm::Value * select_mask) {
370    if (mBitBlockWidth == 256 && fw == 64) {
371        Value * PDEP_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_32);
372        Value * mask = CreateZExt(select_mask, getInt32Ty());
373        Value * mask32 = CreateMul(CreateCall(PDEP_func, {mask, getInt32(0x55)}), getInt32(3));
374        Value * result = fwCast(fw, mvmd_compress(32, fwCast(32, a), CreateTrunc(mask32, getInt8Ty())));
375        return result;
376    }
377    if (mBitBlockWidth == 256 && fw == 32) {
378        Type * v1xi32Ty = VectorType::get(getInt32Ty(), 1);
379        Type * v8xi32Ty = VectorType::get(getInt32Ty(), 8);
380        Type * v8xi1Ty = VectorType::get(getInt1Ty(), 8);
381        Constant * mask0000000Fsplaat = ConstantVector::getSplat(8, ConstantInt::get(getInt32Ty(), 0xF));
382        Value * PEXT_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pext_32);
383        Value * PDEP_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_bmi_pdep_32);
384        Value * const popcount_func = Intrinsic::getDeclaration(getModule(), Intrinsic::ctpop, getInt32Ty());
385        // First duplicate each mask bit to select 4-bit fields
386        Value * mask = CreateZExt(select_mask, getInt32Ty());
387        Value * field_count = CreateCall(popcount_func, mask);
388        Value * spread = CreateCall(PDEP_func, {mask, getInt32(0x11111111)});
389        Value * ext_mask = CreateMul(spread, getInt32(0xF));
390        // Now extract the 4-bit index values for the required fields.
391        Value * indexes = CreateCall(PEXT_func, {getInt32(0x76543210), ext_mask});
392        // Broadcast to all fields
393        Value * bdcst = CreateShuffleVector(CreateBitCast(indexes, v1xi32Ty),
394                                            UndefValue::get(v1xi32Ty),
395                                            ConstantVector::getNullValue(v8xi32Ty));
396        Constant * Shifts[8];
397        for (unsigned int i = 0; i < 8; i++) {
398            Shifts[i] = getInt32(i*4);
399        }
400        Value * shuf = CreateAnd(CreateLShr(bdcst, ConstantVector::get({Shifts, 8})), mask0000000Fsplaat);
401        Value * compress = mvmd_shuffle(32, a, shuf);
402        Value * field_mask = CreateTrunc(CreateSub(CreateShl(getInt32(1), field_count), getInt32(1)), getInt8Ty());
403        Value * result = CreateAnd(compress, CreateSExt(CreateBitCast(field_mask, v8xi1Ty), v8xi32Ty));
404        return result;
405    }
406    return IDISA_Builder::mvmd_compress(fw, a, select_mask);
407}
408
409std::string IDISA_AVX512F_Builder::getBuilderUniqueName() {
410    return mBitBlockWidth != 512 ? "AVX512F_" + std::to_string(mBitBlockWidth) : "AVX512BW";
411}
412
413llvm::Value * IDISA_AVX512F_Builder::hsimd_packh(unsigned fw, llvm::Value * a, llvm::Value * b) {
414    if ((mBitBlockWidth == 512) && (fw == 16)) {
415
416        const unsigned int field_count = 64;
417        Constant * Idxs[field_count];
418
419        for (unsigned int i = 0; i < field_count; i++) {
420            Idxs[i] = getInt32(i);
421        }
422
423        llvm::Value * pmovfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_pmov_wb_512);
424        llvm::Value * mask = getInt32(-1);
425        llvm::Constant * shuffleMask = ConstantVector::get({Idxs, 64});
426        llvm::Constant * src = UndefValue::get(VectorType::get(getInt8Ty(), 32));
427
428        a = fwCast(fw, a);
429        a = IDISA_Builder::simd_srli(fw, a, fw/2);
430        a = CreateCall(pmovfunc, {a, src, mask});
431        b = fwCast(fw, b);
432        b = IDISA_Builder::simd_srli(fw, b, fw/2);
433        b = CreateCall(pmovfunc, {b, src, mask});
434
435        llvm::Value * c = CreateShuffleVector(a, b, shuffleMask);
436        c = bitCast(c);
437        return c;
438    }
439    return IDISA_Builder::hsimd_packh(fw, a, b);
440}
441
442llvm::Value * IDISA_AVX512F_Builder::hsimd_packl(unsigned fw, llvm::Value * a, llvm::Value * b) {
443    if ((mBitBlockWidth == 512) && (fw == 16)) {
444
445        const unsigned int field_count = 64;
446        Constant * Idxs[field_count];
447        for (unsigned int i = 0; i < field_count; i++) {
448            Idxs[i] = getInt32(i);
449        }
450
451        llvm::Value * pmovfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_pmov_wb_512);
452        llvm::Value * mask = getInt32(-1);
453        llvm::Constant * shuffleMask = ConstantVector::get({Idxs, 64});
454        llvm::Constant * src = UndefValue::get(VectorType::get(getInt8Ty(), 32));
455        a = fwCast(fw, a);
456        a = CreateCall(pmovfunc, {a, src, mask});
457        b = fwCast(fw, b);
458        b = CreateCall(pmovfunc, {b, src, mask});
459
460        llvm::Value * c = CreateShuffleVector(a, b, shuffleMask);
461        c = bitCast(c);
462        return c;
463    }
464    return IDISA_Builder::hsimd_packl(fw, a, b);
465}
466
467llvm::Value * IDISA_AVX512F_Builder::esimd_bitspread(unsigned fw, llvm::Value * bitmask) {
468   
469    if (mBitBlockWidth == 512 && fw == 64) {
470        Value * broadcastFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_broadcasti64x4_512);
471        Value * broadcastMask = CreateZExtOrTrunc(bitmask, getInt8Ty());
472       
473        const unsigned int srcFieldCount = 8;
474        Constant * srcArr[srcFieldCount];
475        for (unsigned int i = 0; i < srcFieldCount; i++) {
476            srcArr[i] = getInt64(0);
477        }
478        Constant * src = ConstantVector::get({srcArr, srcFieldCount});
479       
480        const unsigned int aFieldCount = 4;
481        Constant * aArr[aFieldCount];
482        for (unsigned int i = 0; i < aFieldCount; i++) {
483            aArr[i] = getInt64(1);
484        }
485        Constant * a = ConstantVector::get({aArr, aFieldCount});
486       
487        return CreateCall(broadcastFunc, {a, src, broadcastMask});
488    }
489   
490    return IDISA_Builder::esimd_bitspread(fw, bitmask);
491}
492
493llvm::Value * IDISA_AVX512F_Builder::mvmd_srl(unsigned fw, llvm::Value * a, llvm::Value * shift) {
494    const unsigned fieldCount = mBitBlockWidth/fw;
495    Type * fieldTy = getIntNTy(fw);
496    Constant * indexes[fieldCount];
497    for (unsigned int i = 0; i < fieldCount; i++) {
498        indexes[i] = ConstantInt::get(fieldTy, i);
499    }
500    Constant * indexVec = ConstantVector::get({indexes, fieldCount});
501    Value * permuteVec = CreateAdd(indexVec, simd_fill(fw, CreateZExtOrTrunc(shift, fieldTy)));
502    Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
503    if (mBitBlockWidth == 512) {
504        Value * permuteFunc = nullptr;
505        if (fw == 64) permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_q_512);
506        else if (fw == 32) permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_d_512);
507        if (permuteFunc) {
508            Value * shifted = CreateCall(permuteFunc, {permuteVec, fwCast(fw, a), fwCast(fw, allZeroes()), mask});
509            return shifted;
510        }
511    }
512    return IDISA_Builder::mvmd_srl(fw, a, shift);
513}
514 
515llvm::Value * IDISA_AVX512F_Builder::mvmd_sll(unsigned fw, llvm::Value * a, llvm::Value * shift) {
516    const unsigned fieldCount = mBitBlockWidth/fw;
517    Type * fieldTy = getIntNTy(fw);
518    Constant * indexes[fieldCount];
519    for (unsigned int i = 0; i < fieldCount; i++) {
520        indexes[i] = ConstantInt::get(fieldTy, fieldCount + i);
521    }
522    Constant * indexVec = ConstantVector::get({indexes, fieldCount});
523    Value * permuteVec = CreateSub(indexVec, simd_fill(fw, CreateZExtOrTrunc(shift, fieldTy)));
524    Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
525    if (mBitBlockWidth == 512) {
526        Value * permuteFunc = nullptr;
527        if (fw == 64) permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_q_512);
528        else if (fw == 32) permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_d_512);
529        if (permuteFunc) {
530            Value * shifted = CreateCall(permuteFunc, {permuteVec, fwCast(fw, allZeroes()), fwCast(fw, a), mask});
531            return shifted;
532        }
533    }
534    return IDISA_Builder::mvmd_sll(fw, a, shift);
535}
536
537llvm::Value * IDISA_AVX512F_Builder::mvmd_shuffle(unsigned fw, llvm::Value * a, llvm::Value * shuffle_table) {
538    const unsigned fieldCount = mBitBlockWidth/fw;
539    if (mBitBlockWidth == 512 && fw == 32) {
540        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_d_512);
541        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
542        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), UndefValue::get(fwVectorType(fw)), mask});
543    }
544    if (mBitBlockWidth == 512 && fw == 64) {
545        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_q_512);
546        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
547        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), UndefValue::get(fwVectorType(fw)), mask});
548    }
549    if (mBitBlockWidth == 512 && fw == 16 && hostCPUFeatures.hasAVX512BW) {
550        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_hi_512);
551        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
552        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), UndefValue::get(fwVectorType(fw)), mask});
553    }
554    return IDISA_Builder::mvmd_shuffle(fw, a, shuffle_table);
555}
556
557llvm::Value * IDISA_AVX512F_Builder::mvmd_shuffle2(unsigned fw, Value * a, Value * b, llvm::Value * shuffle_table) {
558    const unsigned fieldCount = mBitBlockWidth/fw;
559    if (mBitBlockWidth == 512 && fw == 32) {
560        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_d_512);
561        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
562        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), fwCast(fw, b), mask});
563    }
564    if (mBitBlockWidth == 512 && fw == 64) {
565        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_vpermt2var_q_512);
566        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
567        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), fwCast(fw, b), mask});
568    }
569    if (mBitBlockWidth == 512 && fw == 16 && hostCPUFeatures.hasAVX512BW) {
570        Value * permuteFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_hi_512);
571        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(fieldCount));
572        return CreateCall(permuteFunc, {fwCast(fw, shuffle_table), fwCast(fw, a), fwCast(fw, b), mask});
573    }
574    return IDISA_Builder::mvmd_shuffle2(fw, a, b, shuffle_table);
575}
576
577llvm::Value * IDISA_AVX512F_Builder::mvmd_compress(unsigned fw, llvm::Value * a, llvm::Value * select_mask) {
578    if (mBitBlockWidth == 512 && fw == 32) {
579        Value * compressFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_compress_d_512);
580        return CreateCall(compressFunc, {fwCast(32, a), fwCast(32, allZeroes()), CreateZExtOrTrunc(select_mask, getInt16Ty())});
581    }
582    if (mBitBlockWidth == 512 && fw == 64) {
583        Value * compressFunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_compress_q_512);
584        return CreateCall(compressFunc, {fwCast(64, a), fwCast(64, allZeroes()), CreateZExtOrTrunc(select_mask, getInt8Ty())});
585    }
586    return IDISA_Builder::mvmd_compress(fw, a, select_mask);
587}
588
589Value * IDISA_AVX512F_Builder:: mvmd_slli(unsigned fw, llvm::Value * a, unsigned shift) {
590    if (shift == 0) return a;
591    if (fw > 32) {
592        return mvmd_slli(32, a, shift * (fw/32));
593    } else if (((shift % 2) == 0) && (fw < 32)) {
594        return mvmd_slli(2 * fw, a, shift / 2);
595    }
596    const unsigned field_count = mBitBlockWidth/fw;
597    if ((fw == 32) || (hostCPUFeatures.hasAVX512BW && (fw == 16)))   {
598        // Mask with 1 bit per field indicating which fields are not zeroed out.
599        Type * fwTy = getIntNTy(fw);
600        Constant * fieldMask = ConstantInt::get(getIntNTy(field_count), (1 << field_count) - (1 << shift));
601        Value * permute_func = nullptr;
602        if (fw == 32) permute_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_d_512);
603        else permute_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_hi_512);
604        Constant * indices[field_count];
605        for (unsigned i = 0; i < field_count; i++) {
606            indices[i] = i < shift ? UndefValue::get(fwTy) : ConstantInt::get(fwTy, i - shift);
607        }
608        Value * args[4] = {ConstantVector::get({indices, field_count}), fwCast(fw, a), UndefValue::get(fwVectorType(fw)), fieldMask};
609        return bitCast(CreateCall(permute_func, args));
610    } else {
611        unsigned field32_shift = (shift * fw) / 32;
612        unsigned bit_shift = (shift * fw) % 32;
613        return simd_or(simd_slli(32, mvmd_slli(32, a, field32_shift), bit_shift),
614                       simd_srli(32, mvmd_slli(32, a, field32_shift + 1), 32-bit_shift));
615    }
616}
617
618Value * IDISA_AVX512F_Builder:: mvmd_dslli(unsigned fw, llvm::Value * a, llvm::Value * b, unsigned shift) {
619    if (shift == 0) return a;
620    if (fw > 32) {
621        return mvmd_dslli(32, a, b, shift * (fw/32));
622    } else if (((shift % 2) == 0) && (fw < 32)) {
623        return mvmd_dslli(2 * fw, a, b, shift / 2);
624    }
625    const unsigned field_count = mBitBlockWidth/fw;
626    if ((fw == 32) || (hostCPUFeatures.hasAVX512BW && (fw == 16)))   {
627        Type * fwTy = getIntNTy(fw);
628        Value * permute_func = nullptr;
629        if (fw == 32) permute_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_d_512);
630        else permute_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_maskz_vpermt2var_hi_512);
631        Constant * indices[field_count];
632        for (unsigned i = 0; i < field_count; i++) {
633            indices[i] = ConstantInt::get(fwTy, i + field_count - shift);
634        }
635        Constant * mask = ConstantInt::getAllOnesValue(getIntNTy(field_count));
636        Value * args[4] = {ConstantVector::get({indices, field_count}), fwCast(fw, a), fwCast(fw, b), mask};
637        return bitCast(CreateCall(permute_func, args));
638    } else {
639        unsigned field32_shift = (shift * fw) / 32;
640        unsigned bit_shift = (shift * fw) % 32;
641        return simd_or(simd_slli(32, mvmd_slli(32, a, field32_shift), bit_shift),
642                       simd_srli(32, mvmd_slli(32, a, field32_shift + 1), 32-bit_shift));
643    }
644}
645
646llvm::Value * IDISA_AVX512F_Builder::simd_popcount(unsigned fw, llvm::Value * a) {
647     if (fw == 512) {
648         Constant * zero16xi8 = Constant::getNullValue(VectorType::get(getInt8Ty(), 16));
649         Constant * zeroInt32 = Constant::getNullValue(getInt32Ty());
650         Value * c = simd_popcount(64, a);
651         //  Should probably use _mm512_reduce_add_epi64, but not found in LLVM 3.8
652         Value * pack64_8_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_mask_pmov_qb_512);
653         // popcounts of 64 bit fields will always fit in 8 bit fields.
654         // We don't need the masked version of this, but the unmasked intrinsic was not found.
655         c = CreateCall(pack64_8_func, {c, zero16xi8, Constant::getAllOnesValue(getInt8Ty())});
656         Value * horizSADfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_psad_bw);
657         c = CreateCall(horizSADfunc, {c, zero16xi8});
658         return CreateInsertElement(allZeroes(), CreateExtractElement(c, zeroInt32), zeroInt32);
659    }
660    if (hostCPUFeatures.hasAVX512VPOPCNTDQ && (fw == 32 || fw == 64)){
661        //llvm should use vpopcntd or vpopcntq instructions
662        return CreatePopcount(fwCast(fw, a));
663    }
664    if (hostCPUFeatures.hasAVX512BW && (fw == 64)) {
665        Value * horizSADfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx512_psad_bw_512);
666        return bitCast(CreateCall(horizSADfunc, {fwCast(8, simd_popcount(8, a)), fwCast(8, allZeroes())}));
667    }
668    //https://en.wikipedia.org/wiki/Hamming_weight#Efficient_implementation
669    if((fw == 64) && (mBitBlockWidth == 512)){
670        Constant * m1Arr[8];
671        llvm::Constant * m1;
672        for (unsigned int i = 0; i < 8; i++) {
673            m1Arr[i] = getInt64(0x5555555555555555);
674        }
675        m1 = ConstantVector::get({m1Arr, 8});
676       
677        Constant * m2Arr[8];
678        llvm::Constant * m2;
679        for (unsigned int i = 0; i < 8; i++) {
680            m2Arr[i] = getInt64(0x3333333333333333);
681        }
682        m2 = ConstantVector::get({m2Arr, 8});
683       
684        Constant * m4Arr[8];
685        llvm::Constant * m4;
686        for (unsigned int i = 0; i < 8; i++) {
687            m4Arr[i] = getInt64(0x0f0f0f0f0f0f0f0f);
688        }
689        m4 = ConstantVector::get({m4Arr, 8});
690       
691        Constant * h01Arr[8];
692        llvm::Constant * h01;
693        for (unsigned int i = 0; i < 8; i++) {
694            h01Arr[i] = getInt64(0x0101010101010101);
695        }
696        h01 = ConstantVector::get({h01Arr, 8});
697       
698        a = simd_sub(fw, a, simd_and(simd_srli(fw, a, 1), m1));
699        a = simd_add(fw, simd_and(a, m2), simd_and(simd_srli(fw, a, 2), m2));
700        a = simd_and(simd_add(fw, a, simd_srli(fw, a, 4)), m4);
701        return simd_srli(fw, simd_mult(fw, a, h01), 56);
702       
703    }
704    return IDISA_Builder::simd_popcount(fw, a);
705}
706
707llvm::Value * IDISA_AVX512F_Builder::hsimd_signmask(unsigned fw, llvm::Value * a) {
708    //IDISA_Builder::hsimd_signmask outperforms IDISA_AVX2_Builder::hsimd_signmask
709    //when run with BlockSize=512
710    return IDISA_Builder::hsimd_signmask(fw, a);
711}
712
713void IDISA_AVX512F_Builder::getAVX512Features() {
714    llvm::StringMap<bool> features;
715    if (llvm::sys::getHostCPUFeatures(features)) {
716        hostCPUFeatures.hasAVX512CD = features.lookup("avx512cd");
717        hostCPUFeatures.hasAVX512BW = features.lookup("avx512bw");
718        hostCPUFeatures.hasAVX512DQ = features.lookup("avx512dq");
719        hostCPUFeatures.hasAVX512VL = features.lookup("avx512vl");
720       
721        //hostCPUFeatures.hasAVX512VBMI, hostCPUFeatures.hasAVX512VBMI2,
722        //hostCPUFeatures.hasAVX512VPOPCNTDQ have not been tested as we
723        //did not have hardware support. It should work in theory (tm)
724       
725        hostCPUFeatures.hasAVX512VBMI = features.lookup("avx512_vbmi");
726        hostCPUFeatures.hasAVX512VBMI2 = features.lookup("avx512_vbmi2");
727        hostCPUFeatures.hasAVX512VPOPCNTDQ = features.lookup("avx512_vpopcntdq");
728    }
729}
730
731
732}
Note: See TracBrowser for help on using the repository browser.