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

Last change on this file since 6082 was 6082, checked in by xwa163, 12 months ago

One missing line for AVX512 bug fixing

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