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

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

esimd_merge 8 for AVX-512; improves p2s performance

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