source: icGREP/icgrep-devel/icgrep/kernels/lzparabix/LZParabixAioKernel.cpp @ 6118

Last change on this file since 6118 was 6118, checked in by xwa163, 10 months ago

Implement bitstream decompression version of LZ4 Aio Kernel

File size: 24.9 KB
Line 
1//
2// Created by wxy325 on 2018/6/18.
3//
4
5#include "LZParabixAioKernel.h"
6
7#include <kernels/kernel_builder.h>
8#include <iostream>
9#include <string>
10#include <llvm/Support/raw_ostream.h>
11#include <kernels/streamset.h>
12#include <cstdint>
13
14
15using namespace llvm;
16using namespace kernel;
17using namespace std;
18
19
20namespace kernel{
21    LZParabixAioKernel::LZParabixAioKernel(const std::unique_ptr<kernel::KernelBuilder> &b, std::vector<unsigned> numsOfBitStreams)
22            :SegmentOrientedKernel("LZParabixAioKernel",
23            // Inputs
24                                   {
25                    Binding{b->getStreamSetTy(1, 8), "byteStream", BoundedRate(0, 1)},
26
27                    // block data
28                    Binding{b->getStreamSetTy(1, 64), "blockStart", BoundedRate(0, 1), AlwaysConsume()},
29                    Binding{b->getStreamSetTy(1, 64), "blockEnd", RateEqualTo("blockStart"), AlwaysConsume()}
30
31
32            },
33            //Outputs
34                                   {
35
36                                   },
37            //Arguments
38                                   {
39                                           Binding{b->getSizeTy(), "fileSize"}
40                                   },
41                                   {},
42            //Internal states:
43                                   {
44                                           Binding{b->getSizeTy(), "blockDataIndex"},
45                                           Binding{b->getInt64Ty(), "outputPos"},
46
47
48                                   }), mNumsOfBitStreams(numsOfBitStreams) {
49        this->setStride(4 * 1024 * 1024);
50        addAttribute(MustExplicitlyTerminate());
51
52        mStreamSetInputs.push_back(Binding{b->getStreamSetTy(numsOfBitStreams[0], 1), "inputBitStream0", RateEqualTo("byteStream")});
53        mStreamSetOutputs.push_back(Binding{b->getStreamSetTy(numsOfBitStreams[0], 1), "outputStream0", BoundedRate(0, 1)});
54
55        for (unsigned i = 1; i < numsOfBitStreams.size(); i++) {
56            mStreamSetInputs.push_back(Binding{b->getStreamSetTy(numsOfBitStreams[i], 1), "inputBitStream" + std::to_string(i), RateEqualTo("byteStream")});
57            mStreamSetOutputs.push_back(Binding{b->getStreamSetTy(numsOfBitStreams[i], 1), "outputStream" + std::to_string(i), RateEqualTo("outputStream0")});
58        }
59
60        this->initPendingOutputScalar(b);
61
62    }
63
64
65    void LZParabixAioKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> &b) {
66        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
67        BasicBlock* blockEndConBlock = b->CreateBasicBlock("blockEndConBlock");
68
69        Value * blockDataIndex = b->getScalarField("blockDataIndex");
70        Value * totalNumber = b->getAvailableItemCount("blockEnd");
71
72        Value * blockEnd = this->generateLoadInt64NumberInput(b, "blockEnd", blockDataIndex);
73
74        b->CreateCondBr(b->CreateICmpULT(blockDataIndex, totalNumber), blockEndConBlock, exitBlock);
75
76        b->SetInsertPoint(blockEndConBlock);
77        Value * blockStart = this->generateLoadInt64NumberInput(b, "blockStart", blockDataIndex);
78        BasicBlock * processBlock = b->CreateBasicBlock("processBlock");
79//        b->CreateCondBr(b->CreateICmpULE(blockEnd, totalExtender), processBlock, exitBlock);
80        b->CreateBr(processBlock);
81
82        b->SetInsertPoint(processBlock);
83
84        this->generateProcessCompressedBlock(b, blockStart, blockEnd);
85
86
87        Value * newBlockDataIndex = b->CreateAdd(blockDataIndex, b->getInt64(1));
88        b->setScalarField("blockDataIndex", newBlockDataIndex);
89        b->setProcessedItemCount("blockStart", newBlockDataIndex);
90        b->setProcessedItemCount("byteStream", blockEnd);
91        b->setProducedItemCount("outputStream0", b->getScalarField("outputPos"));
92        b->CreateBr(exitBlock);
93
94        b->SetInsertPoint(exitBlock);
95    }
96
97
98    llvm::Value *LZParabixAioKernel::generateLoadInt64NumberInput(const std::unique_ptr<KernelBuilder> &iBuilder,
99                                                                      std::string inputBufferName, llvm::Value *globalOffset) {
100
101        Value * capacity = iBuilder->getCapacity(inputBufferName);
102        Value * processed = iBuilder->getProcessedItemCount(inputBufferName);
103        processed = iBuilder->CreateAnd(processed, iBuilder->CreateNeg(capacity));
104        Value * offset = iBuilder->CreateSub(globalOffset, processed);
105        Value * valuePtr = iBuilder->getRawInputPointer(inputBufferName, offset);
106        return iBuilder->CreateLoad(valuePtr);
107    }
108
109    void LZParabixAioKernel::generateProcessCompressedBlock(const std::unique_ptr<KernelBuilder> &b,
110                                                            llvm::Value *lz4BlockStart, llvm::Value *lz4BlockEnd) {
111        Value* isTerminal = b->CreateICmpEQ(lz4BlockEnd, b->getScalarField("fileSize"));
112        b->setTerminationSignal(isTerminal);
113
114        BasicBlock* exitBlock = b->CreateBasicBlock("processCompressedExitBlock");
115
116        BasicBlock* processCon = b->CreateBasicBlock("processCompressedConBlock");
117        BasicBlock* processBody = b->CreateBasicBlock("processCompressedBodyBlock");
118
119
120        BasicBlock* beforeProcessConBlock = b->GetInsertBlock();
121        b->CreateBr(processCon);
122        b->SetInsertPoint(processCon);
123
124        PHINode* phiCursorValue = b->CreatePHI(b->getInt64Ty(), 2, "phiCursorValue"); // phiCursorValue should always be the position of next token except for the final sequence
125        phiCursorValue->addIncoming(lz4BlockStart, beforeProcessConBlock);
126
127        b->CreateCondBr(b->CreateICmpULT(phiCursorValue, lz4BlockEnd), processBody, exitBlock);
128
129        b->SetInsertPoint(processBody);
130
131        Value* nextTokenGlobalPos = this->processSequence(b, phiCursorValue, lz4BlockEnd);
132        phiCursorValue->addIncoming(nextTokenGlobalPos, b->GetInsertBlock());
133        b->CreateBr(processCon);
134
135        b->SetInsertPoint(exitBlock);
136        this->storePendingOutput(b);
137
138    }
139
140
141    llvm::Value *LZParabixAioKernel::processSequence(const std::unique_ptr<KernelBuilder> &b, llvm::Value *cursorPos,
142                                                              llvm::Value *lz4BlockEnd) {
143
144        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
145        Value* cursorNextPos = b->CreateAdd(cursorPos, b->getSize(1));
146
147        Value* sequenceBasePtr = b->getRawInputPointer("byteStream", cursorPos);
148        Value* sequenceToken = b->CreateLoad(sequenceBasePtr);
149
150        Value* highestTokenBit = b->CreateAnd(sequenceToken, b->getInt8((uint8_t)1 << 7));
151        Value* isLiteral = b->CreateICmpNE(highestTokenBit, b->getInt8(0));
152        Value* tokenNumValue = b->CreateZExt(b->CreateSub(sequenceToken, highestTokenBit), b->getSizeTy());
153
154
155        BasicBlock* literalProcessBlock = b->CreateBasicBlock("literalProcessBlock");
156        BasicBlock* matchProcessBlock = b->CreateBasicBlock("matchProcessBlock");
157        b->CreateCondBr(isLiteral, literalProcessBlock, matchProcessBlock);
158
159        // ---- literalProcessBlock
160        b->SetInsertPoint(literalProcessBlock);
161        this->processLiteral(b, cursorNextPos, tokenNumValue);
162        Value* newCursorPosAfterLiteral = b->CreateAdd(cursorNextPos, tokenNumValue);
163
164
165        BasicBlock* literalProcessFinalBlock = b->GetInsertBlock();
166        b->CreateBr(exitBlock);
167
168        // ---- matchProcessBlock
169        b->SetInsertPoint(matchProcessBlock);
170
171        Value* matchIndexBytes = this->processMatch(b, cursorNextPos, tokenNumValue, sequenceBasePtr);
172        Value* newCursorPosAfterMatch = b->CreateAdd(cursorNextPos, matchIndexBytes);
173
174        BasicBlock* matchProcessFinalBlock = b->GetInsertBlock();
175        b->CreateBr(exitBlock);
176
177        // ---- exitBlock
178        b->SetInsertPoint(exitBlock);
179        PHINode* phiCursorValue = b->CreatePHI(b->getSizeTy(), 2);
180        phiCursorValue->addIncoming(newCursorPosAfterLiteral, literalProcessFinalBlock);
181        phiCursorValue->addIncoming(newCursorPosAfterMatch, matchProcessFinalBlock);
182
183
184        return phiCursorValue;
185    }
186
187    llvm::Value *LZParabixAioKernel::processLiteral(const std::unique_ptr<KernelBuilder> &b, llvm::Value* cursorPos, llvm::Value* literalLength) {
188        Value* remCursorPos = b->CreateURem(cursorPos, b->getCapacity("inputBitStream0"));
189
190        Value* cursorBlockIndex = b->CreateUDiv(remCursorPos, b->getSize(b->getBitBlockWidth()));
191        Value* cursorBlockRem = b->CreateURem(remCursorPos, b->getSize(b->getBitBlockWidth()));
192        Value* cursorI64BlockIndex = b->CreateUDiv(cursorBlockRem, b->getSize(64));
193        Value* cursorI64BlockRem = b->CreateURem(cursorBlockRem, b->getSize(64));
194        Value* literalMask = b->CreateSub(
195                b->CreateSelect(b->CreateICmpEQ(literalLength, b->getInt64(0x40)), b->getInt64(0), b->CreateShl(b->getInt64(1), literalLength)),
196                b->getInt64(1)
197        );
198
199        std::vector<llvm::Value*> extractValues;
200
201        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
202            Value* bitStreamBasePtr = b->CreatePointerCast(b->getRawInputPointer("inputBitStream" + std::to_string(i), b->getSize(0)), b->getBitBlockType()->getPointerTo());
203            Value* targetBlockBasePtr = b->CreatePointerCast(b->CreateGEP(bitStreamBasePtr, b->CreateMul(cursorBlockIndex, b->getSize(mNumsOfBitStreams[i]))), b->getInt64Ty()->getPointerTo());
204
205            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
206                Value* ptr = b->CreateGEP(targetBlockBasePtr, b->CreateAdd(cursorI64BlockIndex, b->getSize(j * (b->getBitBlockWidth() / 64))));
207                Value* extractV = b->CreateLShr(b->CreateLoad(ptr), cursorI64BlockRem);
208                extractV = b->CreateAnd(extractV, literalMask);
209                extractValues.push_back(extractV);
210            }
211        }
212
213        this->appendBitStreamOutput(b, extractValues, literalLength);
214    }
215
216
217    llvm::Value *LZParabixAioKernel::processMatch(const std::unique_ptr<KernelBuilder> &b, llvm::Value* cursorPos, llvm::Value* matchOffset, llvm::Value* sequenceBasePtr) {
218        Function* pdep = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_bmi_pdep_64);
219        Constant * PEXT_func = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_bmi_pext_64);
220
221        Value* pdepMask = b->getInt64(0x0101010101010101);
222
223        Value* oneBitIndex = b->CreateZExt(b->CreateLoad(b->CreateGEP(sequenceBasePtr, b->getSize(1))), b->getInt64Ty());
224        Value* zeroBitIndex = b->CreateZExt(b->CreateLoad(b->CreateGEP(sequenceBasePtr, b->getSize(2))), b->getInt64Ty());
225        Value* matchMaskPtr = b->CreatePointerCast(b->CreateGEP(sequenceBasePtr, b->getSize(3)), b->getInt64Ty()->getPointerTo());
226        Value* matchMask = b->CreateLoad(matchMaskPtr);
227
228        Value* fullOneBitIndex = b->CreateCall(pdep, {oneBitIndex, pdepMask});
229        Value* fullZeroBitIndex = b->CreateCall(pdep, {zeroBitIndex, pdepMask});
230
231
232        Value* remainingMask = b->CreateNot(b->CreateMul(b->CreateOr(fullOneBitIndex, fullZeroBitIndex), b->getInt64(0xff)));
233        Value* fullMatchMask = b->CreateOr(
234                b->CreateMul(fullOneBitIndex, b->getInt64(0xff)),
235                b->CreateCall(pdep, {matchMask, remainingMask})
236        );
237
238        Value* remCursorPos = b->CreateURem(cursorPos, b->getCapacity("outputStream0"));
239        Value* cursorPosI64BlockIndex = b->CreateUDiv(remCursorPos, b->getSize(64));
240
241        Value* remOutputPos = b->CreateURem(b->getScalarField("outputPos"), b->getCapacity("outputStream0"));
242        Value* outputPosI64BlockIndex = b->CreateUDiv(remOutputPos, b->getSize(64));
243
244        Value* matchCopyFromI64BlockIndex = b->CreateSub(outputPosI64BlockIndex, matchOffset);
245
246        Value* matchCopyFromBitBlockIndex = b->CreateUDiv(matchCopyFromI64BlockIndex, b->getSize(4));
247        matchCopyFromI64BlockIndex = b->CreateURem(matchCopyFromI64BlockIndex, b->getSize(4));
248
249        std::vector<llvm::Value*> extractValues;
250        unsigned iStreamIndex = 0;
251        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
252            Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream" + std::to_string(i), b->getSize(0)), b->getBitBlockType()->getPointerTo());
253            Value* outputBlockBasePtr = b->CreateGEP(outputBasePtr, b->CreateMul(matchCopyFromBitBlockIndex, b->getSize(mNumsOfBitStreams[i])));
254            outputBlockBasePtr = b->CreatePointerCast(outputBlockBasePtr, b->getInt64Ty()->getPointerTo());
255
256            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
257                Value* ptr = b->CreateGEP(outputBlockBasePtr, b->CreateAdd(matchCopyFromI64BlockIndex, b->getSize(j * (b->getBitBlockWidth() / 64))));
258                Value* value = b->CreateLoad(ptr);
259                Value * extractV = b->CreateCall(PEXT_func, {value, fullMatchMask});
260                extractValues.push_back(extractV);
261                ++iStreamIndex;
262            }
263        }
264
265        this->appendBitStreamOutput(b, extractValues, b->CreatePopcount(fullMatchMask));
266
267        return b->CreateAdd(b->CreateSub(b->getSize(8), b->CreatePopcount(b->CreateOr(oneBitIndex, zeroBitIndex))), b->getSize(2));
268    }
269
270
271    // ---- Output
272    void LZParabixAioKernel::initPendingOutputScalar(const std::unique_ptr<KernelBuilder> &b) {
273        this->initPendingOutputScalar_BitStream(b);
274//        this->initPendingOutputScalar_Swizzled(b);
275    }
276
277    void LZParabixAioKernel::appendBitStreamOutput(const std::unique_ptr<KernelBuilder> &b, std::vector<llvm::Value*>& extractedValues, llvm::Value* valueLength) {
278        this->appendBitStreamOutput_BitStream(b, extractedValues, valueLength);
279//        this->appendBitStreamOutput_Swizzled(b, extractedValues, valueLength);
280    }
281
282    void LZParabixAioKernel::storePendingOutput(const std::unique_ptr<KernelBuilder> &b) {
283        BasicBlock* storePendingOutputBlock = b->CreateBasicBlock("storePendingOutputBlock");
284        BasicBlock* storePendingOutputExitBlock = b->CreateBasicBlock("storePendingOutputExitBlock");
285
286        Value* oldOutputPos = b->getScalarField("outputPos");
287        b->CreateCondBr(
288                b->CreateICmpNE(b->CreateURem(oldOutputPos, b->getSize(64)), b->getSize(0)),
289                storePendingOutputBlock,
290                storePendingOutputExitBlock
291        );
292
293        b->SetInsertPoint(storePendingOutputBlock);
294        this->storePendingOutput_BitStream(b);
295//        this->storePendingOutput_Swizzled(b);
296        b->CreateBr(storePendingOutputExitBlock);
297
298        b->SetInsertPoint(storePendingOutputExitBlock);
299    }
300
301
302    // ---- Output BitStream
303    void LZParabixAioKernel::initPendingOutputScalar_BitStream(const std::unique_ptr<KernelBuilder> &b) {
304        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
305            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
306                this->addScalar(b->getInt64Ty(), "pendingOutput" + std::to_string(i) + "_" + std::to_string(j));
307            }
308        }
309    }
310
311    void LZParabixAioKernel::appendBitStreamOutput_BitStream(const std::unique_ptr<KernelBuilder> &b, std::vector<llvm::Value*>& extractedValues, llvm::Value* valueLength) {
312        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
313
314        Value* oldOutputPos = b->getScalarField("outputPos");
315        Value* oldOutputPosRem64 = b->CreateURem(oldOutputPos, b->getSize(64));
316
317        std::vector<llvm::Value*> newOutputVec;
318
319        unsigned iStreamIndex = 0;
320        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
321            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
322                Value* newValue = b->CreateOr(b->getScalarField("pendingOutput" + std::to_string(i) + "_" + std::to_string(j)), b->CreateShl(extractedValues[iStreamIndex], oldOutputPosRem64));
323                newOutputVec.push_back(newValue);
324                ++iStreamIndex;
325            }
326        }
327
328        BasicBlock* noStoreOutputBlock = b->CreateBasicBlock("noStoreOutputBlock");
329        BasicBlock* storeOutputBlock =b->CreateBasicBlock("storeOutputBlock");
330
331        b->CreateCondBr(b->CreateICmpULT(b->CreateAdd(oldOutputPosRem64, valueLength), b->getSize(64)), noStoreOutputBlock, storeOutputBlock);
332
333        // ---- noStoreOutputBlock
334        b->SetInsertPoint(noStoreOutputBlock);
335
336        iStreamIndex = 0;
337        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
338            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
339                b->setScalarField("pendingOutput" + std::to_string(i) + "_" + std::to_string(j), newOutputVec[iStreamIndex]);
340                ++iStreamIndex;
341            }
342        }
343
344        b->CreateBr(exitBlock);
345
346        // ---- storeOutputBlock
347        b->SetInsertPoint(storeOutputBlock);
348
349        Value* oldOutputPosRem = b->CreateURem(oldOutputPos, b->getCapacity("outputStream0"));
350        Value* oldOutputPosBitBlockIndex = b->CreateUDiv(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
351        Value* oldOutputPosBitBlockRem = b->CreateURem(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
352
353        iStreamIndex = 0;
354        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
355            Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream" + std::to_string(i), b->getSize(0)), b->getBitBlockType()->getPointerTo());
356            Value* outputBitBlockBasePtr = b->CreateGEP(outputBasePtr, b->CreateMul(oldOutputPosBitBlockIndex, b->getSize(mNumsOfBitStreams[i])));
357            outputBitBlockBasePtr = b->CreatePointerCast(outputBitBlockBasePtr, b->getInt64Ty()->getPointerTo());
358
359            Value* oldOutputPosI64Index = b->CreateUDiv(oldOutputPosBitBlockRem, b->getSize(64));
360
361            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
362                Value* targetPtr = b->CreateGEP(outputBitBlockBasePtr, b->CreateAdd(oldOutputPosI64Index, b->getSize(j * (b->getBitBlockWidth() / 64))));
363                b->CreateStore(newOutputVec[iStreamIndex], targetPtr);
364                ++iStreamIndex;
365            }
366        }
367
368        Value* shiftAmount = b->CreateSub(b->getSize(0x40), oldOutputPosRem64);
369        Value* fullyShift = b->CreateICmpEQ(shiftAmount, b->getSize(0x40));
370
371        iStreamIndex = 0;
372        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
373            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
374                b->setScalarField("pendingOutput" + std::to_string(i) + "_" + std::to_string(j), b->CreateSelect(fullyShift, b->getInt64(0), b->CreateLShr(extractedValues[iStreamIndex], shiftAmount)));
375                ++iStreamIndex;
376            }
377        }
378
379        b->CreateBr(exitBlock);
380
381        b->SetInsertPoint(exitBlock);
382        b->setScalarField("outputPos", b->CreateAdd(oldOutputPos, valueLength));
383    }
384
385    void LZParabixAioKernel::storePendingOutput_BitStream(const std::unique_ptr<KernelBuilder> &b) {
386        Value* oldOutputPos = b->getScalarField("outputPos");
387        Value* oldOutputPosRem = b->CreateURem(oldOutputPos, b->getCapacity("outputStream0"));
388        Value* oldOutputPosBitBlockIndex = b->CreateUDiv(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
389        Value* oldOutputPosBitBlockRem = b->CreateURem(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
390        Value* oldOutputPosI64Index = b->CreateUDiv(oldOutputPosBitBlockRem, b->getSize(64));
391
392        unsigned iStreamIndex = 0;
393        for (unsigned i = 0; i < mNumsOfBitStreams.size(); i++) {
394            Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream" + std::to_string(i), b->getSize(0)), b->getBitBlockType()->getPointerTo());
395            Value* outputBitBlockBasePtr = b->CreateGEP(outputBasePtr, b->CreateMul(oldOutputPosBitBlockIndex, b->getSize(mNumsOfBitStreams[i])));
396            outputBitBlockBasePtr = b->CreatePointerCast(outputBitBlockBasePtr, b->getInt64Ty()->getPointerTo());
397            for (unsigned j = 0; j < mNumsOfBitStreams[i]; j++) {
398                Value* targetPtr = b->CreateGEP(outputBitBlockBasePtr, b->CreateAdd(oldOutputPosI64Index, b->getSize(j * (b->getBitBlockWidth() / 64))));
399                b->CreateStore(b->getScalarField("pendingOutput" + std::to_string(i) + "_" + std::to_string(j)), targetPtr);
400                ++iStreamIndex;
401            }
402        }
403    }
404
405    // ---- Output Swizzled
406    void LZParabixAioKernel::initPendingOutputScalar_Swizzled(const std::unique_ptr<KernelBuilder> &b) {
407        for (unsigned i = 0; i < (mNumsOfBitStreams[0] + 3) / 4; i++) {
408            this->addScalar(b->getBitBlockType(), "pendingOutput" + std::to_string(0) + "_" + std::to_string(i));
409        }
410    }
411    void LZParabixAioKernel::appendBitStreamOutput_Swizzled(const std::unique_ptr<KernelBuilder> &b, std::vector<llvm::Value*>& extractedValues, llvm::Value* valueLength) {
412
413        std::vector<llvm::Value*> extractedValuesVec;
414        for (unsigned i = 0; i < 2; i++) {
415            Value* vec = ConstantVector::getNullValue(b->getBitBlockType());
416            for (unsigned j = 0; j < 4; j++) {
417                vec = b->CreateInsertElement(vec, extractedValues[i * 4 + j], j);
418            }
419            extractedValuesVec.push_back(vec);
420        }
421
422        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
423
424        Value* oldOutputPos = b->getScalarField("outputPos");
425        Value* oldOutputPosRem64 = b->CreateURem(oldOutputPos, b->getSize(64));
426
427        std::vector<llvm::Value*> newOutputVec;
428        for (unsigned i = 0; i < 2; i++) {
429            Value* newValue = b->CreateOr(b->getScalarField("pendingOutput" + std::to_string(0) + "_" + std::to_string(i)), b->CreateShl(extractedValuesVec[i], b->simd_fill(64, oldOutputPosRem64)));
430            newOutputVec.push_back(newValue);
431        }
432
433
434        BasicBlock* noStoreOutputBlock = b->CreateBasicBlock("noStoreOutputBlock");
435        BasicBlock* storeOutputBlock =b->CreateBasicBlock("storeOutputBlock");
436
437        b->CreateCondBr(b->CreateICmpULT(b->CreateAdd(oldOutputPosRem64, valueLength), b->getSize(64)), noStoreOutputBlock, storeOutputBlock);
438
439        // ---- noStoreOutputBlock
440        b->SetInsertPoint(noStoreOutputBlock);
441        for (unsigned i = 0; i < 2; i++) {
442            b->setScalarField("pendingOutput" + std::to_string(0) + "_" + std::to_string(i), newOutputVec[i]);
443        }
444        b->CreateBr(exitBlock);
445
446        // ---- storeOutputBlock
447        b->SetInsertPoint(storeOutputBlock);
448
449        Value* oldOutputPosRem = b->CreateURem(oldOutputPos, b->getCapacity("outputStream0"));
450        Value* oldOutputPosBitBlockIndex = b->CreateUDiv(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
451        Value* oldOutputPosBitBlockRem = b->CreateURem(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
452
453        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream0", b->getSize(0)), b->getBitBlockType()->getPointerTo());
454        Value* outputBitBlockBasePtr = b->CreateGEP(outputBasePtr, b->CreateMul(oldOutputPosBitBlockIndex, b->getSize(8)));
455        outputBitBlockBasePtr = b->CreatePointerCast(outputBitBlockBasePtr, b->getInt64Ty()->getPointerTo());
456
457        Value* oldOutputPosI64Index = b->CreateUDiv(oldOutputPosBitBlockRem, b->getSize(64));
458
459        for (unsigned i = 0; i < 2; i++) {
460            for (unsigned j = 0; j < 4; j++) {
461                Value* targetPtr = b->CreateGEP(outputBitBlockBasePtr, b->CreateAdd(oldOutputPosI64Index, b->getSize((i * 4 + j) * 4)));
462                b->CreateStore(b->CreateExtractElement(newOutputVec[i], j), targetPtr);
463            }
464
465        }
466
467        Value* shiftAmount = b->CreateSub(b->getSize(0x40), oldOutputPosRem64);
468        Value* fullyShift = b->CreateICmpEQ(shiftAmount, b->getSize(0x40));
469
470        for (unsigned i = 0; i < 2; i++) {
471
472            b->setScalarField("pendingOutput" + std::to_string(0) + "_" + std::to_string(i), b->CreateSelect(fullyShift, ConstantVector::getNullValue(b->getBitBlockType()), b->CreateLShr(extractedValuesVec[i], b->simd_fill(64, shiftAmount))));
473        }
474
475        b->CreateBr(exitBlock);
476
477        b->SetInsertPoint(exitBlock);
478        b->setScalarField("outputPos", b->CreateAdd(oldOutputPos, valueLength));
479
480    }
481
482    void LZParabixAioKernel::storePendingOutput_Swizzled(const std::unique_ptr<KernelBuilder> &b) {
483        Value* oldOutputPos = b->getScalarField("outputPos");
484        Value* oldOutputPosRem = b->CreateURem(oldOutputPos, b->getCapacity("outputStream0"));
485        Value* oldOutputPosBitBlockIndex = b->CreateUDiv(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
486        Value* oldOutputPosBitBlockRem = b->CreateURem(oldOutputPosRem, b->getSize(b->getBitBlockWidth()));
487
488        Value* oldOutputPosI64Index = b->CreateUDiv(oldOutputPosBitBlockRem, b->getSize(64));
489
490        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream0", b->getSize(0)), b->getBitBlockType()->getPointerTo());
491        Value* outputBitBlockBasePtr = b->CreateGEP(outputBasePtr, b->CreateMul(oldOutputPosBitBlockIndex, b->getSize(8)));
492        outputBitBlockBasePtr = b->CreatePointerCast(outputBitBlockBasePtr, b->getInt64Ty()->getPointerTo());
493
494        vector<Value*> pendingOutputVec;
495        for (unsigned i = 0; i < 2; i++) {
496            pendingOutputVec.push_back(b->getScalarField("pendingOutput" + std::to_string(0) + "_" + std::to_string(i)));
497        }
498
499        for (unsigned i = 0; i < 2; i++) {
500            for (unsigned j = 0; j < 2; j++) {
501                Value* targetPtr = b->CreateGEP(outputBitBlockBasePtr, b->CreateAdd(oldOutputPosI64Index, b->getSize((i * 4 + j) * 4)));
502                b->CreateStore(b->CreateExtractElement(pendingOutputVec[i], j), targetPtr);
503            }
504        }
505    }
506}
Note: See TracBrowser for help on using the repository browser.