source: icGREP/icgrep-devel/icgrep/kernels/kernel.cpp @ 5171

Last change on this file since 5171 was 5171, checked in by lindanl, 3 years ago

Tiny fix of error message.

File size: 20.5 KB
Line 
1/*
2 *  Copyright (c) 2016 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5
6#include "kernel.h"
7#include <llvm/IR/Module.h>
8#include <llvm/IR/Type.h>
9#include <llvm/IR/Value.h>
10#include <llvm/Support/raw_ostream.h>
11#include <llvm/IR/TypeBuilder.h>
12#include <toolchain.h>
13
14using namespace llvm;
15using namespace kernel;
16
17KernelBuilder::KernelBuilder(IDISA::IDISA_Builder * builder,
18                                 std::string kernelName,
19                                 std::vector<StreamSetBinding> stream_inputs,
20                                 std::vector<StreamSetBinding> stream_outputs,
21                                 std::vector<ScalarBinding> scalar_parameters,
22                                 std::vector<ScalarBinding> scalar_outputs,
23                                 std::vector<ScalarBinding> internal_scalars) :
24    KernelInterface(builder, kernelName, stream_inputs, stream_outputs, scalar_parameters, scalar_outputs, internal_scalars) {}
25
26void KernelBuilder::addScalar(Type * t, std::string scalarName) {
27    if (LLVM_UNLIKELY(mKernelStateType != nullptr)) {
28        throw std::runtime_error("Illegal addition of kernel field after kernel state finalized: " + scalarName);
29    }
30    unsigned index = mKernelFields.size();
31    mKernelFields.push_back(t);
32    mInternalStateNameMap.emplace(scalarName, index);
33}
34
35void KernelBuilder::prepareKernel() {
36    unsigned blockSize = iBuilder->getBitBlockWidth();
37    if (mStreamSetInputs.size() != mStreamSetInputBuffers.size()) {
38        throw std::runtime_error("Kernel preparation: Incorrect number of input buffers");
39    }
40    if (mStreamSetOutputs.size() != mStreamSetOutputBuffers.size()) {
41        throw std::runtime_error("Kernel preparation: Incorrect number of output buffers");
42    }
43    addScalar(iBuilder->getSizeTy(), blockNoScalar);
44    int streamSetNo = 0;
45    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
46        size_t bufferSize = mStreamSetInputBuffers[i]->getBufferSize() * blockSize;
47        if (!(mStreamSetInputBuffers[i]->getBufferStreamSetType() == mStreamSetInputs[i].ssType)) {
48             throw std::runtime_error("Kernel preparation: Incorrect input buffer type");
49        }
50        if ((bufferSize > 0) && (bufferSize < codegen::SegmentSize + (blockSize + mLookAheadPositions - 1)/blockSize)) {
51             errs() << "buffer size = " << mStreamSetInputBuffers[i]->getBufferSize() << "\n";
52             throw std::runtime_error("Kernel preparation: Buffer size too small.");
53        }
54
55        mScalarInputs.push_back(ScalarBinding{mStreamSetInputBuffers[i]->getStreamSetStructPointerType(), mStreamSetInputs[i].ssName + basePtrSuffix});
56        mStreamSetNameMap.emplace(mStreamSetInputs[i].ssName, streamSetNo);
57        streamSetNo++;
58    }
59    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
60        if (!(mStreamSetOutputBuffers[i]->getBufferStreamSetType() == mStreamSetOutputs[i].ssType)) {
61             throw std::runtime_error("Kernel preparation: Incorrect output buffer type");
62        }
63        mScalarInputs.push_back(ScalarBinding{mStreamSetOutputBuffers[i]->getStreamSetStructPointerType(), mStreamSetOutputs[i].ssName + basePtrSuffix});
64        mStreamSetNameMap.emplace(mStreamSetOutputs[i].ssName, streamSetNo);
65        streamSetNo++;
66    }
67    for (auto binding : mScalarInputs) {
68        addScalar(binding.scalarType, binding.scalarName);
69    }
70    for (auto binding : mScalarOutputs) {
71        addScalar(binding.scalarType, binding.scalarName);
72    }
73    for (auto binding : mInternalScalars) {
74        addScalar(binding.scalarType, binding.scalarName);
75    }
76    mKernelStateType = StructType::create(getGlobalContext(), mKernelFields, mKernelName);
77}
78
79std::unique_ptr<Module> KernelBuilder::createKernelModule(std::vector<StreamSetBuffer *> input_buffers, std::vector<StreamSetBuffer *> output_buffers) {
80    Module * saveModule = iBuilder->getModule();
81    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
82    std::unique_ptr<Module> theModule = make_unique<Module>(mKernelName + "_" + iBuilder->getBitBlockTypeName(), getGlobalContext());
83    Module * m = theModule.get();
84    iBuilder->setModule(m);
85    generateKernel(input_buffers, output_buffers);
86    iBuilder->setModule(saveModule);
87    iBuilder->restoreIP(savePoint);
88    return theModule;
89}
90
91void KernelBuilder::generateKernel(std::vector<StreamSetBuffer *> input_buffers, std::vector<StreamSetBuffer*> output_buffers) {
92    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
93    Module * m = iBuilder->getModule();
94    mStreamSetInputBuffers = input_buffers;
95    mStreamSetOutputBuffers = output_buffers;
96    prepareKernel();  // possibly overriden by the KernelBuilder subtype
97    KernelInterface::addKernelDeclarations(m);
98    generateDoBlockMethod();     // must be implemented by the KernelBuilder subtype
99    generateFinalBlockMethod();  // possibly overriden by the KernelBuilder subtype
100    generateDoSegmentMethod();
101
102    // Implement the accumulator get functions
103    for (auto binding : mScalarOutputs) {
104        auto fnName = mKernelName + accumulator_infix + binding.scalarName;
105        Function * accumFn = m->getFunction(fnName);
106        iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "get_" + binding.scalarName, accumFn, 0));
107        Value * self = &*(accumFn->arg_begin());
108        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(binding.scalarName)});
109        Value * retVal = iBuilder->CreateLoad(ptr);
110        iBuilder->CreateRet(retVal);
111    }
112    // Implement the initializer function
113    Function * initFunction = m->getFunction(mKernelName + init_suffix);
114    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "Init_entry", initFunction, 0));
115   
116    Function::arg_iterator args = initFunction->arg_begin();
117    Value * self = &*(args++);
118    iBuilder->CreateStore(Constant::getNullValue(mKernelStateType), self);
119    for (auto binding : mScalarInputs) {
120        Value * parm = &*(args++);
121        Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(binding.scalarName)});
122        iBuilder->CreateStore(parm, ptr);
123    }
124    iBuilder->CreateRetVoid();
125    iBuilder->restoreIP(savePoint);
126}
127
128//  The default finalBlock method simply dispatches to the doBlock routine.
129void KernelBuilder::generateFinalBlockMethod() {
130    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
131    Module * m = iBuilder->getModule();
132    Function * doBlockFunction = m->getFunction(mKernelName + doBlock_suffix);
133    Function * finalBlockFunction = m->getFunction(mKernelName + finalBlock_suffix);
134    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "fb_entry", finalBlockFunction, 0));
135    // Final Block arguments: self, remaining, then the standard DoBlock args.
136    Function::arg_iterator args = finalBlockFunction->arg_begin();
137    Value * self = &*(args++);
138    /* Skip "remaining" arg */ args++;
139    std::vector<Value *> doBlockArgs = {self};
140    while (args != finalBlockFunction->arg_end()){
141        doBlockArgs.push_back(&*args++);
142    }
143    iBuilder->CreateCall(doBlockFunction, doBlockArgs);
144    iBuilder->CreateRetVoid();
145    iBuilder->restoreIP(savePoint);
146}
147
148//  The default doSegment method simply dispatches to the doBlock routine.
149void KernelBuilder::generateDoSegmentMethod() {
150    IDISA::IDISA_Builder::InsertPoint savePoint = iBuilder->saveIP();
151    Module * m = iBuilder->getModule();
152    Function * doBlockFunction = m->getFunction(mKernelName + doBlock_suffix);
153    Function * doSegmentFunction = m->getFunction(mKernelName + doSegment_suffix);
154    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", doSegmentFunction, 0));
155    BasicBlock * entryBlock = iBuilder->GetInsertBlock();
156    BasicBlock * blockLoopCond = BasicBlock::Create(iBuilder->getContext(), "blockLoopCond", doSegmentFunction, 0);
157    BasicBlock * blockLoopBody = BasicBlock::Create(iBuilder->getContext(), "blockLoopBody", doSegmentFunction, 0);
158    BasicBlock * blocksDone = BasicBlock::Create(iBuilder->getContext(), "blocksDone", doSegmentFunction, 0);
159    Type * const size_ty = iBuilder->getSizeTy();
160   
161    Function::arg_iterator args = doSegmentFunction->arg_begin();
162    Value * self = &*(args++);
163    Value * blocksToDo = &*(args);
164   
165    iBuilder->CreateBr(blockLoopCond);
166
167    iBuilder->SetInsertPoint(blockLoopCond);
168    PHINode * blocksRemaining = iBuilder->CreatePHI(size_ty, 2, "blocksRemaining");
169    blocksRemaining->addIncoming(blocksToDo, entryBlock);
170    Value * notDone = iBuilder->CreateICmpUGT(blocksRemaining, ConstantInt::get(size_ty, 0));
171    iBuilder->CreateCondBr(notDone, blockLoopBody, blocksDone);
172
173    iBuilder->SetInsertPoint(blockLoopBody);
174    Value * blockNo = getScalarField(self, blockNoScalar);   
175    iBuilder->CreateCall(doBlockFunction, {self});
176    setBlockNo(self, iBuilder->CreateAdd(blockNo, ConstantInt::get(size_ty, iBuilder->getStride() / iBuilder->getBitBlockWidth())));
177    blocksRemaining->addIncoming(iBuilder->CreateSub(blocksRemaining, ConstantInt::get(size_ty, 1)), blockLoopBody);
178    iBuilder->CreateBr(blockLoopCond);
179   
180    iBuilder->SetInsertPoint(blocksDone);
181    iBuilder->CreateRetVoid();
182    iBuilder->restoreIP(savePoint);
183}
184
185Value * KernelBuilder::getScalarIndex(std::string fieldName) {
186    const auto f = mInternalStateNameMap.find(fieldName);
187    if (LLVM_UNLIKELY(f == mInternalStateNameMap.end())) {
188        throw std::runtime_error("Kernel does not contain internal state: " + fieldName);
189    }
190    return iBuilder->getInt32(f->second);
191}
192
193
194
195Value * KernelBuilder::getScalarField(Value * self, std::string fieldName) {
196    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(fieldName)});
197    return iBuilder->CreateLoad(ptr);
198}
199
200void KernelBuilder::setScalarField(Value * self, std::string fieldName, Value * newFieldVal) {
201    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(fieldName)});
202    iBuilder->CreateStore(newFieldVal, ptr);
203}
204
205Value * KernelBuilder::getBlockNo(Value * self) {
206    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
207    LoadInst * blockNo = iBuilder->CreateAlignedLoad(ptr, 8);
208    blockNo->setOrdering(Acquire);
209    return blockNo;
210}
211
212void KernelBuilder::setBlockNo(Value * self, Value * newFieldVal) {
213    Value * ptr = iBuilder->CreateGEP(self, {iBuilder->getInt32(0), getScalarIndex(blockNoScalar)});
214    iBuilder->CreateAlignedStore(newFieldVal, ptr, 8)->setOrdering(Release);
215}
216
217
218Value * KernelBuilder::getParameter(Function * f, std::string paramName) {
219    for (Function::arg_iterator argIter = f->arg_begin(), end = f->arg_end(); argIter != end; argIter++) {
220        Value * arg = &*argIter;
221        if (arg->getName() == paramName) return arg;
222    }
223    throw std::runtime_error("Method does not have parameter: " + paramName);
224}
225
226unsigned KernelBuilder::getStreamSetIndex(std::string ssName) {
227    const auto f = mStreamSetNameMap.find(ssName);
228    if (LLVM_UNLIKELY(f == mStreamSetNameMap.end())) {
229        throw std::runtime_error("Kernel does not contain stream set: " + ssName);
230    }
231    return f->second;
232}
233
234size_t KernelBuilder::getStreamSetBufferSize(Value * self, std::string ssName) {
235    unsigned ssIndex = getStreamSetIndex(ssName);
236    if (ssIndex < mStreamSetInputs.size()) {
237        return mStreamSetInputBuffers[ssIndex]->getBufferSize();
238    }
239    else {
240        return mStreamSetOutputBuffers[ssIndex - mStreamSetInputs.size()]->getBufferSize();
241    }
242}
243
244Value * KernelBuilder::getStreamSetBasePtr(Value * self, std::string ssName) {
245    return getScalarField(self, ssName + basePtrSuffix);
246}
247
248Value * KernelBuilder::getStreamSetBlockPtr(Value * self, std::string ssName, Value * blockNo) {
249    Value * basePtr = getStreamSetBasePtr(self, ssName);
250    unsigned ssIndex = getStreamSetIndex(ssName);
251    if (ssIndex < mStreamSetInputs.size()) {
252        return mStreamSetInputBuffers[ssIndex]->getStreamSetBlockPointer(basePtr, blockNo);
253    }
254    else {
255        return mStreamSetOutputBuffers[ssIndex - mStreamSetInputs.size()]->getStreamSetBlockPointer(basePtr, blockNo);
256    }
257}
258
259Value * KernelBuilder::createInstance(std::vector<Value *> args) {
260    Value * kernelInstance = iBuilder->CreateAlloca(mKernelStateType);
261    Module * m = iBuilder->getModule();
262    std::vector<Value *> init_args = {kernelInstance};
263    for (auto a : args) {
264        init_args.push_back(a);
265    }
266    for (auto b : mStreamSetInputBuffers) { 
267        init_args.push_back(b->getStreamSetStructPtr());
268    }
269    for (auto b : mStreamSetOutputBuffers) { 
270        init_args.push_back(b->getStreamSetStructPtr());
271    }
272    std::string initFnName = mKernelName + init_suffix;
273    Function * initMethod = m->getFunction(initFnName);
274    if (!initMethod) {
275        throw std::runtime_error("Cannot find " + initFnName);
276    }
277    iBuilder->CreateCall(initMethod, init_args);
278    return kernelInstance;
279}
280
281Function * KernelBuilder::generateThreadFunction(std::string name){
282    Module * m = iBuilder->getModule();
283    Type * const voidTy = Type::getVoidTy(m->getContext());
284    Type * const voidPtrTy = TypeBuilder<void *, false>::get(m->getContext());
285    Type * const int8PtrTy = iBuilder->getInt8PtrTy();
286    Type * const int1ty = iBuilder->getInt1Ty();
287
288    Function * const threadFunc = cast<Function>(m->getOrInsertFunction(name, voidTy, int8PtrTy, nullptr));
289    threadFunc->setCallingConv(CallingConv::C);
290    Function::arg_iterator args = threadFunc->arg_begin();
291
292    Value * const arg = &*(args++);
293    arg->setName("args");
294
295    iBuilder->SetInsertPoint(BasicBlock::Create(iBuilder->getContext(), "entry", threadFunc,0));
296
297    Value * self = iBuilder->CreateBitCast(arg, PointerType::get(mKernelStateType, 0));
298
299    std::vector<Value *> inbufProducerPtrs;
300    std::vector<Value *> inbufConsumerPtrs;
301    std::vector<Value *> outbufProducerPtrs;
302    std::vector<Value *> outbufConsumerPtrs;   
303    std::vector<Value *> endSignalPtrs;
304
305    for (unsigned i = 0; i < mStreamSetInputs.size(); i++) {
306        Value * basePtr = getStreamSetBasePtr(self, mStreamSetInputs[i].ssName);
307        inbufProducerPtrs.push_back(mStreamSetInputBuffers[i]->getProducerPosPtr(basePtr));
308        inbufConsumerPtrs.push_back(mStreamSetInputBuffers[i]->getComsumerPosPtr(basePtr));
309        endSignalPtrs.push_back(mStreamSetInputBuffers[i]->hasEndOfInputPtr(basePtr));
310    }
311    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
312        Value * basePtr = getStreamSetBasePtr(self, mStreamSetOutputs[i].ssName);
313        outbufProducerPtrs.push_back(mStreamSetOutputBuffers[i]->getProducerPosPtr(basePtr));
314        outbufConsumerPtrs.push_back(mStreamSetOutputBuffers[i]->getComsumerPosPtr(basePtr));
315    }
316
317    const unsigned segmentBlocks = codegen::SegmentSize;
318    const unsigned bufferSegments = codegen::BufferSegments;
319    const unsigned segmentSize = segmentBlocks * iBuilder->getBitBlockWidth();
320    Type * const size_ty = iBuilder->getSizeTy();
321
322    Value * segSize = ConstantInt::get(size_ty, segmentSize);
323    Value * bufferSize = ConstantInt::get(size_ty, segmentSize * (bufferSegments - 1));
324    Value * segBlocks = ConstantInt::get(size_ty, segmentBlocks);
325   
326    BasicBlock * outputCheckBlock = BasicBlock::Create(iBuilder->getContext(), "outputCheck", threadFunc, 0);
327    BasicBlock * inputCheckBlock = BasicBlock::Create(iBuilder->getContext(), "inputCheck", threadFunc, 0);
328   
329    BasicBlock * endSignalCheckBlock = BasicBlock::Create(iBuilder->getContext(), "endSignalCheck", threadFunc, 0);
330    BasicBlock * doSegmentBlock = BasicBlock::Create(iBuilder->getContext(), "doSegment", threadFunc, 0);
331    BasicBlock * endBlock = BasicBlock::Create(iBuilder->getContext(), "end", threadFunc, 0);
332    BasicBlock * doFinalSegBlock = BasicBlock::Create(iBuilder->getContext(), "doFinalSeg", threadFunc, 0);
333    BasicBlock * doFinalBlock = BasicBlock::Create(iBuilder->getContext(), "doFinal", threadFunc, 0);
334
335    iBuilder->CreateBr(outputCheckBlock);
336
337    iBuilder->SetInsertPoint(outputCheckBlock);
338
339    Value * waitCondTest = ConstantInt::get(int1ty, 1);   
340    for (unsigned i = 0; i < outbufProducerPtrs.size(); i++) {
341        LoadInst * producerPos = iBuilder->CreateAlignedLoad(outbufProducerPtrs[i], 8);
342        producerPos->setOrdering(Acquire);
343        // iBuilder->CallPrintInt(name + ":output producerPos", producerPos);
344        LoadInst * consumerPos = iBuilder->CreateAlignedLoad(outbufConsumerPtrs[i], 8);
345        consumerPos->setOrdering(Acquire);
346        // iBuilder->CallPrintInt(name + ":output consumerPos", consumerPos);
347        waitCondTest = iBuilder->CreateAnd(waitCondTest, iBuilder->CreateICmpULE(producerPos, iBuilder->CreateAdd(consumerPos, bufferSize)));
348    }
349   
350    iBuilder->CreateCondBr(waitCondTest, inputCheckBlock, outputCheckBlock); 
351
352    iBuilder->SetInsertPoint(inputCheckBlock); 
353
354    waitCondTest = ConstantInt::get(int1ty, 1); 
355    for (unsigned i = 0; i < inbufProducerPtrs.size(); i++) {
356        LoadInst * producerPos = iBuilder->CreateAlignedLoad(inbufProducerPtrs[i], 8);
357        producerPos->setOrdering(Acquire);
358        // iBuilder->CallPrintInt(name + ":input producerPos", producerPos);
359        LoadInst * consumerPos = iBuilder->CreateAlignedLoad(inbufConsumerPtrs[i], 8);
360        consumerPos->setOrdering(Acquire);
361        // iBuilder->CallPrintInt(name + ":input consumerPos", consumerPos);
362        waitCondTest = iBuilder->CreateAnd(waitCondTest, iBuilder->CreateICmpULE(iBuilder->CreateAdd(consumerPos, segSize), producerPos));
363    }
364
365    iBuilder->CreateCondBr(waitCondTest, doSegmentBlock, endSignalCheckBlock);
366   
367    iBuilder->SetInsertPoint(endSignalCheckBlock);
368   
369    LoadInst * endSignal = iBuilder->CreateAlignedLoad(endSignalPtrs[0], 8);
370    // iBuilder->CallPrintInt(name + ":endSignal", endSignal);
371    endSignal->setOrdering(Acquire);
372    for (unsigned i = 1; i < endSignalPtrs.size(); i++){
373        LoadInst * endSignal_next = iBuilder->CreateAlignedLoad(endSignalPtrs[i], 8);
374        endSignal_next->setOrdering(Acquire);
375        iBuilder->CreateAnd(endSignal, endSignal_next);
376    }
377       
378    iBuilder->CreateCondBr(iBuilder->CreateICmpEQ(endSignal, ConstantInt::get(iBuilder->getInt8Ty(), 1)), endBlock, inputCheckBlock);
379   
380    iBuilder->SetInsertPoint(doSegmentBlock);
381 
382    createDoSegmentCall(self, segBlocks);
383
384    for (unsigned i = 0; i < inbufConsumerPtrs.size(); i++) {
385        Value * consumerPos = iBuilder->CreateAdd(iBuilder->CreateLoad(inbufConsumerPtrs[i]), segSize);
386        iBuilder->CreateAlignedStore(consumerPos, inbufConsumerPtrs[i], 8)->setOrdering(Release);
387    }
388    for (unsigned i = 0; i < outbufProducerPtrs.size(); i++) {
389        Value * producerPos = iBuilder->CreateAdd(iBuilder->CreateLoad(outbufProducerPtrs[i]), segSize);
390        iBuilder->CreateAlignedStore(producerPos, outbufProducerPtrs[i], 8)->setOrdering(Release);
391    }
392   
393    iBuilder->CreateBr(outputCheckBlock);
394     
395    iBuilder->SetInsertPoint(endBlock);
396    LoadInst * producerPos = iBuilder->CreateLoad(inbufProducerPtrs[0]);
397    LoadInst * consumerPos = iBuilder->CreateLoad(inbufConsumerPtrs[0]);
398    Value * remainingBytes = iBuilder->CreateSub(producerPos, consumerPos);
399    Value * blockSize = ConstantInt::get(size_ty, iBuilder->getBitBlockWidth());
400    Value * blocks = iBuilder->CreateUDiv(remainingBytes, blockSize);
401    Value * finalBlockRemainingBytes = iBuilder->CreateURem(remainingBytes, blockSize);
402
403    iBuilder->CreateCondBr(iBuilder->CreateICmpEQ(blocks, ConstantInt::get(size_ty, 0)), doFinalBlock, doFinalSegBlock);
404
405    iBuilder->SetInsertPoint(doFinalSegBlock);
406
407    createDoSegmentCall(self, blocks);
408
409    iBuilder->CreateBr(doFinalBlock);
410
411    iBuilder->SetInsertPoint(doFinalBlock);
412
413    createFinalBlockCall(self, finalBlockRemainingBytes);
414
415    for (unsigned i = 0; i < inbufConsumerPtrs.size(); i++) {
416        Value * consumerPos = iBuilder->CreateAdd(iBuilder->CreateLoad(inbufConsumerPtrs[i]), remainingBytes);
417        iBuilder->CreateAlignedStore(consumerPos, inbufConsumerPtrs[i], 8)->setOrdering(Release);
418    }
419    for (unsigned i = 0; i < outbufProducerPtrs.size(); i++) {
420        Value * producerPos = iBuilder->CreateAdd(iBuilder->CreateLoad(outbufProducerPtrs[i]), remainingBytes);
421        iBuilder->CreateAlignedStore(producerPos, outbufProducerPtrs[i], 8)->setOrdering(Release);
422    }
423
424    for (unsigned i = 0; i < mStreamSetOutputs.size(); i++) {
425        Value * basePtr = getStreamSetBasePtr(self, mStreamSetOutputs[i].ssName);
426        mStreamSetOutputBuffers[i]->setEndOfInput(basePtr);
427    }
428
429    Value * nullVal = Constant::getNullValue(voidPtrTy);
430    Function * pthreadExitFunc = m->getFunction("pthread_exit");
431    CallInst * exitThread = iBuilder->CreateCall(pthreadExitFunc, {nullVal}); 
432    exitThread->setDoesNotReturn();
433    iBuilder->CreateRetVoid();
434
435    return threadFunc;
436
437}
Note: See TracBrowser for help on using the repository browser.