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