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

Last change on this file since 5440 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.0 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
9namespace IDISA {
10
11std::string IDISA_SSE_Builder::getBuilderUniqueName() { return mBitBlockWidth != 128 ? "SSE_" + std::to_string(mBitBlockWidth) : "SSE";}
12std::string IDISA_SSE2_Builder::getBuilderUniqueName() { return mBitBlockWidth != 128 ? "SSE2_" + std::to_string(mBitBlockWidth) : "SSE2";}
13
14Value * IDISA_SSE2_Builder::hsimd_packh(unsigned fw, Value * a, Value * b) {   
15    if ((fw == 16) && (mBitBlockWidth == 128)) {
16        Value * packuswb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_packuswb_128);
17        return CreateCall(packuswb_func, {simd_srli(16, a, 8), simd_srli(16, b, 8)});
18    }
19    // Otherwise use default logic.
20    return IDISA_Builder::hsimd_packh(fw, a, b);
21}
22
23Value * IDISA_SSE2_Builder::hsimd_packl(unsigned fw, Value * a, Value * b) {
24    if ((fw == 16) && (mBitBlockWidth == 128)) {
25        Value * packuswb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_packuswb_128);
26        Value * mask = simd_lomask(16);
27        return CreateCall(packuswb_func, {fwCast(16, simd_and(a, mask)), fwCast(16, simd_and(b, mask))});
28    }
29    // Otherwise use default logic.
30    return IDISA_Builder::hsimd_packl(fw, a, b);
31}
32
33Value * IDISA_SSE2_Builder::hsimd_signmask(unsigned fw, Value * a) {
34    // SSE2 special case using Intrinsic::x86_sse2_movmsk_pd (fw=32 only)
35    if (mBitBlockWidth == 128) {
36        if (fw == 64) {
37            Value * signmask_f64func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_movmsk_pd);
38            Type * bitBlock_f64type = VectorType::get(getDoubleTy(), mBitBlockWidth/64);
39            Value * a_as_pd = CreateBitCast(a, bitBlock_f64type);
40            return CreateCall(signmask_f64func, a_as_pd);
41        }
42        if (fw == 8) {
43            Value * pmovmskb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_pmovmskb_128);
44            return CreateCall(pmovmskb_func, fwCast(8, a));
45        }
46    }
47    const auto fieldCount = mBitBlockWidth / fw;
48    if ((fieldCount > 4) && (fieldCount <= 16)) {
49        Value * pmovmskb_func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse2_pmovmskb_128);
50        int fieldBytes = fw / 8;
51        int hiByte = fieldBytes - 1;
52        Constant * Idxs[16];
53        for (unsigned i = 0; i < fieldCount; i++) {
54            Idxs[i] = getInt32(fieldBytes * i + hiByte);
55        }
56        for (unsigned i = fieldCount; i < 16; i++) {
57            Idxs[i] = getInt32(mBitBlockWidth / 8);
58        }
59        Value * packh = CreateShuffleVector(fwCast(8, a), fwCast(8, allZeroes()), ConstantVector::get({Idxs, 16}));
60        return CreateCall(pmovmskb_func, packh);
61    }
62    // Otherwise use default SSE logic.
63    return IDISA_SSE_Builder::hsimd_signmask(fw, a);
64}
65
66Value * IDISA_SSE_Builder::hsimd_signmask(unsigned fw, Value * a) {
67    // SSE special cases using Intrinsic::x86_sse_movmsk_ps (fw=32 only)
68    if (fw == 32) {
69        Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse_movmsk_ps);
70        Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
71        Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
72        if (mBitBlockWidth == 128) {
73            return CreateCall(signmask_f32func, a_as_ps);
74        }
75    } else if ((fw == 64) && (mBitBlockWidth == 256)) {
76        Type * bitBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/32);
77        Value * a_as_ps = CreateBitCast(a, bitBlock_f32type);
78        Constant * Idxs[4];
79        for (unsigned i = 0; i < 4; i++) {
80            Idxs[i] = getInt32(2 * i + 1);
81        }
82        Value * packh = CreateShuffleVector(a_as_ps, UndefValue::get(bitBlock_f32type), ConstantVector::get({Idxs, 4}));
83        Type * halfBlock_f32type = VectorType::get(getFloatTy(), mBitBlockWidth/64);
84        Value * pack_as_ps = CreateBitCast(packh, halfBlock_f32type);
85        Value * signmask_f32func = Intrinsic::getDeclaration(getModule(), Intrinsic::x86_sse_movmsk_ps);
86        Value * mask = CreateCall(signmask_f32func, pack_as_ps);
87        return mask;
88    }
89    // Otherwise use default logic.
90    return IDISA_Builder::hsimd_signmask(fw, a);
91}
92
93#define SHIFT_FIELDWIDTH 64
94//#define LEAVE_CARRY_UNNORMALIZED
95
96// full shift producing {shiftout, shifted}
97std::pair<Value *, Value *> IDISA_SSE2_Builder::bitblock_advance(Value * a, Value * shiftin, unsigned shift) {
98    Value * shifted = nullptr;
99    Value * shiftout = nullptr;
100    Type * shiftTy = shiftin->getType();
101    if (LLVM_UNLIKELY(shift == 0)) {
102        return std::pair<Value *, Value *>(Constant::getNullValue(shiftTy), a);
103    }
104    Value * si = shiftin;
105    if (shiftTy != mBitBlockType) {
106        si = bitCast(CreateZExt(shiftin, getIntNTy(mBitBlockWidth)));
107    }
108    if (LLVM_UNLIKELY(shift == mBitBlockWidth)) {
109        return std::pair<Value *, Value *>(CreateBitCast(a, shiftTy), si);
110    }
111#ifndef LEAVE_CARRY_UNNORMALIZED
112    if (LLVM_UNLIKELY((shift % 8) == 0)) { // Use a single whole-byte shift, if possible.
113        shifted = simd_or(mvmd_slli(8, a, shift / 8), si);
114        shiftout = mvmd_srli(8, a, (mBitBlockWidth - shift) / 8);
115        return std::pair<Value *, Value *>(shiftout, shifted);
116    }
117    Value * shiftback = simd_srli(SHIFT_FIELDWIDTH, a, SHIFT_FIELDWIDTH - (shift % SHIFT_FIELDWIDTH));
118    Value * shiftfwd = simd_slli(SHIFT_FIELDWIDTH, a, shift % SHIFT_FIELDWIDTH);
119    if (LLVM_LIKELY(shift < SHIFT_FIELDWIDTH)) {
120        shiftout = mvmd_srli(SHIFT_FIELDWIDTH, shiftback, mBitBlockWidth/SHIFT_FIELDWIDTH - 1);
121        shifted = simd_or(simd_or(shiftfwd, si), mvmd_slli(SHIFT_FIELDWIDTH, shiftback, 1));
122    }
123    else {
124        shiftout = simd_or(shiftback, mvmd_srli(SHIFT_FIELDWIDTH, shiftfwd, 1));
125        shifted = simd_or(si, mvmd_slli(SHIFT_FIELDWIDTH, shiftfwd, (mBitBlockWidth - shift) / SHIFT_FIELDWIDTH));
126        if (shift < mBitBlockWidth - SHIFT_FIELDWIDTH) {
127            shiftout = mvmd_srli(SHIFT_FIELDWIDTH, shiftout, (mBitBlockWidth - shift) / SHIFT_FIELDWIDTH);
128            shifted = simd_or(shifted, mvmd_slli(SHIFT_FIELDWIDTH, shiftback, shift/SHIFT_FIELDWIDTH + 1));
129        }
130    }
131#endif
132#ifdef LEAVE_CARRY_UNNORMALIZED
133    shiftout = a;
134    if (LLVM_UNLIKELY((shift % 8) == 0)) { // Use a single whole-byte shift, if possible.
135        shifted = mvmd_dslli(8, a, shiftin, (mBitBlockWidth - shift) / 8);
136    }
137    else if (LLVM_LIKELY(shift < SHIFT_FIELDWIDTH)) {
138        Value * ahead = mvmd_dslli(SHIFT_FIELDWIDTH, a, shiftin, mBitBlockWidth / SHIFT_FIELDWIDTH - 1);
139        shifted = simd_or(simd_srli(SHIFT_FIELDWIDTH, ahead, SHIFT_FIELDWIDTH - shift), simd_slli(SHIFT_FIELDWIDTH, a, shift));
140    }
141    else {
142        throw std::runtime_error("Unsupported shift.");
143    }
144#endif
145    if (shiftTy != mBitBlockType) {
146        shiftout = CreateBitCast(shiftout, shiftTy);
147    }
148    //CallPrintRegister("shifted", shifted);
149    //CallPrintRegister("shiftout", shiftout);
150    return std::pair<Value *, Value *>(shiftout, shifted);
151}
152
153}
Note: See TracBrowser for help on using the repository browser.