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

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

Alternative transposition strategies with AVX2

File size: 8.6 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
13namespace IDISA {
14
15Value * IDISA_AVX_Builder::hsimd_signmask(unsigned fw, Value * a) {
16    if (mBitBlockWidth == 256) {
17        if (fw == 64) {
18            Value * signmask_f64func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx_movmsk_pd_256);
19            Type * bitBlock_f64type = VectorType::get(getDoubleTy(), mBitBlockWidth/64);
20            Value * a_as_pd = CreateBitCast(a, bitBlock_f64type);
21            Value * mask = CreateCall(signmask_f64func, std::vector<Value *>({a_as_pd}));
22            return mask;
23        }
24        else if (fw == 32) {
25            Value * signmask_f32func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx_movmsk_ps_256);
26            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
27            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
28            Value * mask = CreateCall(signmask_f32func, std::vector<Value *>({a_as_ps}));
29            return mask;
30        }
31    }
32    else if (mBitBlockWidth == 512) {
33        if (fw == 64) {
34            Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
35            Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
36            std::vector<Constant*> Idxs;
37            for (unsigned i = 0; i < 8; i++) {
38                Idxs.push_back(getInt32(2*i+1));
39            }
40            Value * packh = CreateShuffleVector(a_as_ps, UndefValue::get(bitBlock_f32type), ConstantVector::get(Idxs));
41            Type * halfBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/64);
42            Value * pack_as_ps = CreateBitCast(packh, halfBlock_f32type);
43            Value * signmask_f32func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx_movmsk_ps_256);
44            Value * mask = CreateCall(signmask_f32func, std::vector<Value *>({pack_as_ps}));
45            return mask;
46        }
47    }
48    Value * mask = CreateICmpSLT(fwCast(fw, a), ConstantAggregateZero::get(fwVectorType(fw)));
49    return CreateBitCast(mask, getIntNTy(mBitBlockWidth/fw));
50}
51   
52Value * IDISA_AVX2_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {
53    unsigned field_count = 2 * mBitBlockWidth/fw;
54    Value * aVec = fwCast(fw/2, a);
55    Value * bVec = fwCast(fw/2, b);
56    if (fw <= 64) {
57        std::vector<Constant*> Idxs;
58        for (unsigned i = 0; i < field_count/4; i++) {
59            Idxs.push_back(getInt32(2*i + 1));
60        }
61        for (unsigned i = 0; i < field_count/4; i++) {
62            Idxs.push_back(getInt32(2*i));
63        }
64        for (unsigned i = 0; i < field_count/4; i++) {
65            Idxs.push_back(getInt32(field_count/2 + 2*i + 1));
66        }
67        for (unsigned i = 0; i < field_count/4; i++) {
68            Idxs.push_back(getInt32(field_count/2 + 2*i));
69        }
70        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get(Idxs));
71        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get(Idxs));
72        return hsimd_packh(mBitBlockWidth/2, shufa, shufb);
73    }
74    else {
75        std::vector<Constant*> Idxs;
76        for (unsigned i = 0; i < field_count; i++) {
77            Idxs.push_back(getInt32(2*i));
78        }
79        return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
80    }
81}
82
83Value * IDISA_AVX2_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
84    unsigned field_count = 2 * mBitBlockWidth/fw;
85    Value * aVec = fwCast(fw/2, a);
86    Value * bVec = fwCast(fw/2, b);
87    if (fw <= 64) {
88        std::vector<Constant*> Idxs;
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(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        for (unsigned i = 0; i < field_count/4; i++) {
99            Idxs.push_back(getInt32(field_count/2 + 2*i));
100        }
101        Value * shufa = CreateShuffleVector(aVec, aVec, ConstantVector::get(Idxs));
102        Value * shufb = CreateShuffleVector(bVec, bVec, ConstantVector::get(Idxs));
103        return hsimd_packl(mBitBlockWidth/2, shufa, shufb);
104    }
105    else {
106        std::vector<Constant*> Idxs;
107        for (unsigned i = 0; i < field_count; i++) {
108            Idxs.push_back(getInt32(2*i+1));
109        }
110        return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
111    }
112}
113   
114Value * IDISA_AVX2_Builder::esimd_mergeh(unsigned fw, Value * a, Value * b) {
115    if ((fw == 128) && (mBitBlockWidth == 256)) {
116        Value * vperm2i128func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx2_vperm2i128);
117        return CreateCall3(vperm2i128func, fwCast(64, a), fwCast(64, b), getInt8(0x31));
118    }
119    unsigned field_count = mBitBlockWidth/fw;
120    Value * aVec = fwCast(fw, a);
121    Value * bVec = fwCast(fw, b);
122    std::vector<Constant*> Idxs;
123    for (unsigned i = field_count/2; i < field_count; i++) {
124        Idxs.push_back(getInt32(i));    // selects elements from first reg.
125        Idxs.push_back(getInt32(i + field_count)); // selects elements from second reg.
126    }
127    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
128}
129
130Value * IDISA_AVX2_Builder::esimd_mergel(unsigned fw, Value * a, Value * b) {
131    if ((fw == 128) && (mBitBlockWidth == 256)) {
132        Value * vperm2i128func = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx2_vperm2i128);
133        return CreateCall3(vperm2i128func, fwCast(64, a), fwCast(64, b), getInt8(0x20));
134    }
135    unsigned field_count = mBitBlockWidth/fw;
136    Value * aVec = fwCast(fw, a);
137    Value * bVec = fwCast(fw, b);
138    std::vector<Constant*> Idxs;
139    for (unsigned i = 0; i < field_count/2; i++) {
140        Idxs.push_back(getInt32(i));    // selects elements from first reg.
141        Idxs.push_back(getInt32(i + field_count)); // selects elements from second reg.
142    }
143    return CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
144}
145
146Value * IDISA_AVX2_Builder::hsimd_packl_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
147    if ((fw == 16)  && (lanes == 2)) {
148        Value * vpackuswbfunc = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx2_packuswb);
149        Value * a_low = fwCast(16, simd_and(a, simd_lomask(fw)));
150        Value * b_low = fwCast(16, simd_and(b, simd_lomask(fw)));
151        Value * pack = CreateCall2(vpackuswbfunc, a_low, b_low);
152        return pack;
153    }
154    unsigned fw_out = fw/2;
155    unsigned fields_per_lane = mBitBlockWidth/(fw_out * lanes);
156    unsigned field_offset_for_b = mBitBlockWidth/fw_out;
157    Value * aVec = fwCast(fw_out, a);
158    Value * bVec = fwCast(fw_out, b);
159    std::vector<Constant*> Idxs;
160    for (unsigned lane = 0; lane < lanes; lane++) {
161        unsigned first_field_in_lane = lane * fields_per_lane; // every second field
162        for (unsigned i = 0; i < fields_per_lane/2; i++) {
163            Idxs.push_back(getInt32(first_field_in_lane + 2*i));
164        }
165        for (unsigned i = 0; i < fields_per_lane/2; i++) {
166            Idxs.push_back(getInt32(field_offset_for_b + first_field_in_lane + 2*i));
167        }
168    }
169    Value * pack = CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
170    return pack;
171}
172
173Value * IDISA_AVX2_Builder::hsimd_packh_in_lanes(unsigned lanes, unsigned fw, Value * a, Value * b) {
174    if ((fw == 16)  && (lanes == 2)) {
175        Value * vpackuswbfunc = Intrinsic::getDeclaration(mMod, Intrinsic::x86_avx2_packuswb);
176        Value * a_low = simd_srli(fw, a, fw/2);
177        Value * b_low = simd_srli(fw, b, fw/2);
178        Value * pack = CreateCall2(vpackuswbfunc, a_low, b_low);
179        return pack;
180    }
181    unsigned fw_out = fw/2;
182    unsigned fields_per_lane = mBitBlockWidth/(fw_out * lanes);
183    unsigned field_offset_for_b = mBitBlockWidth/fw_out;
184    Value * aVec = fwCast(fw_out, a);
185    Value * bVec = fwCast(fw_out, b);
186    std::vector<Constant*> Idxs;
187    for (unsigned lane = 0; lane < lanes; lane++) {
188        unsigned first_field_in_lane = lane * fields_per_lane; // every second field
189        for (unsigned i = 0; i < fields_per_lane/2; i++) {
190            Idxs.push_back(getInt32(first_field_in_lane + 2*i));
191        }
192        for (unsigned i = 0; i < fields_per_lane/2; i++) {
193            Idxs.push_back(getInt32(field_offset_for_b + first_field_in_lane + 2*i));
194        }
195    }
196    Value * pack = CreateShuffleVector(aVec, bVec, ConstantVector::get(Idxs));
197    return pack;
198}
199   
200}
Note: See TracBrowser for help on using the repository browser.