source: icGREP/icgrep-devel/icgrep/IDISA/idisa_sse_builder.cpp @ 5117

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

bitblock_advance

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