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

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

Replaced short vector construction in IDISA_Builder with stack allocated arrays.

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