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

Last change on this file since 5463 was 5440, checked in by nmedfort, 2 years ago

Large refactoring step. Removed IR generation code from Kernel (formally KernelBuilder?) and moved it into the new KernelBuilder? class.

File size: 7.2 KB
Line 
1/*
2 *  Copyright (c) 2015 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
9namespace IDISA {
10   
11std::string IDISA_AVX_Builder::getBuilderUniqueName() {
12    return mBitBlockWidth != 256 ? "AVX_" + std::to_string(mBitBlockWidth) : "AVX";
13}
14
15Value * IDISA_AVX_Builder::hsimd_signmask(unsigned fw, Value * a) {
16    // AVX2 special cases
17    if (mBitBlockWidth == 256) {
18        if (fw == 64) {
19            Value * signmask_f64func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_pd_256);
20            Type * bitBlock_f64type = VectorType::get(getDoubleTy(), mBitBlockWidth/64);
21            Value * a_as_pd = CreateBitCast(a, bitBlock_f64type);
22            return CreateCall(signmask_f64func, a_as_pd);
23        } else if (fw == 32) {
24            Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_ps_256);
25            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
26            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
27            return CreateCall(signmask_f32func, a_as_ps);
28        }
29    } else if (mBitBlockWidth == 512) {
30        if (fw == 64) {
31            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth / 32);
32            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
33            Constant * indicies[8];
34            for (unsigned i = 0; i < 8; i++) {
35                indicies[i] = getInt32(2 * i + 1);
36            }
37            Value * packh = CreateShuffleVector(a_as_ps, UndefValue::get(bitBlock_f32type), ConstantVector::get({indicies, 8}));
38            Type * halfBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/64);
39            Value * pack_as_ps = CreateBitCast(packh, halfBlock_f32type);
40            Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx_movmsk_ps_256);
41            return CreateCall(signmask_f32func, pack_as_ps);
42        }
43    }
44    // Otherwise use default SSE logic.
45    return IDISA_SSE_Builder::hsimd_signmask(fw, a);
46}
47
48std::string IDISA_AVX2_Builder::getBuilderUniqueName() {
49    return mBitBlockWidth != 256 ? "AVX2_" + std::to_string(mBitBlockWidth) : "AVX2";
50}
51   
52Value * IDISA_AVX2_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
53    if (fw <= 64) {       
54        Value * aVec = fwCast(fw / 2, a);
55        Value * bVec = fwCast(fw / 2, b);
56        const auto field_count = 2 * mBitBlockWidth / fw;
57        Constant * Idxs[field_count];
58        const auto H = (field_count / 2);
59        const auto Q = (field_count / 4);
60        for (unsigned i = 0; i < Q; i++) {
61            Idxs[i] = getInt32(2 * i);
62            Idxs[i + Q] = getInt32((2 * i) + 1);
63            Idxs[i + H] = getInt32((2 * i) + H);
64            Idxs[i + H + Q] = getInt32((2 * i) + 1 + H);
65        }
66        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get({Idxs, field_count}));
67        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get({Idxs, field_count}));
68        return hsimd_packh(mBitBlockWidth / 2, shufa, shufb);
69    }
70    // Otherwise use default SSE logic.
71    return IDISA_SSE_Builder::hsimd_packh(fw, a, b);
72}
73
74Value * IDISA_AVX2_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
75    if (fw <= 64) {
76        Value * aVec = fwCast(fw / 2, a);
77        Value * bVec = fwCast(fw / 2, b);
78        const auto field_count = 2 * mBitBlockWidth / fw;
79        Constant * Idxs[field_count];
80        const auto H = (field_count / 2);
81        const auto Q = (field_count / 4);
82        for (unsigned i = 0; i < Q; i++) {
83            Idxs[i] = getInt32(2 * i);
84            Idxs[i + Q] = getInt32((2 * i) + 1);
85            Idxs[i + H] = getInt32((2 * i) + H);
86            Idxs[i + H + Q] = getInt32((2 * i) + H + 1);
87        }
88        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get({Idxs, field_count}));
89        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get({Idxs, field_count}));
90        return hsimd_packl(mBitBlockWidth / 2, shufa, shufb);
91    }
92    // Otherwise use default SSE logic.
93    return IDISA_SSE_Builder::hsimd_packl(fw, a, b);
94}
95   
96Value * IDISA_AVX2_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {
97    if ((fw == 128) && (mBitBlockWidth == 256)) {
98        Value * vperm2i128func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_vperm2i128);
99        return CreateCall(vperm2i128func, {fwCast(64, a), fwCast(64, b), getInt8(0x31)});
100    }
101    // Otherwise use default SSE logic.
102    return IDISA_SSE_Builder::esimd_mergeh(fw, a, b);
103}
104
105Value * IDISA_AVX2_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {
106    if ((fw == 128) && (mBitBlockWidth == 256)) {
107        Value * vperm2i128func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_vperm2i128);
108        return CreateCall(vperm2i128func, {fwCast(64, a), fwCast(64, b), getInt8(0x20)});
109    }
110    // Otherwise use default SSE logic.
111    return IDISA_SSE_Builder::esimd_mergel(fw, a, b);
112}
113
114Value * IDISA_AVX2_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
115    if ((fw == 16)  && (lanes == 2)) {
116        Value * vpackuswbfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_packuswb);
117        Value * a_low = fwCast(16, simd_and(a, simd_lomask(fw)));
118        Value * b_low = fwCast(16, simd_and(b, simd_lomask(fw)));
119        return CreateCall(vpackuswbfunc, {a_low, b_low});
120    }
121    // Otherwise use default SSE logic.
122    return IDISA_SSE_Builder::hsimd_packl_in_lanes(lanes, fw, a, b);
123}
124
125Value * IDISA_AVX2_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
126    if ((fw == 16)  && (lanes == 2)) {
127        Value * vpackuswbfunc = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_avx2_packuswb);
128        Value * a_low = simd_srli(fw, a, fw/2);
129        Value * b_low = simd_srli(fw, b, fw/2);
130        return CreateCall(vpackuswbfunc, {a_low, b_low});
131    }
132    // Otherwise use default SSE logic.
133    return IDISA_SSE_Builder::hsimd_packh_in_lanes(lanes, fw, a, b);
134}
135   
136std::pair<Value *, Value *> IDISA_AVX2_Builder::bitblock_add_with_carry(Value * e1, Value * e2, Value * carryin) {
137    // using LONG_ADD
138    Type * carryTy = carryin->getType();
139    if (carryTy == mBitBlockType) {
140        carryin = mvmd_extract(32, carryin, 0);
141    }
142    Value * carrygen = simd_and(e1, e2);
143    Value * carryprop = simd_or(e1, e2);
144    Value * digitsum = simd_add(64, e1, e2);
145    Value * digitcarry = simd_or(carrygen, simd_and(carryprop, CreateNot(digitsum)));
146    Value * carryMask = hsimd_signmask(64, digitcarry);
147    Value * carryMask2 = CreateOr(CreateAdd(carryMask, carryMask), carryin);
148    Value * bubble = simd_eq(64, digitsum, allOnes());
149    Value * bubbleMask = hsimd_signmask(64, bubble);
150    Value * incrementMask = CreateXor(CreateAdd(bubbleMask, carryMask2), bubbleMask);
151    Value * increments = esimd_bitspread(64,incrementMask);
152    Value * sum = simd_add(64, digitsum, increments);
153    Value * carry_out = CreateLShr(incrementMask, mBitBlockWidth / 64);
154    if (carryTy == mBitBlockType) {
155        carry_out = bitCast(CreateZExt(carry_out, getIntNTy(mBitBlockWidth)));
156    }
157    return std::pair<Value *, Value *>{carry_out, bitCast(sum)};
158}
159   
160}
Note: See TracBrowser for help on using the repository browser.