source: icGREP/icgrep-devel/icgrep/kernels/p2s_kernel.cpp @ 6089

Last change on this file since 6089 was 6089, checked in by cameron, 10 months ago

Little-endian/big-endian bit number options, default to little-endian

File size: 10.1 KB
Line 
1#include "p2s_kernel.h"
2#include <kernels/streamset.h>
3#include <kernels/kernel_builder.h>
4#include <toolchain/toolchain.h>
5#include <llvm/Support/Compiler.h>
6
7namespace llvm { class Value; }
8
9using namespace llvm;
10using namespace parabix;
11
12namespace kernel{
13       
14void p2s_step(const std::unique_ptr<KernelBuilder> & iBuilder, Value * p0, Value * p1, Value * hi_mask, unsigned shift, Value * &s1, Value * &s0) {
15    Value * t0 = iBuilder->simd_if(1, hi_mask, p0, iBuilder->simd_srli(16, p1, shift));
16    Value * t1 = iBuilder->simd_if(1, hi_mask, iBuilder->simd_slli(16, p0, shift), p1);
17    s1 = iBuilder->esimd_mergeh(8, t1, t0);
18    s0 = iBuilder->esimd_mergel(8, t1, t0);
19}
20#define LITTLE_ENDIAN_BIT_NUMBERING
21
22inline void p2s(const std::unique_ptr<KernelBuilder> & iBuilder, Value * p[], Value * s[], cc::BitNumbering basisNumbering = cc::BitNumbering::LittleEndian) {
23    Value * bit00004444[2];
24    Value * bit22226666[2];
25    Value * bit11115555[2];
26    Value * bit33337777[2];
27    if (basisNumbering == cc::BitNumbering::BigEndian) {
28        p2s_step(iBuilder, p[0], p[4], iBuilder->simd_himask(8), 4, bit00004444[1], bit00004444[0]);
29        p2s_step(iBuilder, p[1], p[5], iBuilder->simd_himask(8), 4, bit11115555[1], bit11115555[0]);
30        p2s_step(iBuilder, p[2], p[6], iBuilder->simd_himask(8), 4, bit22226666[1], bit22226666[0]);
31        p2s_step(iBuilder, p[3], p[7], iBuilder->simd_himask(8), 4, bit33337777[1], bit33337777[0]);
32    }  else {
33        p2s_step(iBuilder, p[7], p[3], iBuilder->simd_himask(8), 4, bit00004444[1], bit00004444[0]);
34        p2s_step(iBuilder, p[6], p[2], iBuilder->simd_himask(8), 4, bit11115555[1], bit11115555[0]);
35        p2s_step(iBuilder, p[5], p[1], iBuilder->simd_himask(8), 4, bit22226666[1], bit22226666[0]);
36        p2s_step(iBuilder, p[4], p[0], iBuilder->simd_himask(8), 4, bit33337777[1], bit33337777[0]);
37    }
38    Value * bit00224466[4];
39    Value * bit11335577[4];
40    for (unsigned j = 0; j<2; j++) {
41        p2s_step(iBuilder, bit00004444[j], bit22226666[j],iBuilder->simd_himask(4), 2, bit00224466[2*j+1], bit00224466[2*j]);
42        p2s_step(iBuilder, bit11115555[j], bit33337777[j],iBuilder->simd_himask(4), 2, bit11335577[2*j+1], bit11335577[2*j]);
43    }
44    for (unsigned j = 0; j<4; j++) {
45        p2s_step(iBuilder, bit00224466[j], bit11335577[j], iBuilder->simd_himask(2), 1, s[2*j+1], s[2*j]);
46    }
47}
48               
49void P2SKernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & b) {
50    Value * p_bitblock[8];
51    for (unsigned i = 0; i < 8; i++) {
52        p_bitblock[i] = b->loadInputStreamBlock("basisBits", b->getInt32(i));
53    }
54    Value * s_bytepack[8];
55    p2s(b, p_bitblock, s_bytepack, mBasisSetNumbering);
56    for (unsigned j = 0; j < 8; ++j) {
57        b->storeOutputStreamPack("byteStream", b->getInt32(0), b->getInt32(j), s_bytepack[j]);
58    }
59}
60
61inline Value * partial_sum_popcounts(const std::unique_ptr<KernelBuilder> & iBuilder, const unsigned fw, Value * popcounts) {
62    Value * summed_counts = popcounts;
63    const auto count = iBuilder->getBitBlockWidth() / fw;
64    for (unsigned move = 1; move < count; move *= 2) {
65        summed_counts = iBuilder->simd_add(fw, summed_counts, iBuilder->mvmd_slli(fw, summed_counts, move));
66    }
67    return summed_counts;
68}
69
70void P2SKernelWithCompressedOutput::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & b) {
71    IntegerType * i32 = b->getInt32Ty();
72    PointerType * bitBlockPtrTy = PointerType::get(b->getBitBlockType(), 0);
73    unsigned const unitsPerRegister = b->getBitBlockWidth()/8;
74
75    Value * basisBits[8];
76    for (unsigned i = 0; i < 8; i++) {
77        basisBits[i] = b->loadInputStreamBlock("basisBits", b->getInt32(i));
78    }
79    Value * bytePack[8];
80    p2s(b, basisBits, bytePack, mBasisSetNumbering);
81
82    Value * const fieldCounts = b->loadInputStreamBlock("fieldCounts", b->getInt32(0));
83    Value * unitCounts = partial_sum_popcounts(b, unitsPerRegister, fieldCounts);
84
85    Value * output_ptr = b->getOutputStreamBlockPtr("byteStream", b->getInt32(0));
86    output_ptr = b->CreatePointerCast(output_ptr, b->getInt8PtrTy());
87    Value * offset = b->getInt32(0);
88    for (unsigned j = 0; j < 8; ++j) {
89        b->CreateStore(bytePack[j], b->CreateBitCast(b->CreateGEP(output_ptr, offset), bitBlockPtrTy));
90        offset = b->CreateZExt(b->CreateExtractElement(unitCounts, b->getInt32(j)), i32);
91    }
92
93    Value * unitsGenerated = b->getProducedItemCount("byteStream"); // units generated to buffer
94    unitsGenerated = b->CreateAdd(unitsGenerated, b->CreateZExt(offset, b->getSizeTy()));
95    b->setProducedItemCount("byteStream", unitsGenerated);
96}
97
98void P2S16Kernel::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & b) {
99    Value * hi_input[8];
100    for (unsigned j = 0; j < 8; ++j) {
101        const unsigned idx = mBasisSetNumbering == cc::BitNumbering::LittleEndian ? j + 8 : j;
102        hi_input[j] = b->loadInputStreamBlock("basisBits", b->getInt32(idx));
103    }
104    Value * hi_bytes[8];
105    p2s(b, hi_input, hi_bytes, mBasisSetNumbering);
106    Value * lo_input[8];
107    for (unsigned j = 0; j < 8; ++j) {
108        const unsigned idx = mBasisSetNumbering == cc::BitNumbering::LittleEndian ? j : j + 8;
109        lo_input[j] = b->loadInputStreamBlock("basisBits", b->getInt32(idx));
110    }
111    Value * lo_bytes[8];
112    p2s(b, lo_input, lo_bytes, mBasisSetNumbering);
113    for (unsigned j = 0; j < 8; ++j) {
114        Value * merge0 = b->bitCast(b->esimd_mergel(8, hi_bytes[j], lo_bytes[j]));
115        Value * merge1 = b->bitCast(b->esimd_mergeh(8, hi_bytes[j], lo_bytes[j]));
116        b->storeOutputStreamPack("i16Stream", b->getInt32(0), b->getInt32(2 * j), merge0);
117        b->storeOutputStreamPack("i16Stream", b->getInt32(0), b->getInt32(2 * j + 1), merge1);
118    }
119}
120   
121void P2S16KernelWithCompressedOutput::generateDoBlockMethod(const std::unique_ptr<KernelBuilder> & b) {
122    IntegerType * i32Ty = b->getInt32Ty();
123    PointerType * int16PtrTy = b->getInt16Ty()->getPointerTo();
124    PointerType * bitBlockPtrTy = b->getBitBlockType()->getPointerTo();
125    ConstantInt * blockMask = b->getSize(b->getBitBlockWidth() - 1);
126    unsigned const unitsPerRegister = b->getBitBlockWidth()/16;
127   
128    Value * hi_input[8];
129    for (unsigned j = 0; j < 8; ++j) {
130        const unsigned idx = mBasisSetNumbering == cc::BitNumbering::LittleEndian ? j + 8 : j;
131        hi_input[j] = b->loadInputStreamBlock("basisBits", b->getInt32(idx));
132    }
133    Value * hi_bytes[8];
134    p2s(b, hi_input, hi_bytes, mBasisSetNumbering);
135
136    Value * lo_input[8];
137    for (unsigned j = 0; j < 8; ++j) {
138        const unsigned idx = mBasisSetNumbering == cc::BitNumbering::LittleEndian ? j : j + 8;
139        lo_input[j] = b->loadInputStreamBlock("basisBits", b->getInt32(idx));
140    }
141    Value * lo_bytes[8];
142    p2s(b, lo_input, lo_bytes, mBasisSetNumbering);
143
144    Value * const fieldCounts = b->loadInputStreamBlock("fieldCounts", b->getInt32(0));
145    Value * unitCounts = partial_sum_popcounts(b, unitsPerRegister, fieldCounts);
146   
147    Value * outputPtr = b->getOutputStreamBlockPtr("i16Stream", b->getInt32(0));
148    outputPtr = b->CreatePointerCast(outputPtr, int16PtrTy);
149    Value * const i16UnitsGenerated = b->getProducedItemCount("i16Stream"); // units generated to buffer
150    outputPtr = b->CreateGEP(outputPtr, b->CreateAnd(i16UnitsGenerated, blockMask));
151
152    Value * offset = b->getInt32(0);
153
154    for (unsigned j = 0; j < 8; ++j) {
155        Value * const merge0 = b->bitCast(b->esimd_mergel(8, hi_bytes[j], lo_bytes[j]));
156        b->CreateAlignedStore(merge0, b->CreateBitCast(b->CreateGEP(outputPtr, offset), bitBlockPtrTy), 1);
157        Value * const nextOffset1 = b->CreateZExt(b->CreateExtractElement(unitCounts, b->getInt32(2 * j)), i32Ty);
158        if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
159            b->CreateAssert(b->CreateICmpULE(offset, nextOffset1), "deletion offset is not monotonically non-decreasing");
160        }
161        Value * const merge1 = b->bitCast(b->esimd_mergeh(8, hi_bytes[j], lo_bytes[j]));
162        b->CreateAlignedStore(merge1, b->CreateBitCast(b->CreateGEP(outputPtr, nextOffset1), bitBlockPtrTy), 1);
163        Value * const nextOffset2 = b->CreateZExt(b->CreateExtractElement(unitCounts, b->getInt32(2 * j + 1)), i32Ty);
164        if (LLVM_UNLIKELY(codegen::DebugOptionIsSet(codegen::EnableAsserts))) {
165            b->CreateAssert(b->CreateICmpULE(nextOffset1, nextOffset2), "deletion offset is not monotonically non-decreasing");
166        }
167        offset = nextOffset2;
168    }
169
170    Value * const i16UnitsFinal = b->CreateAdd(i16UnitsGenerated, b->CreateZExt(offset, b->getSizeTy()));
171    b->setProducedItemCount("i16Stream", i16UnitsFinal);
172}
173
174P2SKernel::P2SKernel(const std::unique_ptr<kernel::KernelBuilder> & b, cc::BitNumbering numbering)
175    : BlockOrientedKernel("p2s" + cc::numberingSuffix(numbering),
176              {Binding{b->getStreamSetTy(8, 1), "basisBits"}},
177              {Binding{b->getStreamSetTy(1, 8), "byteStream"}},
178              {}, {}, {}),
179    mBasisSetNumbering(numbering) {
180}
181
182P2SKernelWithCompressedOutput::P2SKernelWithCompressedOutput(const std::unique_ptr<kernel::KernelBuilder> & b, cc::BitNumbering numbering)
183: BlockOrientedKernel("p2s_compress" + cc::numberingSuffix(numbering),
184              {Binding{b->getStreamSetTy(8, 1), "basisBits"}, Binding{b->getStreamSetTy(1, 1), "fieldCounts"}},
185              {Binding{b->getStreamSetTy(1, 8), "byteStream", BoundedRate(0, 1)}},
186                      {}, {}, {}),
187    mBasisSetNumbering(numbering) {
188}
189
190P2S16Kernel::P2S16Kernel(const std::unique_ptr<kernel::KernelBuilder> & b, cc::BitNumbering numbering)
191: BlockOrientedKernel("p2s_16" + cc::numberingSuffix(numbering),
192              {Binding{b->getStreamSetTy(16, 1), "basisBits"}},
193              {Binding{b->getStreamSetTy(1, 16), "i16Stream"}},
194                      {}, {}, {}),
195    mBasisSetNumbering(numbering) {
196}
197
198
199P2S16KernelWithCompressedOutput::P2S16KernelWithCompressedOutput(const std::unique_ptr<kernel::KernelBuilder> & b, cc::BitNumbering numbering)
200: BlockOrientedKernel("p2s_16_compress" + cc::numberingSuffix(numbering),
201              {Binding{b->getStreamSetTy(16, 1), "basisBits"}, Binding{b->getStreamSetTy(1, 1), "fieldCounts"}},
202              {Binding{b->getStreamSetTy(1, 16), "i16Stream", BoundedRate(0, 1)}},
203              {},
204              {},
205              {}),
206    mBasisSetNumbering(numbering) {
207}
208   
209   
210}
Note: See TracBrowser for help on using the repository browser.