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

Last change on this file since 6076 was 6076, checked in by cameron, 11 months ago

IDISA_SSSE3 builder; other IDISA operations

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