source: icGREP/icgrep-devel/icgrep/IR_Gen/idisa_sse_builder.cpp @ 6053

Last change on this file since 6053 was 6050, checked in by cameron, 16 months ago

IDISA testing

File size: 8.8 KB
Line 
1/*
2 *  Copyright (c) 2016 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_sse_builder.h"
8
9using namespace llvm;
10
11namespace IDISA {
12
13std::string IDISA_SSE_Builder::getBuilderUniqueName() { return mBitBlockWidth != 128 ? "SSE_" + std::to_string(mBitBlockWidth) : "SSE";}
14std::string IDISA_SSE2_Builder::getBuilderUniqueName() { return mBitBlockWidth != 128 ? "SSE2_" + std::to_string(mBitBlockWidth) : "SSE2";}
15
16Value * IDISA_SSE2_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {   
17    if ((fw == 16) && (mBitBlockWidth == 128)) {
18        Value * packuswb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_packuswb_128);
19        return CreateCall(packuswb_func, {simd_srli(16, a, 8), simd_srli(16, b, 8)});
20    }
21    // Otherwise use default logic.
22    return IDISA_Builder::hsimd_packh(fw, a, b);
23}
24
25Value * IDISA_SSE2_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
26    if ((fw == 16) && (mBitBlockWidth == 128)) {
27        Value * packuswb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_packuswb_128);
28        Value * mask = simd_lomask(16);
29        return CreateCall(packuswb_func, {fwCast(16, simd_and(a, mask)), fwCast(16, simd_and(b, mask))});
30    }
31    // Otherwise use default logic.
32    return IDISA_Builder::hsimd_packl(fw, a, b);
33}
34
35Value * IDISA_SSE2_Builder::hsimd_signmask(unsigned fw, Value * a) {
36    // SSE2 special case using Intrinsic::x86_sse2_movmsk_pd (fw=32 only)
37    if (mBitBlockWidth == 128) {
38        if (fw == 64) {
39            Value * signmask_f64func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_movmsk_pd);
40            Type * bitBlock_f64type = VectorType::get(getDoubleTy(), mBitBlockWidth/64);
41            Value * a_as_pd = CreateBitCast(a, bitBlock_f64type);
42            return CreateCall(signmask_f64func, a_as_pd);
43        }
44        if (fw == 8) {
45            Value * pmovmskb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_pmovmskb_128);
46            return CreateCall(pmovmskb_func, fwCast(8, a));
47        }
48    }
49    const auto fieldCount = mBitBlockWidth / fw;
50    if ((fieldCount > 4) && (fieldCount <= 16)) {
51        Value * pmovmskb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_pmovmskb_128);
52        int fieldBytes = fw / 8;
53        int hiByte = fieldBytes - 1;
54        Constant * Idxs[16];
55        for (unsigned i = 0; i < fieldCount; i++) {
56            Idxs[i] = getInt32(fieldBytes * i + hiByte);
57        }
58        for (unsigned i = fieldCount; i < 16; i++) {
59            Idxs[i] = getInt32(mBitBlockWidth / 8);
60        }
61        Value * packh = CreateShuffleVector(fwCast(8, a), fwCast(8, allZeroes()), ConstantVector::get({Idxs, 16}));
62        return CreateCall(pmovmskb_func, packh);
63    }
64    // Otherwise use default SSE logic.
65    return IDISA_SSE_Builder::hsimd_signmask(fw, a);
66}
67
68Value * IDISA_SSE_Builder::hsimd_signmask(const unsigned fw, Value * a) {
69    // SSE special cases using Intrinsic::x86_sse_movmsk_ps (fw=32 only)
70    if (fw == 32) {
71        Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse_movmsk_ps);
72        Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
73        Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
74        if (mBitBlockWidth == 128) {
75            return CreateCall(signmask_f32func, a_as_ps);
76        }
77    } else if ((fw == 64) && (mBitBlockWidth == 256)) {
78        Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
79        Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
80        Constant * Idxs[4];
81        for (unsigned i = 0; i < 4; i++) {
82            Idxs[i] = getInt32(2 * i + 1);
83        }
84        Value * packh = CreateShuffleVector(a_as_ps, UndefValue::get(bitBlock_f32type), ConstantVector::get({Idxs, 4}));
85        Type * halfBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/64);
86        Value * pack_as_ps = CreateBitCast(packh, halfBlock_f32type);
87        Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse_movmsk_ps);
88        Value * mask = CreateCall(signmask_f32func, pack_as_ps);
89        return mask;
90    }
91    // Otherwise use default logic.
92    return IDISA_Builder::hsimd_signmask(fw, a);
93}
94
95#define SHIFT_FIELDWIDTH 64
96//#define LEAVE_CARRY_UNNORMALIZED
97
98// full shift producing {shiftout, shifted}
99std::pair<Value *, Value *> IDISA_SSE2_Builder::bitblock_advance(Value * a, Value * shiftin, unsigned shift) {
100    Value * shifted = nullptr;
101    Value * shiftout = nullptr;
102    Type * shiftTy = shiftin->getType();
103    if (LLVM_UNLIKELY(shift == 0)) {
104        return std::pair<Value *, Value *>(Constant::getNullValue(shiftTy), a);
105    }
106    Value * si = shiftin;
107    if (shiftTy != mBitBlockType) {
108        si = bitCast(CreateZExt(shiftin, getIntNTy(mBitBlockWidth)));
109    }
110    if (LLVM_UNLIKELY(shift == mBitBlockWidth)) {
111        return std::pair<Value *, Value *>(CreateBitCast(a, shiftTy), si);
112    }
113#ifndef LEAVE_CARRY_UNNORMALIZED
114    if (LLVM_UNLIKELY((shift % 8) == 0)) { // Use a single whole-byte shift, if possible.
115        shifted = simd_or(mvmd_slli(8, a, shift / 8), si);
116        shiftout = mvmd_srli(8, a, (mBitBlockWidth - shift) / 8);
117        return std::pair<Value *, Value *>(shiftout, shifted);
118    }
119    Value * shiftback = simd_srli(SHIFT_FIELDWIDTH, a, SHIFT_FIELDWIDTH - (shift % SHIFT_FIELDWIDTH));
120    Value * shiftfwd = simd_slli(SHIFT_FIELDWIDTH, a, shift % SHIFT_FIELDWIDTH);
121    if (LLVM_LIKELY(shift < SHIFT_FIELDWIDTH)) {
122        shiftout = mvmd_srli(SHIFT_FIELDWIDTH, shiftback, mBitBlockWidth/SHIFT_FIELDWIDTH - 1);
123        shifted = simd_or(simd_or(shiftfwd, si), mvmd_slli(SHIFT_FIELDWIDTH, shiftback, 1));
124    }
125    else {
126        shiftout = simd_or(shiftback, mvmd_srli(SHIFT_FIELDWIDTH, shiftfwd, 1));
127        shifted = simd_or(si, mvmd_slli(SHIFT_FIELDWIDTH, shiftfwd, (mBitBlockWidth - shift) / SHIFT_FIELDWIDTH));
128        if (shift < mBitBlockWidth - SHIFT_FIELDWIDTH) {
129            shiftout = mvmd_srli(SHIFT_FIELDWIDTH, shiftout, (mBitBlockWidth - shift) / SHIFT_FIELDWIDTH);
130            shifted = simd_or(shifted, mvmd_slli(SHIFT_FIELDWIDTH, shiftback, shift/SHIFT_FIELDWIDTH + 1));
131        }
132    }
133#endif
134#ifdef LEAVE_CARRY_UNNORMALIZED
135    shiftout = a;
136    if (LLVM_UNLIKELY((shift % 8) == 0)) { // Use a single whole-byte shift, if possible.
137        shifted = mvmd_dslli(8, a, shiftin, (mBitBlockWidth - shift) / 8);
138    }
139    else if (LLVM_LIKELY(shift < SHIFT_FIELDWIDTH)) {
140        Value * ahead = mvmd_dslli(SHIFT_FIELDWIDTH, a, shiftin, mBitBlockWidth / SHIFT_FIELDWIDTH - 1);
141        shifted = simd_or(simd_srli(SHIFT_FIELDWIDTH, ahead, SHIFT_FIELDWIDTH - shift), simd_slli(SHIFT_FIELDWIDTH, a, shift));
142    }
143    else {
144        throw std::runtime_error("Unsupported shift.");
145    }
146#endif
147    if (shiftTy != mBitBlockType) {
148        shiftout = CreateBitCast(shiftout, shiftTy);
149    }
150    //CallPrintRegister("shifted", shifted);
151    //CallPrintRegister("shiftout", shiftout);
152    return std::pair<Value *, Value *>(shiftout, shifted);
153}
154   
155Value * IDISA_SSE2_Builder::mvmd_shuffle(unsigned fw, Value * a, Value * shuffle_table) {
156    if ((mBitBlockWidth == 128) && (fw == 64)) {
157        // First create a vector with exchanged values of the 2 fields.
158        Constant * idx[2] = {ConstantInt::get(getInt32Ty(), 1), ConstantInt::get(getInt32Ty(), 0)};
159        Value * exchanged = CreateShuffleVector(a, UndefValue::get(fwVectorType(fw)), ConstantVector::get({idx, 2}));
160        // bits that change if we the value in a needs to be exchanged.
161        Value * changed = simd_xor(a, exchanged);
162        // Now create a mask to select between original and exchanged values.
163        Constant * xchg[2] = {ConstantInt::get(getInt64Ty(), 1), ConstantInt::get(getInt64Ty(), 0)};
164        Value * exchange_mask = simd_eq(fw, shuffle_table, ConstantVector::get({xchg, 2}));
165        Value * rslt = simd_xor(simd_and(changed, exchange_mask), a);
166        return rslt;
167    }
168    return IDISA_Builder::mvmd_shuffle(fw, a, shuffle_table);
169}
170
171Value * IDISA_SSE_Builder::mvmd_compress(unsigned fw, Value * a, Value * selector) {
172    if ((mBitBlockWidth == 128) && (fw == 64)) {
173        Constant * keep[2] = {ConstantInt::get(getInt64Ty(), 1), ConstantInt::get(getInt64Ty(), 3)};
174        Constant * keep_mask = ConstantVector::get({keep, 2});
175        Constant * shift[2] = {ConstantInt::get(getInt64Ty(), 2), ConstantInt::get(getInt64Ty(), 0)};
176        Constant * shifted_mask = ConstantVector::get({shift, 2});
177        Value * a_srli1 = mvmd_srli(64, a, 1);
178        Value * bdcst = simd_fill(64, CreateZExt(selector, getInt64Ty()));
179        Value * kept = simd_and(simd_eq(64, simd_and(keep_mask, bdcst), keep_mask), a);
180        Value * shifted = simd_and(a_srli1, simd_eq(64, shifted_mask, bdcst));
181        return simd_or(kept, shifted);
182    }
183    return IDISA_Builder::mvmd_compress(fw, a, selector);
184}
185
186
187}
Note: See TracBrowser for help on using the repository browser.