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

Last change on this file since 5795 was 5464, checked in by nmedfort, 22 months ago

Restructuring work for the Driver classes. Start of work to eliminate the memory leaks with the ExecutionEngine?. Replaced custom AlignedMalloc? with backend call to std::aligned_malloc. Salvaged some work on DistributionPass? for reevaluation.

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
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(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
155}
Note: See TracBrowser for help on using the repository browser.