source: icGREP/icgrep-devel/icgrep/IDISA/idisa_avx_builder.cpp @ 5115

Last change on this file since 5115 was 5115, checked in by cameron, 3 years ago

Use bitblock_add_with_carry in carry_manager; add AVX2 implementation

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