source: icGREP/icgrep-devel/icgrep/kernels/lz4/lz4_parallel_bytestream_aio.cpp @ 6070

Last change on this file since 6070 was 6070, checked in by xwa163, 11 months ago

Improve performance of literal copy and match copy in LZ4ParallelByteSteamAIOKernel

File size: 59.9 KB
Line 
1
2#include "lz4_parallel_bytestream_aio.h"
3
4#include <kernels/kernel_builder.h>
5#include <iostream>
6#include <string>
7#include <llvm/Support/raw_ostream.h>
8#include <kernels/streamset.h>
9
10using namespace llvm;
11using namespace kernel;
12using namespace std;
13
14#define SIMD_WIDTH (64)
15
16
17namespace kernel{
18
19    LZ4ParallelByteStreamAioKernel::LZ4ParallelByteStreamAioKernel(const std::unique_ptr<kernel::KernelBuilder> &b, size_t outputBlockSize)
20            :SegmentOrientedKernel("LZ4ParallelByteStreamAioKernel",
21            // Inputs
22                                   {
23                    Binding{b->getStreamSetTy(1, 8), "byteStream", BoundedRate(0, 1)},
24
25                    // block data
26                    Binding{b->getStreamSetTy(1, 1), "isCompressed", BoundedRate(0, 1), AlwaysConsume()},
27                    Binding{b->getStreamSetTy(1, 64), "blockStart", RateEqualTo("isCompressed"), AlwaysConsume()},
28                    Binding{b->getStreamSetTy(1, 64), "blockEnd", RateEqualTo("isCompressed"), AlwaysConsume()}
29
30            },
31            //Outputs
32                                   {
33                                           Binding{b->getStreamSetTy(1, 8), "outputStream", BoundedRate(0, 1)},
34                                   },
35            //Arguments
36                                   {
37                                           Binding{b->getSizeTy(), "fileSize"}
38                                   },
39                                   {},
40            //Internal states:
41                                   {
42                                           Binding{b->getInt64Ty(), "tempTimes"},
43                                           Binding{b->getIntNTy(SIMD_WIDTH), "outputPos"},
44
45                                   }), mOutputBlockSize(outputBlockSize) {
46        this->setStride(4 * 1024 * 1024 * 4);
47        addAttribute(MustExplicitlyTerminate());
48    }
49
50    Value* LZ4ParallelByteStreamAioKernel::generateSimdAcceleration(const std::unique_ptr<KernelBuilder> &b, llvm::Value *beginTokenPosVec,
51                                  llvm::Value *blockEndVec) {
52        /*
53        // TODO incomplete
54
55        // Constant
56        Function *gatherFunc = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_avx2_gather_d_q_256); // TODO find ret <4 * i32> version
57//        Function *gatherFunc2 = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_avx2_gather_d_q);
58
59        // ---- Entry Block
60        BasicBlock* entryBlock = b->GetInsertBlock();
61        Value* maskedTokenPosVec = b->CreateAnd(beginTokenPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(b->getCapacity("extender")))));
62        Value* maskBlockIndexVec = b->CreateLShr(beginTokenPosVec, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, std::log2(64))));
63        Value* maskBlockOffsetVec = b->CreateAnd(beginTokenPosVec, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 63)));
64        Value* extenderValueVec = b->CreateCall(
65                gatherFunc,
66                {
67                        UndefValue::get(b->getBitBlockType()),
68                        b->CreatePointerCast(b->getRawInputPointer("extender", b->getSize(0)), b->getInt8PtrTy()),
69                        b->CreateTrunc(maskBlockIndexVec, VectorType::get(b->getInt32Ty(), 4)),
70                        Constant::getAllOnesValue(b->getBitBlockType()),
71                        b->getInt8(8)
72                }
73        );
74
75        Value* extenderValueVec2 = b->CreateCall(
76                gatherFunc,
77                {
78                        UndefValue::get(VectorType::get(b->getInt8Ty(), 4)),
79                        b->CreatePointerCast(b->getRawInputPointer("extender", b->getSize(0)), b->getInt8PtrTy()),
80                        b->CreateTrunc(maskBlockIndexVec, VectorType::get(b->getInt32Ty(), 4)),
81                        Constant::getAllOnesValue(b->getBitBlockType()),
82                        b->getInt8(8)
83                }
84        );
85
86        Value* initTokeMarkersVec = b->CreateShl(b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 1)), maskBlockOffsetVec);
87
88//        b->CallPrintRegister("a", beginTokenPosVec);
89//        b->CallPrintRegister("maskedTokenPosVec", maskedTokenPosVec);
90//        b->CallPrintRegister("maskBlockIndexVec", maskBlockIndexVec);
91//        b->CallPrintRegister("gather_result", extenderValueVec);
92
93
94        BasicBlock* accelerationProcessBlock = b->CreateBasicBlock("accelerationProcessBlock");
95        BasicBlock* accelerationExitBlock = b->CreateBasicBlock("accelerationExitBlock");
96        b->CreateBr(accelerationProcessBlock);
97
98        // ---- AccelerationProcessBlock
99        b->SetInsertPoint(accelerationProcessBlock);
100        PHINode* phiTokenMarkersVec = b->CreatePHI(initTokeMarkersVec->getType(), 2);
101        phiTokenMarkersVec->addIncoming(initTokeMarkersVec, entryBlock);
102
103
104
105*/
106        return beginTokenPosVec;    //TODO
107
108    }
109
110
111    std::pair<Value *, Value *> LZ4ParallelByteStreamAioKernel::simdProcessBlockBoundary(
112            const std::unique_ptr<KernelBuilder> &b, Value *beginTokenPosVec, Value *lz4BlockEndVec, Value* initOutputPosVec
113    ) {
114        Function *gatherFunc = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_avx2_gather_d_q_256); // Maybe it will be better to use <4 * i32> version
115
116        // Constant
117        Value* BIT_BLOCK_0 = ConstantVector::getNullValue(b->getBitBlockType());
118        Value* BIT_BLOCK_1 = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0x1));
119        Value* BIT_BLOCK_F0 = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0xf0));
120        Value* BIT_BLOCK_0F = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0x0f));
121        Value* BIT_BLOCK_FF = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0xff));
122        Value* BIT_BLOCK_FFFF = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0xffff));
123        Type* INT_BIT_BLOCK_TY = b->getIntNTy(b->getBitBlockWidth());
124        Constant* INT_BIT_BLOCK_TY_0 = b->getIntN(b->getBitBlockWidth(), 0);
125
126        // ---- EntryBlock
127        BasicBlock* entryBlock = b->GetInsertBlock();
128        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
129
130        Value* notFinishBlocksVec = b->CreateICmpULT(beginTokenPosVec, lz4BlockEndVec);
131        Value* notFinishBitBlock = b->CreateZExt(notFinishBlocksVec, b->getBitBlockType());
132        Value* notFinishMask = b->CreateNeg(notFinishBitBlock);
133
134
135        Value* byteRawInputPtr = b->CreatePointerCast(b->getRawInputPointer("byteStream", b->getSize(0)), b->getInt8PtrTy());
136
137        Value* firstTokenPos = b->CreateExtractElement(beginTokenPosVec, (uint64_t)0);
138        Value* bytePtrBase = b->CreateGEP(byteRawInputPtr, firstTokenPos);
139
140
141
142        Value* tokenValuesVec = this->simdFetchByteData(b, byteRawInputPtr, beginTokenPosVec, notFinishMask);
143
144        Value* shouldExtendLiteralVec = b->CreateICmpEQ(b->CreateAnd(BIT_BLOCK_F0, tokenValuesVec), BIT_BLOCK_F0);
145        Value* shouldExtendLiteralBitBlockVec = b->CreateZExt(shouldExtendLiteralVec, b->getBitBlockType());
146        Value* shouldExtendLiteral = b->CreateICmpNE(b->CreateBitCast(shouldExtendLiteralBitBlockVec, INT_BIT_BLOCK_TY), INT_BIT_BLOCK_TY_0);
147
148        Value* shouldExtendMatchVec = b->CreateICmpEQ(b->CreateAnd(BIT_BLOCK_0F, tokenValuesVec), BIT_BLOCK_0F);
149        Value* shouldExtendMatchBitBlockVec = b->CreateZExt(shouldExtendMatchVec, b->getBitBlockType());
150        Value* shouldExtendMatch = b->CreateICmpNE(b->CreateBitCast(shouldExtendMatchBitBlockVec, INT_BIT_BLOCK_TY), INT_BIT_BLOCK_TY_0);
151
152        Value* initExtendLiteralPos = b->CreateAdd(beginTokenPosVec, shouldExtendLiteralBitBlockVec);
153
154
155        BasicBlock* extendLiteralCond = b->CreateBasicBlock("extendLiteralCond");
156        BasicBlock* extendLiteralEnd = b->CreateBasicBlock("extendLiteralEnd");
157
158        b->CreateCondBr(shouldExtendLiteral, extendLiteralCond, extendLiteralEnd);
159
160
161        // ---- extendLiteralCond
162        b->SetInsertPoint(extendLiteralCond);
163        PHINode* phiCurrentExtendLiteralPosVec = b->CreatePHI(initExtendLiteralPos->getType(), 2);
164        phiCurrentExtendLiteralPosVec->addIncoming(initExtendLiteralPos, entryBlock);
165
166        PHINode* phiExtendLiteralLengthVec = b->CreatePHI(b->getBitBlockType(), 2);
167        phiExtendLiteralLengthVec->addIncoming(BIT_BLOCK_0, entryBlock);
168
169        PHINode* phiShouldExtendLiteralBitBlockVec = b->CreatePHI(shouldExtendLiteralBitBlockVec->getType(), 2);
170        phiShouldExtendLiteralBitBlockVec->addIncoming(shouldExtendLiteralBitBlockVec, entryBlock);
171        Value* shouldExtendLiteralGatherMask = b->CreateNeg(phiShouldExtendLiteralBitBlockVec);
172        shouldExtendLiteralGatherMask = b->CreateAnd(shouldExtendLiteralGatherMask, notFinishMask);
173//        b->CallPrintInt("a", b->getSize(0));
174        // TODO maybe we can load i64 once and then consume 8 times
175        Value* currentLiteralLengthVec = this->simdFetchByteData(b, byteRawInputPtr, phiCurrentExtendLiteralPosVec, shouldExtendLiteralGatherMask);
176
177        Value* newExtendLiteralLengthVec = b->CreateAdd(phiExtendLiteralLengthVec, currentLiteralLengthVec);
178
179        Value* shouldContinueExtendVec = b->CreateICmpEQ(currentLiteralLengthVec, BIT_BLOCK_FF);
180        Value* shouldContinueExtendVecBitBlock = b->CreateZExt(shouldContinueExtendVec, b->getBitBlockType());
181
182        Value* newExtendLiteralPosVec = b->CreateAdd(phiCurrentExtendLiteralPosVec, b->CreateAnd(shouldExtendLiteralBitBlockVec, shouldContinueExtendVecBitBlock));
183
184
185        phiCurrentExtendLiteralPosVec->addIncoming(newExtendLiteralPosVec, b->GetInsertBlock());
186        phiExtendLiteralLengthVec->addIncoming(newExtendLiteralLengthVec, b->GetInsertBlock());
187
188
189        phiShouldExtendLiteralBitBlockVec->addIncoming(shouldContinueExtendVecBitBlock, b->GetInsertBlock());
190        Value* shouldContinueExtendLiteral = b->CreateICmpNE(b->CreateBitCast(shouldContinueExtendVecBitBlock, INT_BIT_BLOCK_TY), INT_BIT_BLOCK_TY_0);
191
192        b->CreateCondBr(shouldContinueExtendLiteral, extendLiteralCond, extendLiteralEnd);
193
194        // ---- extendLiteralEnd
195        b->SetInsertPoint(extendLiteralEnd);
196        PHINode* literalExtendValueVec = b->CreatePHI(b->getBitBlockType(), 2);
197        literalExtendValueVec->addIncoming(BIT_BLOCK_0, entryBlock);
198        literalExtendValueVec->addIncoming(newExtendLiteralLengthVec, extendLiteralCond);
199
200        PHINode* phiExtendLiteralEndPos = b->CreatePHI(b->getBitBlockType(), 2);
201        phiExtendLiteralEndPos->addIncoming(beginTokenPosVec, entryBlock);
202        phiExtendLiteralEndPos->addIncoming(phiCurrentExtendLiteralPosVec, extendLiteralCond);
203
204
205        Value* literalLengthVec = b->simd_add(SIMD_WIDTH, literalExtendValueVec, b->simd_srlv(SIMD_WIDTH, tokenValuesVec, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 4))));
206//        Value* literalLengthVec = b->CreateAdd(literalExtendValueVec, b->CreateLShr(tokenValuesVec, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 4))));
207
208        Value* literalStartPosVec = b->CreateAdd(phiExtendLiteralEndPos, BIT_BLOCK_1);
209        Value* literalEndPosVec = b->CreateAdd(literalStartPosVec, literalLengthVec);
210
211
212        this->handleSimdLiteralCopy(b, literalStartPosVec, literalLengthVec, initOutputPosVec);
213        Value* outputPosAfterLiteralCpy = b->CreateAdd(initOutputPosVec, literalLengthVec);
214
215
216        Value* matchOffsetBeginPosVec = literalEndPosVec;
217
218        Value* matchOffsetNextPosVec = b->CreateAdd(matchOffsetBeginPosVec, BIT_BLOCK_1);
219
220
221        BasicBlock* hasMatchPartBlock = b->CreateBasicBlock("hasMatchPartBlock");
222        BasicBlock* extendMatchCon = b->CreateBasicBlock("extendMatchCon");
223        BasicBlock* extendMatchExit = b->CreateBasicBlock("extendMatchExit");
224
225
226        BasicBlock* extendLiteralEndFinal = b->GetInsertBlock();
227
228        Value* hasMatchPartVec = b->CreateICmpULT(matchOffsetBeginPosVec, lz4BlockEndVec);
229        Value* hasMatchPartBitBlock = b->CreateZExt(hasMatchPartVec, b->getBitBlockType());
230        Value* hasMatchPartMask = b->CreateNeg(hasMatchPartBitBlock);
231
232        b->CreateLikelyCondBr(b->CreateICmpNE(b->CreateBitCast(hasMatchPartBitBlock, INT_BIT_BLOCK_TY), INT_BIT_BLOCK_TY_0), hasMatchPartBlock, exitBlock);
233
234        // ---- hasMatchPartBlock
235        b->SetInsertPoint(hasMatchPartBlock);
236        Value* initExtendMatchPosVec = b->CreateAdd(matchOffsetNextPosVec, shouldExtendMatchBitBlockVec);
237//        b->CallPrintRegister("initExtendMatchPosVec", initExtendMatchPosVec);
238        b->CreateCondBr(shouldExtendMatch, extendMatchCon, extendMatchExit);
239
240        // ---- extendMatchCon
241        b->SetInsertPoint(extendMatchCon);
242        PHINode* phiCurrentExtendMatchPosVec = b->CreatePHI(initExtendMatchPosVec->getType(), 2);
243        phiCurrentExtendMatchPosVec->addIncoming(initExtendMatchPosVec, hasMatchPartBlock);
244        PHINode* phiExtendMatchLengthVec = b->CreatePHI(b->getBitBlockType(), 2);
245        phiExtendMatchLengthVec->addIncoming(BIT_BLOCK_0, hasMatchPartBlock);
246
247        PHINode* phiShouldExtendMatchBitBlockVec = b->CreatePHI(shouldExtendMatchBitBlockVec->getType(), 2);
248        phiShouldExtendMatchBitBlockVec->addIncoming(shouldExtendMatchBitBlockVec, hasMatchPartBlock);
249        Value* shouldExtendMatchGatherMask = b->CreateNeg(phiShouldExtendMatchBitBlockVec);
250        shouldExtendMatchGatherMask = b->CreateAnd(shouldExtendMatchGatherMask, notFinishMask);
251        // TODO maybe we can load i64 once and then consume 8 times
252
253        Value* currentMatchLengthVec = this->simdFetchByteData(b, byteRawInputPtr, phiCurrentExtendMatchPosVec, shouldExtendMatchGatherMask);
254
255        Value* newExtendMatchLengthVec = b->CreateAdd(phiExtendMatchLengthVec, currentMatchLengthVec);
256
257
258        Value* shouldContinueExtendMatchVec = b->CreateICmpEQ(currentMatchLengthVec, BIT_BLOCK_FF);
259        Value* shouldContinueExtendMatchVecBitBlock = b->CreateZExt(shouldContinueExtendMatchVec, b->getBitBlockType());
260
261        Value* newExtendMatchPosVec = b->CreateAdd(phiCurrentExtendMatchPosVec, b->CreateAnd(shouldExtendMatchBitBlockVec, shouldContinueExtendMatchVecBitBlock));
262
263
264        phiCurrentExtendMatchPosVec->addIncoming(newExtendMatchPosVec, b->GetInsertBlock());
265        phiExtendMatchLengthVec->addIncoming(newExtendMatchLengthVec, b->GetInsertBlock());
266
267
268        phiShouldExtendMatchBitBlockVec->addIncoming(shouldContinueExtendMatchVecBitBlock, b->GetInsertBlock());
269        Value* shouldContinueExtendMatch = b->CreateICmpNE(b->CreateBitCast(shouldContinueExtendMatchVecBitBlock, INT_BIT_BLOCK_TY), INT_BIT_BLOCK_TY_0);
270
271        b->CreateCondBr(shouldContinueExtendMatch, extendMatchCon, extendMatchExit);
272
273
274        // ---- extendMatchExit
275        b->SetInsertPoint(extendMatchExit);
276
277        PHINode* matchExtendValueVec = b->CreatePHI(newExtendMatchLengthVec->getType(), 2);
278        matchExtendValueVec->addIncoming(BIT_BLOCK_0, hasMatchPartBlock);
279        matchExtendValueVec->addIncoming(newExtendMatchLengthVec, extendMatchCon);
280        PHINode* phiExtendMatchEndPos = b->CreatePHI(matchOffsetNextPosVec->getType(), 2);
281        phiExtendMatchEndPos->addIncoming(matchOffsetNextPosVec, hasMatchPartBlock);
282        phiExtendMatchEndPos->addIncoming(phiCurrentExtendMatchPosVec, extendMatchCon);
283
284
285        // matchLength = (size_t)token & 0xf + 4 + matchExtendValue
286        Value* matchLength = b->CreateAdd(
287                b->CreateAdd(matchExtendValueVec, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 4))),
288                b->CreateAnd(tokenValuesVec, BIT_BLOCK_0F)
289        );
290        matchLength = b->CreateAnd(matchLength, hasMatchPartMask);
291
292
293        Value* matchOffsetVec =  b->CreateCall(
294                gatherFunc,
295                {
296                        UndefValue::get(b->getBitBlockType()),
297                        bytePtrBase,
298                        b->CreateTrunc(b->CreateSub(matchOffsetBeginPosVec, b->simd_fill(SIMD_WIDTH, firstTokenPos)), VectorType::get(b->getInt32Ty(), 4)),
299                        hasMatchPartMask,
300                        b->getInt8(1)
301                }
302        );
303        matchOffsetVec = b->CreateAnd(matchOffsetVec, notFinishMask);
304        matchOffsetVec = b->CreateAnd(matchOffsetVec, BIT_BLOCK_FFFF);
305
306//        Value* matchOffsetVec = this->simdFetchByteData(b, byteRawInputPtr, matchOffsetBeginPosVec, b->CreateAnd(hasMatchPartMask, notFinishMask));
307
308
309
310        this->handleSimdMatchCopy(b, matchOffsetVec, matchLength, outputPosAfterLiteralCpy);
311
312        Value* outputPosAfterMatchCpy = b->CreateAdd(outputPosAfterLiteralCpy, matchLength);
313
314        BasicBlock* extendMatchExitFinal = b->GetInsertBlock();
315
316        b->CreateBr(exitBlock);
317        // ---- exitBlock
318
319        b->SetInsertPoint(exitBlock);
320
321        PHINode* phiBeforeTokenPos = b->CreatePHI(matchOffsetNextPosVec->getType(), 2);
322        phiBeforeTokenPos->addIncoming(matchOffsetNextPosVec, extendLiteralEndFinal);
323        phiBeforeTokenPos->addIncoming(phiExtendMatchEndPos, extendMatchExitFinal);
324
325        PHINode* phiNewOutputPos = b->CreatePHI(outputPosAfterLiteralCpy->getType(), 2);
326        phiNewOutputPos->addIncoming(outputPosAfterLiteralCpy, extendLiteralEndFinal);
327        phiNewOutputPos->addIncoming(outputPosAfterMatchCpy, extendMatchExitFinal);
328//        b->CallPrintRegister("phiBeforeTokenPos", phiBeforeTokenPos);
329        Value* nextTokenPos = b->CreateAdd(phiBeforeTokenPos, BIT_BLOCK_1);
330//        b->CallPrintRegister("nextTokenPos", nextTokenPos);
331        return std::make_pair(nextTokenPos, phiNewOutputPos);
332    }
333
334    void LZ4ParallelByteStreamAioKernel::generateSimdDecompression(const std::unique_ptr<KernelBuilder> &b, Value* blockDataIndex) {
335        BasicBlock* entryBlock = b->GetInsertBlock();
336        BasicBlock* exitBlock = b->CreateBasicBlock("simdDecompressionExitBlock");
337        BasicBlock* processCon = b->CreateBasicBlock("simdDecompressionProcessConBlock");
338        BasicBlock* processBody = b->CreateBasicBlock("simdDecompressionProcessBodyBlock");
339
340        // ---- entryBlock
341        Value* blockStartVec = this->generateLoadSimdInt64NumberInput(b, "blockStart", blockDataIndex);
342        Value* blockEndVec = this->generateLoadSimdInt64NumberInput(b, "blockEnd", blockDataIndex);
343
344        Value* outputPos = b->getProducedItemCount("outputStream");
345        Value* initOutputPosVec = b->simd_fill(SIMD_WIDTH, outputPos);
346        initOutputPosVec = b->CreateAdd(
347                initOutputPosVec,
348                ConstantVector::get({
349                                            b->getIntN(SIMD_WIDTH, 0),
350                                            b->getIntN(SIMD_WIDTH, 1 * 4 * 1024 * 1024),
351                                            b->getIntN(SIMD_WIDTH, 2 * 4 * 1024 * 1024),
352                                            b->getIntN(SIMD_WIDTH, 3 * 4 * 1024 * 1024)
353                                    }));
354
355        // TODO handle uncompression blocks
356
357        b->CreateBr(processCon);
358
359        // ---- processCon
360        b->SetInsertPoint(processCon);
361        PHINode* phiCursorVec = b->CreatePHI(blockStartVec->getType(), 2);
362        phiCursorVec->addIncoming(blockStartVec, entryBlock);
363
364        PHINode* phiOutputPosVec = b->CreatePHI(initOutputPosVec->getType(), 2);
365        phiOutputPosVec->addIncoming(initOutputPosVec, entryBlock);
366
367
368        Value* hasRemaining = b->simd_ult(SIMD_WIDTH, phiCursorVec, blockEndVec);
369        hasRemaining = b->CreateICmpNE(b->CreateBitCast(hasRemaining, b->getIntNTy(256)), Constant::getNullValue(b->getIntNTy(256)));
370
371        b->CreateCondBr(hasRemaining, processBody, exitBlock);
372
373        // ---- processBody
374        b->SetInsertPoint(processBody);
375//        Value* newCursorVec = this->generateSimdAcceleration(b, phiCursorVec, blockEndVec);
376        auto ret = this->simdProcessBlockBoundary(b, phiCursorVec, blockEndVec, phiOutputPosVec);;
377        Value* newCursorVec = ret.first;
378        Value* newOutputPosVec = ret.second;
379//        b->CallPrintInt("newOutputPosVec", b->CreateExtractElement(newOutputPosVec, (uint64_t)0));
380
381        phiCursorVec->addIncoming(newCursorVec, b->GetInsertBlock());
382        phiOutputPosVec->addIncoming(newOutputPosVec, b->GetInsertBlock());
383
384        b->CreateBr(processCon);
385
386        // ---- exitBlock
387        b->SetInsertPoint(exitBlock);
388
389        uint64_t lastVecIndex = b->getBitBlockWidth() / SIMD_WIDTH - 1;
390        Value* lastBlockEnd = b->CreateExtractElement(blockEndVec, lastVecIndex);
391        b->setProcessedItemCount("byteStream", lastBlockEnd);
392
393        Value* lastOutputPos = b->CreateExtractElement(phiOutputPosVec, lastVecIndex);
394        b->setProducedItemCount("outputStream", lastOutputPos);
395//        b->CallPrintRegister("phiOutputPosVec", phiOutputPosVec);
396
397    }
398
399    void LZ4ParallelByteStreamAioKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> &b) {
400        // Constant
401        Value* SIZE_1 = b->getSize(1);
402
403        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
404
405        Value * blockDataIndex = b->getProcessedItemCount("isCompressed");
406        Value * totalNumber = b->getAvailableItemCount("isCompressed");
407//        b->CallPrintInt("totalNumber", totalNumber);
408        Value * fileSize = b->getScalarField("fileSize");
409        Value * availableNumber = b->CreateSub(totalNumber, blockDataIndex);
410        Value * lastBlockEnd = this->generateLoadInt64NumberInput(b, "blockEnd", b->CreateSub(totalNumber, SIZE_1));
411        Value * isTerminal = b->CreateAnd(b->CreateICmpEQ(fileSize, lastBlockEnd), b->CreateICmpULE(availableNumber, b->getSize(b->getBitBlockWidth() / SIMD_WIDTH)));
412        b->setTerminationSignal(isTerminal);
413
414        BasicBlock* simdProcessEntryBlock = b->CreateBasicBlock("simdProcessEntryBlock");
415        BasicBlock* notEnoughSimdDataBlock = b->CreateBasicBlock("notEnoughSimdDataBlock");
416
417        b->CreateLikelyCondBr(b->CreateICmpUGE(availableNumber, b->getSize(b->getBitBlockWidth() / SIMD_WIDTH)), simdProcessEntryBlock, notEnoughSimdDataBlock);
418
419        // ---- simdProcessEntryBlock
420        b->SetInsertPoint(simdProcessEntryBlock);
421        this->generateSimdDecompression(b, blockDataIndex);
422        Value* newProcessedDataIndex = b->CreateAdd(blockDataIndex, b->getSize(b->getBitBlockWidth() / SIMD_WIDTH));
423        b->setProcessedItemCount("isCompressed", newProcessedDataIndex);
424
425        b->CreateBr(exitBlock);
426
427        // ---- notEnoughSimdDataBlock
428        b->SetInsertPoint(notEnoughSimdDataBlock);
429
430        BasicBlock* notSimdProcessBlock = b->CreateBasicBlock("notSimdProcessBlock");
431        b->CreateUnlikelyCondBr(isTerminal, notSimdProcessBlock, exitBlock);
432
433        // ---- notSimdProcessBlock
434        b->SetInsertPoint(notSimdProcessBlock);
435        // Use loop to process the remaining block in sequential approach (the number of the remaining block should be less than (b->getBitBlockWidth() / SIMD_WIDTH))
436        this->generateSequentialDecompression(b, blockDataIndex, totalNumber);
437        b->CreateBr(exitBlock);
438
439
440        // ---- ExitBlock
441        b->SetInsertPoint(exitBlock);
442    }
443
444    void LZ4ParallelByteStreamAioKernel::generateSequentialDecompression(const std::unique_ptr<KernelBuilder> &b, llvm::Value* startBlockDataIndex, llvm::Value* endBlockDataIndex) {
445
446        // ---- EntryBlock
447        BasicBlock* entryBlock = b->GetInsertBlock();
448
449        BasicBlock* SequentialConBlock = b->CreateBasicBlock("SequentialConBlock");
450        BasicBlock* SequentialBodyBlock = b->CreateBasicBlock("SequentialBodyBlock");
451        BasicBlock* SequentialExitBlock = b->CreateBasicBlock("SequentialExitBlock");
452
453
454        Value* initOutputPos = b->getProducedItemCount("outputStream");
455
456        b->CreateBr(SequentialConBlock);
457
458        // ---- SequentialConBlock
459        b->SetInsertPoint(SequentialConBlock);
460        PHINode* phiCurrentBlockDataIndex = b->CreatePHI(b->getSizeTy(), 2);
461        phiCurrentBlockDataIndex->addIncoming(startBlockDataIndex, entryBlock);
462        PHINode* phiOutputPos = b->CreatePHI(b->getSizeTy(), 2);
463        phiOutputPos->addIncoming(initOutputPos, entryBlock);
464
465        b->CreateCondBr(b->CreateICmpULT(phiCurrentBlockDataIndex, endBlockDataIndex), SequentialBodyBlock, SequentialExitBlock);
466
467        // ---- SequentialBodyBlock
468        b->SetInsertPoint(SequentialBodyBlock);
469        Value* lz4BlockStart = this->generateLoadInt64NumberInput(b, "blockStart", phiCurrentBlockDataIndex);
470        Value* lz4BlockEnd = this->generateLoadInt64NumberInput(b, "blockEnd", phiCurrentBlockDataIndex);
471        Value* newOutputPos = this->generateProcessCompressedBlock(b, lz4BlockStart, lz4BlockEnd, phiOutputPos);
472
473        b->setProcessedItemCount("byteStream", lz4BlockEnd);
474        b->setProducedItemCount("outputStream", newOutputPos);
475
476        phiCurrentBlockDataIndex->addIncoming(b->CreateAdd(phiCurrentBlockDataIndex, b->getSize(1)), b->GetInsertBlock());
477        phiOutputPos->addIncoming(newOutputPos, b->GetInsertBlock());
478
479        b->CreateBr(SequentialConBlock);
480
481        // ---- SequentialExitBlock
482        b->SetInsertPoint(SequentialExitBlock);
483        b->setProcessedItemCount("isCompressed", endBlockDataIndex);
484
485    }
486
487    llvm::Value *
488    LZ4ParallelByteStreamAioKernel::generateLoadSimdInt64NumberInput(const std::unique_ptr<KernelBuilder> &iBuilder, std::string inputBufferName,
489                                     llvm::Value *globalOffset) {
490        Value * capacity = iBuilder->getCapacity(inputBufferName);
491        Value * processed = iBuilder->getProcessedItemCount(inputBufferName);
492        processed = iBuilder->CreateAnd(processed, iBuilder->CreateNeg(capacity));
493        Value * offset = iBuilder->CreateSub(globalOffset, processed);
494        Value * valuePtr = iBuilder->getRawInputPointer(inputBufferName, offset);
495        valuePtr = iBuilder->CreatePointerCast(valuePtr, iBuilder->getBitBlockType()->getPointerTo());
496        return iBuilder->CreateLoad(valuePtr);
497    }
498
499    llvm::Value *LZ4ParallelByteStreamAioKernel::generateLoadInt64NumberInput(const std::unique_ptr<KernelBuilder> &iBuilder,
500                                                                      std::string inputBufferName, llvm::Value *globalOffset) {
501
502        Value * capacity = iBuilder->getCapacity(inputBufferName);
503        Value * processed = iBuilder->getProcessedItemCount(inputBufferName);
504        processed = iBuilder->CreateAnd(processed, iBuilder->CreateNeg(capacity));
505        Value * offset = iBuilder->CreateSub(globalOffset, processed);
506        Value * valuePtr = iBuilder->getRawInputPointer(inputBufferName, offset);
507        return iBuilder->CreateLoad(valuePtr);
508    }
509
510    llvm::Value*
511    LZ4ParallelByteStreamAioKernel::generateProcessCompressedBlock(const std::unique_ptr<KernelBuilder> &b, llvm::Value *lz4BlockStart,
512                                                           llvm::Value *lz4BlockEnd, llvm::Value* initOutputPos) {
513        BasicBlock* entryBlock = b->GetInsertBlock();
514
515        Value* isTerminal = b->CreateICmpEQ(lz4BlockEnd, b->getScalarField("fileSize"));
516        b->setTerminationSignal(isTerminal);
517
518        BasicBlock* exitBlock = b->CreateBasicBlock("processCompressedExitBlock");
519
520        BasicBlock* processCon = b->CreateBasicBlock("processCompressedConBlock");
521        BasicBlock* processBody = b->CreateBasicBlock("processCompressedBodyBlock");
522
523
524        BasicBlock* beforeProcessConBlock = b->GetInsertBlock();
525        b->CreateBr(processCon);
526        b->SetInsertPoint(processCon);
527        PHINode* phiOutputPos = b->CreatePHI(initOutputPos->getType(), 2);
528        phiOutputPos->addIncoming(initOutputPos, entryBlock);
529        PHINode* phiCursorValue = b->CreatePHI(b->getInt64Ty(), 2); // phiCursorValue should always be the position of next token except for the final sequence
530        phiCursorValue->addIncoming(lz4BlockStart, beforeProcessConBlock);
531
532        b->CreateCondBr(b->CreateICmpULT(phiCursorValue, lz4BlockEnd), processBody, exitBlock);
533
534        b->SetInsertPoint(processBody);
535
536
537        auto ret = this->processBlockBoundary(b, phiCursorValue, lz4BlockEnd, phiOutputPos);
538        Value* nextTokenGlobalPos = ret.first;
539        Value* nextOutputPos = ret.second;
540
541        phiOutputPos->addIncoming(nextOutputPos, b->GetInsertBlock());
542        phiCursorValue->addIncoming(nextTokenGlobalPos, b->GetInsertBlock());
543        b->CreateBr(processCon);
544
545        b->SetInsertPoint(exitBlock);
546        return phiOutputPos;
547    }
548
549
550    std::pair<llvm::Value *, llvm::Value *> LZ4ParallelByteStreamAioKernel::processBlockBoundary(const std::unique_ptr<KernelBuilder> &b, llvm::Value *beginTokenPos,
551                                                              llvm::Value *lz4BlockEnd, llvm::Value* initOutputPos) {
552        // Constant
553        ConstantInt* SIZE_0 = b->getSize(0);
554        ConstantInt* SIZE_1 = b->getSize(1);
555        ConstantInt* BYTE_FF = b->getInt8(0xff);
556        Value* BYTE_F0 = b->getInt8(0xf0);
557        Value* BYTE_0F = b->getInt8(0x0f);
558
559        // ---- EntryBlock
560        BasicBlock* entryBlock = b->GetInsertBlock();
561        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
562
563        Value* bytePtrBase = b->CreatePointerCast(b->getRawInputPointer("byteStream", b->getSize(0)), b->getInt8PtrTy());
564
565        Value* tokenValue = b->CreateLoad(b->CreateGEP(bytePtrBase, beginTokenPos));
566
567        Value* shouldExtendLiteral = b->CreateICmpEQ(b->CreateAnd(tokenValue, BYTE_F0), BYTE_F0);
568
569        Value* shouldExtendMatch = b->CreateICmpEQ(b->CreateAnd(tokenValue, BYTE_0F), BYTE_0F);
570
571        BasicBlock* extendLiteralCond = b->CreateBasicBlock("extendLiteralCond");
572        BasicBlock* extendLiteralEnd = b->CreateBasicBlock("extendLiteralEnd");
573
574        Value* initExtendLiteralPos = b->CreateAdd(beginTokenPos, b->getSize(1));
575
576        b->CreateCondBr(shouldExtendLiteral, extendLiteralCond, extendLiteralEnd);
577
578        // ---- extendLiteralCond
579        b->SetInsertPoint(extendLiteralCond);
580        PHINode* phiCurrentExtendLiteralPos = b->CreatePHI(b->getSizeTy(), 2);
581        phiCurrentExtendLiteralPos->addIncoming(initExtendLiteralPos, entryBlock);
582        PHINode* phiExtendLiteralLength = b->CreatePHI(b->getSizeTy(), 2);
583        phiExtendLiteralLength->addIncoming(SIZE_0, entryBlock);
584
585        Value* currentLiteralLengthByte = b->CreateLoad(b->CreateGEP(bytePtrBase, phiCurrentExtendLiteralPos));
586        Value* newExtendLiteralLength = b->CreateAdd(phiExtendLiteralLength, b->CreateZExt(currentLiteralLengthByte, b->getSizeTy()));
587
588        phiCurrentExtendLiteralPos->addIncoming(b->CreateAdd(phiCurrentExtendLiteralPos, SIZE_1), b->GetInsertBlock());
589        phiExtendLiteralLength->addIncoming(newExtendLiteralLength, b->GetInsertBlock());
590
591        b->CreateCondBr(b->CreateICmpEQ(currentLiteralLengthByte, BYTE_FF), extendLiteralCond, extendLiteralEnd);
592
593        // ---- extendLiteralEnd
594        b->SetInsertPoint(extendLiteralEnd);
595        PHINode* literalExtendValue = b->CreatePHI(b->getSizeTy(), 2);
596        literalExtendValue->addIncoming(SIZE_0, entryBlock);
597        literalExtendValue->addIncoming(newExtendLiteralLength, extendLiteralCond);
598        PHINode* phiExtendLiteralEndPos = b->CreatePHI(b->getSizeTy(), 2);
599        phiExtendLiteralEndPos->addIncoming(beginTokenPos, entryBlock);
600        phiExtendLiteralEndPos->addIncoming(phiCurrentExtendLiteralPos, extendLiteralCond);
601
602        Value* literalLength = b->CreateAdd(literalExtendValue, b->CreateZExt(b->CreateLShr(tokenValue, b->getInt8(4)), b->getSizeTy()));
603
604        Value* literalStartPos = b->CreateAdd(phiExtendLiteralEndPos, SIZE_1);
605        Value* literalEndPos = b->CreateAdd(literalStartPos, literalLength);
606
607        Value* matchOffsetBeginPos = literalEndPos;
608        Value* matchOffsetNextPos = b->CreateAdd(matchOffsetBeginPos, SIZE_1);
609
610        BasicBlock* hasMatchPartBlock = b->CreateBasicBlock("hasMatchPartBlock");
611        BasicBlock* extendMatchCon = b->CreateBasicBlock("extendMatchCon");
612        BasicBlock* extendMatchExit = b->CreateBasicBlock("extendMatchExit");
613
614        // This literal copy will always cross 64 bits literal boundary
615        this->handleLiteralCopy(b, literalStartPos, literalLength, initOutputPos);
616
617        Value* outputPosAfterLiteralCpy = b->CreateAdd(literalLength, initOutputPos);
618
619        BasicBlock* extendLiteralEndFinal = b->GetInsertBlock();
620
621        b->CreateLikelyCondBr(b->CreateICmpULT(matchOffsetBeginPos, lz4BlockEnd), hasMatchPartBlock, exitBlock);
622
623        // ---- hasMatchPartBlock
624        b->SetInsertPoint(hasMatchPartBlock);
625        Value* initExtendMatchPos = b->CreateAdd(matchOffsetBeginPos, b->getSize(2));
626        b->CreateCondBr(shouldExtendMatch, extendMatchCon, extendMatchExit);
627
628        // ---- extendMatchCon
629        b->SetInsertPoint(extendMatchCon);
630        PHINode* phiCurrentExtendMatchPos = b->CreatePHI(b->getSizeTy(), 2);
631        phiCurrentExtendMatchPos->addIncoming(initExtendMatchPos, hasMatchPartBlock);
632        PHINode* phiExtendMatchLength = b->CreatePHI(b->getSizeTy(), 2);
633        phiExtendMatchLength->addIncoming(SIZE_0, hasMatchPartBlock);
634
635        Value* currentMatchLengthByte = b->CreateLoad(b->CreateGEP(bytePtrBase, phiCurrentExtendMatchPos));
636        Value* newExtendMatchLength = b->CreateAdd(phiExtendMatchLength, b->CreateZExt(currentMatchLengthByte, b->getSizeTy()));
637
638        phiCurrentExtendMatchPos->addIncoming(b->CreateAdd(phiCurrentExtendMatchPos, SIZE_1), b->GetInsertBlock());
639        phiExtendMatchLength->addIncoming(newExtendMatchLength, b->GetInsertBlock());
640
641        b->CreateCondBr(b->CreateICmpEQ(currentMatchLengthByte, BYTE_FF), extendMatchCon, extendMatchExit);
642
643        // ---- extendMatchExit
644        b->SetInsertPoint(extendMatchExit);
645        PHINode* matchExtendValue = b->CreatePHI(b->getSizeTy(), 2);
646        matchExtendValue->addIncoming(SIZE_0, hasMatchPartBlock);
647        matchExtendValue->addIncoming(newExtendMatchLength, extendMatchCon);
648        PHINode* phiExtendMatchEndPos = b->CreatePHI(b->getSizeTy(), 2);
649        phiExtendMatchEndPos->addIncoming(matchOffsetNextPos, hasMatchPartBlock);
650        phiExtendMatchEndPos->addIncoming(phiCurrentExtendMatchPos, extendMatchCon);
651
652        // matchLength = (size_t)token & 0xf + 4 + matchExtendValue
653        Value* matchLength = b->CreateAdd(
654                b->CreateAdd(matchExtendValue, b->getSize(4)),
655                b->CreateZExt(b->CreateAnd(tokenValue, BYTE_0F), b->getSizeTy())
656        );
657
658        Value* matchOffsetPtr = b->getRawInputPointer("byteStream", matchOffsetBeginPos);
659        // For now, it is safe to cast matchOffset pointer into i16 since the input byte stream is always linear available
660        matchOffsetPtr = b->CreatePointerCast(matchOffsetPtr, b->getInt16Ty()->getPointerTo());
661        Value* matchOffset = b->CreateZExt(b->CreateLoad(matchOffsetPtr), b->getSizeTy());
662        this->handleMatchCopy(b, matchOffset, matchLength, outputPosAfterLiteralCpy);
663        Value* outputPosAfterMatchCpy = b->CreateAdd(outputPosAfterLiteralCpy, matchLength);
664        BasicBlock* extendMatchExitFinal = b->GetInsertBlock();
665        b->CreateBr(exitBlock);
666
667        // ---- exitBlock
668        b->SetInsertPoint(exitBlock);
669        PHINode* phiBeforeTokenPos = b->CreatePHI(b->getSizeTy(), 2);
670        phiBeforeTokenPos->addIncoming(matchOffsetNextPos, extendLiteralEndFinal);
671        phiBeforeTokenPos->addIncoming(phiExtendMatchEndPos, extendMatchExitFinal);
672        PHINode* phiOutputPos = b->CreatePHI(b->getSizeTy(), 2);
673        phiOutputPos->addIncoming(outputPosAfterLiteralCpy, extendLiteralEndFinal);
674        phiOutputPos->addIncoming(outputPosAfterMatchCpy, extendMatchExitFinal);
675
676        Value* nextTokenPos = b->CreateAdd(phiBeforeTokenPos, SIZE_1);
677
678        return std::make_pair(nextTokenPos, phiOutputPos);
679    }
680
681    void LZ4ParallelByteStreamAioKernel::generateSimdMatchCopyByMemcpy(const std::unique_ptr<KernelBuilder> &b, llvm::Value* matchOffsetVec, llvm::Value* matchLengthVec, llvm::Value* outputPosVec) {
682        Value* outputCapacity = b->getCapacity("outputStream");
683        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream", b->getSize(0)), b->getInt8PtrTy());
684
685        for (uint64_t i = 0; i < b->getBitBlockWidth() / SIMD_WIDTH; i++) {
686            BasicBlock* matchCopyConBlock = b->CreateBasicBlock("matchCopyConBlock" + std::to_string(i));
687            BasicBlock* matchCopyBodyBlock = b->CreateBasicBlock("matchCopyBodyBlock" + std::to_string(i));
688            BasicBlock* matchCopyExitBlock = b->CreateBasicBlock("matchCopyExitBlock" + std::to_string(i));
689
690            BasicBlock* beforeConBlock = b->GetInsertBlock();
691
692            Value* matchOffset = b->CreateExtractElement(matchOffsetVec, i);
693            Value* initMatchLength = b->CreateExtractElement(matchLengthVec, i);
694            Value* initOutputPos = b->CreateExtractElement(outputPosVec, i);
695            b->CreateBr(matchCopyConBlock);
696
697            // ---- matchCopyConBlock
698            b->SetInsertPoint(matchCopyConBlock);
699            PHINode* phiMatchLength = b->CreatePHI(initMatchLength->getType(), 2);
700            phiMatchLength->addIncoming(initMatchLength, beforeConBlock);
701            PHINode* phiOutputPos = b->CreatePHI(initOutputPos->getType(), 2);
702            phiOutputPos->addIncoming(initOutputPos, beforeConBlock);
703
704            b->CreateCondBr(b->CreateICmpUGT(phiMatchLength, b->getSize(0)), matchCopyBodyBlock, matchCopyExitBlock);
705
706            // ---- matchCopyBodyBlock
707            b->SetInsertPoint(matchCopyBodyBlock);
708            Value* copySize = b->CreateUMin(phiMatchLength, matchOffset);
709            Value* copyFromPos = b->CreateSub(phiOutputPos, matchOffset);
710
711            b->CreateMemCpy(
712                    b->CreateGEP(outputBasePtr, b->CreateURem(phiOutputPos, outputCapacity)),
713                    b->CreateGEP(outputBasePtr, b->CreateURem(copyFromPos, outputCapacity)),
714                    copySize,
715                    1
716            );
717
718            phiMatchLength->addIncoming(b->CreateSub(phiMatchLength, copySize), b->GetInsertBlock());
719            phiOutputPos->addIncoming(b->CreateAdd(phiOutputPos, copySize), b->GetInsertBlock());
720
721            b->CreateBr(matchCopyConBlock);
722
723            // ---- matchCopyExitBlock
724            b->SetInsertPoint(matchCopyExitBlock);
725        }
726    }
727
728    void LZ4ParallelByteStreamAioKernel::generateSimdSequentialMatchCopy(const std::unique_ptr<KernelBuilder> &b, llvm::Value* matchOffsetVec, llvm::Value* matchLengthVec, llvm::Value* outputPosVec) {
729
730        // Constant
731        Constant * SIZE_8 = b->getSize(8);
732        // Type
733        PointerType* i64PtrTy = b->getInt64Ty()->getPointerTo();
734        PointerType* i8PtrTy = b->getInt8PtrTy();
735
736        Value* outputCapacity = b->getCapacity("outputStream");
737        Value* outputPosRemVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(outputCapacity))));
738        Value* outputPosRemBlockSizeVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(b->getIntN(SIMD_WIDTH, mOutputBlockSize)))));
739        Value* remainingBlockSizeVec = b->simd_sub(SIMD_WIDTH, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, mOutputBlockSize)), outputPosRemBlockSizeVec);
740        Value* copyFromPosRemVec = b->simd_sub(SIMD_WIDTH, outputPosRemVec, matchOffsetVec);
741
742
743        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream", b->getSize(0)), b->getInt8PtrTy());
744
745
746        for (unsigned i = 0; i < b->getBitBlockWidth() / SIMD_WIDTH; i++) {
747
748            BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
749            BasicBlock* i64MatchCopyBlock = b->CreateBasicBlock("i64LiteralCopyBlock");
750            BasicBlock* i8MatchCopyBlock = b->CreateBasicBlock("i8LiteralCopyBlock");
751
752            // ---- entryBlock
753            Value* matchOffset = b->CreateExtractElement(matchOffsetVec, i);
754            Value* matchLength = b->CreateExtractElement(matchLengthVec, i);
755            Value* outputPosRem = b->CreateExtractElement(outputPosRemVec, i);
756            Value* remainingBlockSize = b->CreateExtractElement(remainingBlockSizeVec, i);
757            Value* outputFromRem = b->CreateExtractElement(copyFromPosRemVec, i);
758
759            Value* inputInitPtr = b->CreateGEP(outputBasePtr, outputFromRem);
760            Value* outputInitPtr = b->CreateGEP(outputBasePtr, outputPosRem);
761
762            b->CreateLikelyCondBr(b->CreateICmpUGE(b->CreateSub(remainingBlockSize, matchLength), SIZE_8), i64MatchCopyBlock, i8MatchCopyBlock);
763
764            //// i64 Match Copy
765            // ---- i64MatchCopyBlock
766            b->SetInsertPoint(i64MatchCopyBlock);
767
768            this->generateOverwritingMemcpy(b, inputInitPtr, outputInitPtr, matchLength, i64PtrTy, b->CreateUMin(matchOffset, SIZE_8));
769            b->CreateBr(exitBlock);
770
771            //// i8 Match Copy
772            // ---- i8MatchCopyBlock
773            b->SetInsertPoint(i8MatchCopyBlock);
774            this->generateOverwritingMemcpy(b, inputInitPtr, outputInitPtr, matchLength, i8PtrTy, 1);
775            b->CreateBr(exitBlock);
776
777            // ---- exitBlock
778            b->SetInsertPoint(exitBlock);
779
780        }
781
782    }
783
784    void LZ4ParallelByteStreamAioKernel::handleSimdMatchCopy(const std::unique_ptr<KernelBuilder> &b, llvm::Value* matchOffsetVec, llvm::Value* matchLengthVec, llvm::Value* outputPosVec) {
785//        this->generateSimdMatchCopyByMemcpy(b, matchOffsetVec, matchLengthVec, outputPosVec);
786        this->generateSimdSequentialMatchCopy(b, matchOffsetVec, matchLengthVec, outputPosVec);
787    }
788
789    void LZ4ParallelByteStreamAioKernel::handleSimdLiteralCopy(const std::unique_ptr<KernelBuilder> &b, llvm::Value* literalStartVec, llvm::Value* literalLengthVec, llvm::Value* outputPosVec) {
790        this->generateSimdSequentialLiteralCopy(b, literalStartVec, literalLengthVec, outputPosVec);
791//        this->generateSequentialLiteralCopyWithSimdCalculation(b, literalStartVec, literalLengthVec, outputPosVec);
792//        this->generateLiteralCopyByMemcpy(b, literalStartVec, literalLengthVec, outputPosVec);
793    }
794
795    void LZ4ParallelByteStreamAioKernel::generateSimdLiteralCopyByMemcpy(const std::unique_ptr<KernelBuilder> &b,
796                                                                         llvm::Value *literalStartVec,
797                                                                         llvm::Value *literalLengthVec,
798                                                                         llvm::Value *outputPosVec) {
799        // This function will be slower than other literal copy related function, it is only for performance testing.
800        Value* outputCapacity = b->getCapacity("outputStream");
801        Value* outputPosRemVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->simd_not(b->CreateNeg(outputCapacity))));
802
803        Value* inputBasePtr = b->CreatePointerCast(b->getRawInputPointer("byteStream", b->getSize(0)), b->getInt8PtrTy());
804        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream", b->getSize(0)), b->getInt8PtrTy());
805
806        for (uint64_t i = 0; i < b->getBitBlockWidth() / SIMD_WIDTH; i++) {
807            Value* literalStart = b->CreateExtractElement(literalStartVec, i);
808            Value* literalLength = b->CreateExtractElement(literalLengthVec, i);
809            Value* outputPosRem = b->CreateExtractElement(outputPosRemVec, i);;
810            b->CreateMemCpy(
811                    b->CreateGEP(outputBasePtr, outputPosRem),
812                    b->CreateGEP(inputBasePtr, literalStart),
813                    literalLength,
814                    1
815            );
816        }
817    }
818
819    void LZ4ParallelByteStreamAioKernel::generateSimdSequentialLiteralCopy(const std::unique_ptr<KernelBuilder> &b,
820                                                                           llvm::Value *literalStartVec,
821                                                                           llvm::Value *literalLengthVec,
822                                                                           llvm::Value *outputPosVec) {
823        // Constant
824        Constant * SIZE_8 = b->getSize(8);
825        // Type
826        PointerType* i64PtrTy = b->getInt64Ty()->getPointerTo();
827        PointerType* i8PtrTy = b->getInt8PtrTy();
828
829        Value* outputCapacity = b->getCapacity("outputStream");
830        Value* outputPosRemVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(outputCapacity))));
831        Value* outputPosRemBlockSizeVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(b->getIntN(SIMD_WIDTH, mOutputBlockSize)))));
832        Value* remainingBlockSizeVec = b->simd_sub(SIMD_WIDTH, b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, mOutputBlockSize)), outputPosRemBlockSizeVec);
833
834        Value* inputBasePtr = b->CreatePointerCast(b->getRawInputPointer("byteStream", b->getSize(0)), b->getInt8PtrTy());
835        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream", b->getSize(0)), b->getInt8PtrTy());
836
837
838        for (unsigned i = 0; i < b->getBitBlockWidth() / SIMD_WIDTH; i++) {
839            BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
840            BasicBlock* i64LiteralCopyBlock = b->CreateBasicBlock("i64LiteralCopyBlock");
841            BasicBlock* i8LiteralCopyBlock = b->CreateBasicBlock("i8LiteralCopyBlock");
842
843            // ---- entryBlock
844            Value* literalStart = b->CreateExtractElement(literalStartVec, i);
845            Value* literalLength = b->CreateExtractElement(literalLengthVec, i);
846            Value* outputPosRem = b->CreateExtractElement(outputPosRemVec, i);
847            Value* remainingBlockSize = b->CreateExtractElement(remainingBlockSizeVec, i);
848
849            Value* inputInitPtr = b->CreateGEP(inputBasePtr, literalStart);
850            Value* outputInitPtr = b->CreateGEP(outputBasePtr, outputPosRem);
851
852            b->CreateLikelyCondBr(b->CreateICmpUGE(b->CreateSub(remainingBlockSize, literalLength), SIZE_8), i64LiteralCopyBlock, i8LiteralCopyBlock);
853
854            //// i64 Literal Copy
855            // ---- i64LiteralCopyBlock
856            b->SetInsertPoint(i64LiteralCopyBlock);
857            this->generateOverwritingMemcpy(b, inputInitPtr, outputInitPtr, literalLength, i64PtrTy, 8);
858            b->CreateBr(exitBlock);
859
860            //// i8 Literal Copy
861            // ---- i8LiteralCopyBlock
862            b->SetInsertPoint(i8LiteralCopyBlock);
863            this->generateOverwritingMemcpy(b, inputInitPtr, outputInitPtr, literalLength, i8PtrTy, 1);
864            b->CreateBr(exitBlock);
865
866            // ---- exitBlock
867            b->SetInsertPoint(exitBlock);
868        }
869    }
870    void LZ4ParallelByteStreamAioKernel::generateOverwritingMemcpy(const std::unique_ptr<KernelBuilder> &b, llvm::Value *inputBasePtr,
871                                   llvm::Value *outputBasePtr, llvm::Value *copyBytes, llvm::PointerType *targetPtrTy,
872                                   llvm::Value* stepSize) {
873        unsigned targetPtrBitWidth = targetPtrTy->getElementType()->getIntegerBitWidth();
874
875        Constant * SIZE_0 = b->getSize(0);
876        Constant * SIZE_1 = b->getSize(1);
877        PointerType* i8PtrTy = b->getInt8PtrTy();
878
879        BasicBlock* entryBlock = b->GetInsertBlock();
880        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
881        BasicBlock* conBlock = b->CreateBasicBlock("conBlock");
882        BasicBlock* bodyBlock = b->CreateBasicBlock("bodyBlock");
883
884        Value* inputInitPtr = b->CreatePointerCast(inputBasePtr, targetPtrTy);
885        Value* outputInitPtr = b->CreatePointerCast(outputBasePtr, targetPtrTy);
886
887        b->CreateBr(conBlock);
888        // ---- conBlock
889        b->SetInsertPoint(conBlock);
890
891        PHINode *phiCopiedSize = b->CreatePHI(b->getSizeTy(), 2);
892        phiCopiedSize->addIncoming(SIZE_0, entryBlock);
893        PHINode *phiInputPtr = b->CreatePHI(targetPtrTy, 2);
894        phiInputPtr->addIncoming(inputInitPtr, entryBlock);
895        PHINode *phiOutputPtr = b->CreatePHI(targetPtrTy, 2);
896        phiOutputPtr->addIncoming(outputInitPtr, entryBlock);
897
898        b->CreateCondBr(b->CreateICmpULT(phiCopiedSize, copyBytes), bodyBlock, exitBlock);
899
900        // ---- bodyBlock
901        b->SetInsertPoint(bodyBlock);
902        b->CreateStore(b->CreateLoad(phiInputPtr), phiOutputPtr);
903
904        phiCopiedSize->addIncoming(b->CreateAdd(phiCopiedSize, stepSize), b->GetInsertBlock());
905
906        Value *newInputPtr = nullptr, *newOutputPtr = nullptr;
907
908        newInputPtr = b->CreatePointerCast(
909                b->CreateGEP(b->CreatePointerCast(phiInputPtr, i8PtrTy), stepSize),
910                targetPtrTy
911        );
912
913        newOutputPtr = b->CreatePointerCast(
914                b->CreateGEP(b->CreatePointerCast(phiOutputPtr, i8PtrTy), stepSize),
915                targetPtrTy
916        );
917
918        phiInputPtr->addIncoming(newInputPtr, b->GetInsertBlock());
919        phiOutputPtr->addIncoming(newOutputPtr, b->GetInsertBlock());
920        b->CreateBr(conBlock);
921
922        // ---- exitBlock
923        b->SetInsertPoint(exitBlock);
924    }
925
926    void LZ4ParallelByteStreamAioKernel::generateOverwritingMemcpy(const std::unique_ptr<KernelBuilder> &b,
927                                                                   llvm::Value *inputBasePtr,
928                                                                   llvm::Value *outputBasePtr,
929                                                                   llvm::Value *copyBytes, llvm::PointerType *targetPtrTy,
930                                                                   size_t stepSize) {
931        unsigned targetPtrBitWidth = targetPtrTy->getElementType()->getIntegerBitWidth();
932
933        Constant * SIZE_0 = b->getSize(0);
934        Constant * SIZE_1 = b->getSize(1);
935        PointerType* i8PtrTy = b->getInt8PtrTy();
936
937        BasicBlock* entryBlock = b->GetInsertBlock();
938        BasicBlock* exitBlock = b->CreateBasicBlock("exitBlock");
939        BasicBlock* conBlock = b->CreateBasicBlock("conBlock");
940        BasicBlock* bodyBlock = b->CreateBasicBlock("bodyBlock");
941
942        Value* inputInitPtr = b->CreatePointerCast(inputBasePtr, targetPtrTy);
943        Value* outputInitPtr = b->CreatePointerCast(outputBasePtr, targetPtrTy);
944
945        b->CreateBr(conBlock);
946        // ---- conBlock
947        b->SetInsertPoint(conBlock);
948
949        PHINode *phiCopiedSize = b->CreatePHI(b->getSizeTy(), 2);
950        phiCopiedSize->addIncoming(SIZE_0, entryBlock);
951        PHINode *phiInputPtr = b->CreatePHI(targetPtrTy, 2);
952        phiInputPtr->addIncoming(inputInitPtr, entryBlock);
953        PHINode *phiOutputPtr = b->CreatePHI(targetPtrTy, 2);
954        phiOutputPtr->addIncoming(outputInitPtr, entryBlock);
955
956        b->CreateCondBr(b->CreateICmpULT(phiCopiedSize, copyBytes), bodyBlock, exitBlock);
957
958        // ---- bodyBlock
959        b->SetInsertPoint(bodyBlock);
960        b->CreateStore(b->CreateLoad(phiInputPtr), phiOutputPtr);
961
962        phiCopiedSize->addIncoming(b->CreateAdd(phiCopiedSize, b->getSize(stepSize)), b->GetInsertBlock());
963
964        Value *newInputPtr = nullptr, *newOutputPtr = nullptr;
965
966        if (targetPtrBitWidth / 8 == stepSize) {
967            newInputPtr = b->CreateGEP(phiInputPtr, SIZE_1);
968            newOutputPtr = b->CreateGEP(phiOutputPtr, SIZE_1);
969        } else {
970            newInputPtr = b->CreatePointerCast(
971                    b->CreateGEP(b->CreatePointerCast(phiInputPtr, i8PtrTy), b->getSize(stepSize)),
972                    targetPtrTy
973            );
974
975            newOutputPtr = b->CreatePointerCast(
976                    b->CreateGEP(b->CreatePointerCast(phiOutputPtr, i8PtrTy), b->getSize(stepSize)),
977                    targetPtrTy
978            );
979
980        }
981
982        phiInputPtr->addIncoming(newInputPtr, b->GetInsertBlock());
983        phiOutputPtr->addIncoming(newOutputPtr, b->GetInsertBlock());
984        b->CreateBr(conBlock);
985
986        // ---- exitBlock
987        b->SetInsertPoint(exitBlock);
988    }
989
990    void LZ4ParallelByteStreamAioKernel::generateSimdLiteralCopyByScatter(const std::unique_ptr<KernelBuilder> &b,
991                                                                          llvm::Value *literalStartVec,
992                                                                          llvm::Value *literalLengthVec,
993                                                                          llvm::Value *outputPosVec) {
994        // TODO
995    }
996
997    void LZ4ParallelByteStreamAioKernel::generateSimdSequentialLiteralCopyWithSimdCalculation(
998            const std::unique_ptr<KernelBuilder> &b, llvm::Value *literalStartVec, llvm::Value *literalLengthVec,
999            llvm::Value *outputPosVec) {
1000        // TODO Incomplete
1001
1002        /*
1003        Value* outputCapacity = b->getCapacity("outputStream");
1004        Value* outputPosRemVec = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(outputCapacity))));
1005        Value* outputPosRemOutputBlockSize = b->simd_and(outputPosVec, b->simd_fill(SIMD_WIDTH, b->CreateNot(b->CreateNeg(b->getIntN(SIMD_WIDTH, mOutputBlockSize)))));
1006
1007
1008
1009        Value* inputBasePtr = b->CreatePointerCast(b->getRawInputPointer("byteStream", b->getSize(0)), b->getInt8PtrTy());
1010        Value* outputBasePtr = b->CreatePointerCast(b->getRawOutputPointer("outputStream", b->getSize(0)), b->getInt8PtrTy());
1011
1012        ////
1013        // ---- i64LiteralCopy
1014        BasicBlock* i64LiteralCopyCon = b->CreateBasicBlock("literalCopyCon");
1015        BasicBlock* i64LiteralCopyBody = b->CreateBasicBlock("literalCopyBody");
1016        BasicBlock* i64LiteralCopyExit = b->CreateBasicBlock("literalCopyExit");
1017
1018        b->CreateBr(i64LiteralCopyCon);
1019
1020        // ---- i64LiteralCopyCon
1021        b->SetInsertPoint(i64LiteralCopyCon);
1022
1023
1024        // ---- literalCopyBody
1025        b->SetInsertPoint(i64LiteralCopyBody);
1026
1027        // ---- literalCopyExit
1028        b->SetInsertPoint(i64LiteralCopyExit);
1029
1030
1031        //// ---- i8LiteralCopyCon
1032         */
1033    }
1034
1035    void LZ4ParallelByteStreamAioKernel::handleLiteralCopy(const std::unique_ptr<KernelBuilder> &b, llvm::Value *literalStart,
1036                                                   llvm::Value *literalLength, llvm::Value* outputPos) {
1037        unsigned fw = 64;
1038        Type* INT_FW_PTR = b->getIntNTy(fw)->getPointerTo();
1039
1040        Value* inputBytePtr = b->getRawInputPointer("byteStream", literalStart);
1041        Value* inputPtr = b->CreatePointerCast(inputBytePtr, INT_FW_PTR);
1042
1043        Value* outputBufferSize = b->getCapacity("outputStream");
1044        Value* outputPtr = b->getRawOutputPointer("outputStream", b->CreateURem(outputPos, outputBufferSize));
1045        outputPtr = b->CreatePointerCast(outputPtr, INT_FW_PTR);
1046
1047        // We can always assume that we have enough output buffer based on our output buffer allocation strategy (except in extract only case)
1048
1049        BasicBlock* entryBlock = b->GetInsertBlock();
1050        BasicBlock* literalCopyCon = b->CreateBasicBlock("literalCopyCon");
1051        BasicBlock* literalCopyBody = b->CreateBasicBlock("literalCopyBody");
1052        BasicBlock* literalCopyExit = b->CreateBasicBlock("literalCopyExit");
1053
1054        b->CreateBr(literalCopyCon);
1055
1056        // ---- literalCopyCon
1057        b->SetInsertPoint(literalCopyCon);
1058        PHINode* phiOutputPtr = b->CreatePHI(outputPtr->getType(), 2);
1059        phiOutputPtr->addIncoming(outputPtr, entryBlock);
1060        PHINode* phiInputPtr = b->CreatePHI(inputPtr->getType(), 2);
1061        phiInputPtr->addIncoming(inputPtr, entryBlock);
1062        PHINode* phiCopiedLength = b->CreatePHI(literalLength->getType(), 2);
1063        phiCopiedLength->addIncoming(b->getSize(0), entryBlock);
1064        b->CreateCondBr(b->CreateICmpULT(phiCopiedLength, literalLength), literalCopyBody, literalCopyExit);
1065
1066        // ---- literalCopyBody
1067        b->SetInsertPoint(literalCopyBody);
1068        // Always copy fw bits to improve performance
1069        b->CreateStore(b->CreateLoad(phiInputPtr), phiOutputPtr);
1070
1071        phiInputPtr->addIncoming(b->CreateGEP(phiInputPtr, b->getSize(1)), b->GetInsertBlock());
1072        phiOutputPtr->addIncoming(b->CreateGEP(phiOutputPtr, b->getSize(1)), b->GetInsertBlock());
1073        phiCopiedLength->addIncoming(b->CreateAdd(phiCopiedLength, b->getSize(fw / 8)), b->GetInsertBlock());
1074        b->CreateBr(literalCopyCon);
1075
1076        // ---- literalCopyExit
1077        b->SetInsertPoint(literalCopyExit);
1078        b->setScalarField("outputPos", b->CreateAdd(outputPos, literalLength));
1079    }
1080
1081    void LZ4ParallelByteStreamAioKernel::handleMatchCopy(const std::unique_ptr<KernelBuilder> &b, llvm::Value *matchOffset,
1082                                                 llvm::Value *matchLength, llvm::Value* outputPos) {
1083        unsigned fw = 64;
1084        Type* INT_FW_PTR = b->getIntNTy(fw)->getPointerTo();
1085
1086        BasicBlock* entryBlock = b->GetInsertBlock();
1087
1088        Value* outputBufferSize = b->getCapacity("outputStream");
1089
1090        Value* copyToPtr = b->getRawOutputPointer("outputStream", b->CreateURem(outputPos, outputBufferSize));
1091        Value* copyFromPtr = b->getRawOutputPointer("outputStream", b->CreateURem(b->CreateSub(outputPos, matchOffset), outputBufferSize));
1092
1093        BasicBlock* matchCopyCon = b->CreateBasicBlock("matchCopyCon");
1094        BasicBlock* matchCopyBody = b->CreateBasicBlock("matchCopyBody");
1095        BasicBlock* matchCopyExit = b->CreateBasicBlock("matchCopyExit");
1096
1097        b->CreateBr(matchCopyCon);
1098
1099        // ---- matchCopyCon
1100        b->SetInsertPoint(matchCopyCon);
1101        PHINode* phiFromPtr = b->CreatePHI(b->getInt8PtrTy(), 2);
1102        phiFromPtr->addIncoming(copyFromPtr, entryBlock);
1103        PHINode* phiToPtr = b->CreatePHI(b->getInt8PtrTy(), 2);
1104        phiToPtr->addIncoming(copyToPtr, entryBlock);
1105        PHINode* phiCopiedSize = b->CreatePHI(b->getSizeTy(), 2);
1106        phiCopiedSize->addIncoming(b->getSize(0), entryBlock);
1107
1108        b->CreateCondBr(b->CreateICmpULT(phiCopiedSize, matchLength), matchCopyBody, matchCopyExit);
1109
1110        // ---- matchCopyBody
1111        b->SetInsertPoint(matchCopyBody);
1112        b->CreateStore(
1113                b->CreateLoad(b->CreatePointerCast(phiFromPtr, INT_FW_PTR)),
1114                b->CreatePointerCast(phiToPtr, INT_FW_PTR)
1115        );
1116
1117        Value* copySize = b->CreateUMin(matchOffset, b->getSize(fw / 8));
1118        phiFromPtr->addIncoming(b->CreateGEP(phiFromPtr, copySize), b->GetInsertBlock());
1119        phiToPtr->addIncoming(b->CreateGEP(phiToPtr, copySize), b->GetInsertBlock());
1120        phiCopiedSize->addIncoming(b->CreateAdd(phiCopiedSize, copySize), b->GetInsertBlock());
1121        b->CreateBr(matchCopyCon);
1122
1123        // ---- matchCopyExit
1124        b->SetInsertPoint(matchCopyExit);
1125        b->setScalarField("outputPos", b->CreateAdd(outputPos, matchLength));
1126    }
1127
1128    llvm::Value* LZ4ParallelByteStreamAioKernel::simdFetchByteData(const std::unique_ptr<KernelBuilder> &b, llvm::Value* basePtr, llvm::Value* offsetVec, llvm::Value* mask) {
1129        return this->simdFetchByteDataByGather(b, basePtr, offsetVec, mask);
1130//        return this->simdFetchByteDataByLoop(b, basePtr, offsetVec, mask);
1131    }
1132
1133    llvm::Value* LZ4ParallelByteStreamAioKernel::simdFetchByteDataByGather(const std::unique_ptr<KernelBuilder> &b, llvm::Value* basePtr, llvm::Value* offsetVec, llvm::Value* mask) {
1134        Value* BIT_BLOCK_FF = b->simd_fill(SIMD_WIDTH, b->getIntN(SIMD_WIDTH, 0xff));
1135//        Function *gatherFunc = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_avx2_gather_d_q_256);
1136        Function *gatherFunc2 = Intrinsic::getDeclaration(b->getModule(), Intrinsic::x86_avx2_gather_d_d);
1137
1138        Value* firstOffset = b->CreateExtractElement(offsetVec, (uint64_t)0);
1139
1140        Type* i32BitBlockTy = VectorType::get(b->getInt32Ty(), 4);
1141
1142//        Value* tokenValuesVec =  b->CreateCall(
1143//                gatherFunc,
1144//                {
1145//                        UndefValue::get(b->getBitBlockType()),
1146//                        b->CreateGEP(basePtr, firstOffset),
1147//                        b->CreateTrunc(b->CreateSub(offsetVec, b->simd_fill(SIMD_WIDTH, firstOffset)), VectorType::get(b->getInt32Ty(), 4)),
1148//                        mask,
1149//                        b->getInt8(1)
1150//                }
1151//        );
1152
1153        ////
1154        Value* tokenValuesVec =  b->CreateCall(
1155                gatherFunc2,
1156                {
1157                        UndefValue::get(i32BitBlockTy),
1158                        b->CreateGEP(basePtr, firstOffset),
1159                        b->CreateTrunc(b->CreateSub(offsetVec, b->simd_fill(SIMD_WIDTH, firstOffset)), VectorType::get(b->getInt32Ty(), 4)),
1160                        b->CreateTrunc(mask, i32BitBlockTy),
1161                        b->getInt8(1)
1162                }
1163        );
1164        tokenValuesVec = b->CreateZExt(tokenValuesVec, b->getBitBlockType());
1165        /////
1166       
1167        tokenValuesVec = b->CreateAnd(tokenValuesVec, mask);
1168        tokenValuesVec = b->CreateAnd(tokenValuesVec, BIT_BLOCK_FF);
1169        return tokenValuesVec;
1170    }
1171
1172    llvm::Value* LZ4ParallelByteStreamAioKernel::simdFetchByteDataByLoop(const std::unique_ptr<KernelBuilder> &b, llvm::Value* basePtr, llvm::Value* offsetVec, llvm::Value* maskVec) {
1173        Value* retVec = ConstantVector::getNullValue(b->getBitBlockType());
1174
1175        for (uint64_t i = 0; i < 4; i++){ //TODO 4 here is a hardcode for AVX2, it may need to be changed to (BitBlockWidth / 64)
1176            Value* mask = b->CreateExtractElement(maskVec, i);
1177            Value* shouldLoad = b->CreateICmpNE(mask, b->getInt64(0));
1178            Value* loadPtr = b->CreateSelect(shouldLoad, b->CreateGEP(basePtr, b->CreateExtractElement(offsetVec, i)), basePtr);
1179            Value* loadValue = b->CreateZExt(b->CreateLoad(loadPtr), b->getInt64Ty());
1180
1181            Value* finalValue = b->CreateSelect(shouldLoad, loadValue, b->getInt64(0));
1182            retVec = b->CreateInsertElement(retVec, finalValue, i);
1183        }
1184
1185        return retVec;
1186    }
1187
1188}
Note: See TracBrowser for help on using the repository browser.