source: icGREP/icgrep-devel/icgrep/kernels/source_kernel.cpp @ 5699

Last change on this file since 5699 was 5694, checked in by cameron, 21 months ago

Update scanmatch callback protocol to use line start/end pointers; add finalize callback for buffer end

File size: 21.9 KB
RevLine 
[5429]1/*
2 *  Copyright (c) 2017 International Characters.
3 *  This software is licensed to the public under the Open Software License 3.0.
4 */
5#include "source_kernel.h"
[5436]6#include <kernels/kernel_builder.h>
[5429]7#include <kernels/streamset.h>
[5493]8#include <llvm/IR/Module.h>
[5429]9#include <sys/stat.h>
10#include <fcntl.h>
11
12using namespace llvm;
13
14inline static size_t round_up_to_nearest(const size_t x, const size_t y) {
15    return (((x - 1) | (y - 1)) + 1);
16}
17
18uint64_t file_size(const uint32_t fd) {
19    struct stat st;
20    if (LLVM_UNLIKELY(fstat(fd, &st) != 0)) {
21        st.st_size = 0;
22    }
23    return st.st_size;
24}
25
26namespace kernel {
27
28/// MMAP SOURCE KERNEL
29
[5500]30void MMapSourceKernel::linkExternalMethods(const std::unique_ptr<kernel::KernelBuilder> & kb) {
31    mFileSizeFunction = kb->LinkFunction("file_size", &file_size);
[5429]32}
33
[5500]34void MMapSourceKernel::generateInitializeMethod(const std::unique_ptr<KernelBuilder> & kb) {
35    BasicBlock * const emptyFile = kb->CreateBasicBlock("EmptyFile");
36    BasicBlock * const nonEmptyFile = kb->CreateBasicBlock("NonEmptyFile");
37    BasicBlock * const exit = kb->CreateBasicBlock("Exit");
38    IntegerType * const sizeTy = kb->getSizeTy();
39    assert (kb->getKernel() == this);
40    Value * const fd = kb->getScalarField("fileDescriptor");
[5429]41    assert (mFileSizeFunction);
[5500]42    Value * fileSize = kb->CreateCall(mFileSizeFunction, fd);
43    fileSize = kb->CreateZExtOrTrunc(fileSize, sizeTy);
[5429]44    if (mCodeUnitWidth > 8) {
[5500]45        fileSize = kb->CreateUDiv(fileSize, kb->getSize(mCodeUnitWidth / 8));
[5429]46    }
[5500]47    Value * const isEmpty = kb->CreateICmpEQ(fileSize, ConstantInt::getNullValue(fileSize->getType()));
48    kb->CreateUnlikelyCondBr(isEmpty, emptyFile, nonEmptyFile);
[5429]49    // we cannot mmap a 0 length file; just create a 1-page sized fake file buffer for simplicity
[5500]50    kb->SetInsertPoint(emptyFile);
51    Constant * pageSize = kb->getSize(getpagesize());
52    Value * fakeFileBuffer = kb->CreateAnonymousMMap(pageSize);
53    kb->CreateBr(exit);
[5429]54
[5500]55    kb->SetInsertPoint(nonEmptyFile);
56    Value * fileBackedBuffer = kb->CreateFileSourceMMap(fd, fileSize);
57    kb->CreateBr(exit);
[5429]58
[5500]59    kb->SetInsertPoint(exit);
60    PHINode * buffer = kb->CreatePHI(fileBackedBuffer->getType(), 2);
[5429]61    buffer->addIncoming(fakeFileBuffer, emptyFile);
62    buffer->addIncoming(fileBackedBuffer, nonEmptyFile);
[5500]63    PHINode * size = kb->CreatePHI(sizeTy, 2);
[5429]64    size->addIncoming(pageSize, emptyFile);
65    size->addIncoming(fileSize, nonEmptyFile);
[5633]66    Value * bufferPtr = kb->CreatePointerCast(buffer, kb->getInt8PtrTy());
67    kb->setBaseAddress("sourceBuffer", bufferPtr);
[5500]68    kb->setBufferedSize("sourceBuffer", size);
[5633]69    kb->setScalarField("readableBuffer", bufferPtr);
[5500]70    kb->setScalarField("fileSize", fileSize);
[5503]71    kb->setCapacity("sourceBuffer", fileSize);
[5500]72    kb->CreateMAdvise(buffer, fileSize, CBuilder::ADVICE_WILLNEED);
[5429]73
74}
75
[5500]76void MMapSourceKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> & kb) {
[5429]77
[5500]78    BasicBlock * dropPages = kb->CreateBasicBlock("dropPages");
79    BasicBlock * processSegment = kb->CreateBasicBlock("produceData");
80    BasicBlock * setTermination = kb->CreateBasicBlock("setTermination");
81    BasicBlock * mmapSourceExit = kb->CreateBasicBlock("mmapSourceExit");
[5429]82
83    // instruct the OS that it can safely drop any fully consumed pages
[5500]84    Value * consumed = kb->getConsumedItemCount("sourceBuffer");
[5454]85    IntegerType * const consumedTy = cast<IntegerType>(consumed->getType());
[5633]86    Type * const int8PtrTy = kb->getInt8PtrTy();
[5429]87
[5500]88    DataLayout DL(kb->getModule());
89    IntegerType * const intAddrTy = kb->getIntPtrTy(DL);
[5454]90
[5429]91    // multiply the consumed count by the code unit size then mask off any partial pages
92    if (mCodeUnitWidth > 8) {
[5500]93        consumed = kb->CreateMul(consumed, ConstantInt::get(consumedTy, mCodeUnitWidth / 8));
[5429]94    }
95    const auto pageSize = getpagesize();
96    if (LLVM_LIKELY((pageSize & (pageSize - 1)) == 0)) {
[5500]97        consumed = kb->CreateAnd(consumed, ConstantExpr::getNeg(ConstantInt::get(consumedTy, pageSize)));
[5429]98    } else {
[5500]99        consumed = kb->CreateSub(consumed, kb->CreateURem(consumed, ConstantInt::get(consumedTy, pageSize)));
[5429]100    }
[5454]101
[5500]102    Value * sourceBuffer = kb->getBaseAddress("sourceBuffer");
103    sourceBuffer = kb->CreatePtrToInt(sourceBuffer, intAddrTy);
[5454]104    if (LLVM_UNLIKELY(intAddrTy->getBitWidth() > consumedTy->getBitWidth())) {
[5500]105        consumed = kb->CreateZExt(consumed, intAddrTy);
[5454]106    } else if (LLVM_UNLIKELY(intAddrTy->getBitWidth() < consumedTy->getBitWidth())) {
[5500]107        sourceBuffer = kb->CreateZExt(sourceBuffer, consumedTy);
[5454]108    }
[5500]109    Value * consumedBuffer = kb->CreateAdd(sourceBuffer, consumed);
110    Value * readableBuffer = kb->getScalarField("readableBuffer");
111    readableBuffer = kb->CreatePtrToInt(readableBuffer, consumedBuffer->getType());
112    Value * unnecessaryBytes = kb->CreateSub(consumedBuffer, readableBuffer);
[5431]113
[5429]114    // avoid calling madvise unless an actual page table change could occur
[5500]115    Value * hasPagesToDrop = kb->CreateICmpEQ(unnecessaryBytes, ConstantInt::getNullValue(intAddrTy));
116    kb->CreateLikelyCondBr(hasPagesToDrop, processSegment, dropPages);
[5429]117
[5500]118    kb->SetInsertPoint(dropPages);
[5633]119    kb->CreateMAdvise(kb->CreateIntToPtr(readableBuffer, int8PtrTy), unnecessaryBytes, CBuilder::ADVICE_DONTNEED);
120    readableBuffer = kb->CreateIntToPtr(kb->CreateAdd(readableBuffer, unnecessaryBytes), int8PtrTy);
[5500]121    kb->setScalarField("readableBuffer", readableBuffer);
122    kb->CreateBr(processSegment);
[5429]123
124    // determine whether or not we've exhausted the file buffer
[5500]125    kb->SetInsertPoint(processSegment);
126    ConstantInt * segmentItems = kb->getSize(mSegmentBlocks * kb->getBitBlockWidth());
127    Value * const fileSize = kb->getScalarField("fileSize");
128    Value * const produced = kb->CreateAdd(kb->getProducedItemCount("sourceBuffer"), segmentItems);
129    Value * const lessThanFullSegment = kb->CreateICmpULT(fileSize, produced);
130    kb->CreateUnlikelyCondBr(lessThanFullSegment, setTermination, mmapSourceExit);
131    kb->SetInsertPoint(setTermination);
[5429]132
[5500]133    kb->setTerminationSignal();
134    kb->CreateBr(mmapSourceExit);
[5429]135
136    // finally, set the "produced" count to reflect current position in the file
[5500]137    kb->SetInsertPoint(mmapSourceExit);
138    PHINode * itemsRead = kb->CreatePHI(produced->getType(), 2);
[5429]139    itemsRead->addIncoming(produced, processSegment);
140    itemsRead->addIncoming(fileSize, setTermination);
[5500]141    kb->setProducedItemCount("sourceBuffer", itemsRead);
[5429]142}
143
[5500]144void MMapSourceKernel::generateFinalizeMethod(const std::unique_ptr<KernelBuilder> & kb) {
145    kb->CreateMUnmap(kb->getBaseAddress("sourceBuffer"), kb->getBufferedSize("sourceBuffer"));
[5429]146}
147
[5500]148MMapSourceKernel::MMapSourceKernel(const std::unique_ptr<kernel::KernelBuilder> & kb, unsigned blocksPerSegment, unsigned codeUnitWidth)
[5435]149: SegmentOrientedKernel("mmap_source" + std::to_string(blocksPerSegment) + "@" + std::to_string(codeUnitWidth),
[5429]150{},
[5500]151{Binding{kb->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}},
152{Binding{kb->getInt32Ty(), "fileDescriptor"}},
[5633]153{Binding{kb->getSizeTy(), "fileSize"}}, {Binding{kb->getInt8PtrTy(), "readableBuffer"}})
[5429]154, mSegmentBlocks(blocksPerSegment)
155, mCodeUnitWidth(codeUnitWidth)
156, mFileSizeFunction(nullptr) {
157
158}
159
160/// READ SOURCE KERNEL
161
[5500]162void ReadSourceKernel::generateInitializeMethod(const std::unique_ptr<KernelBuilder> & kb) {
163    const size_t initialBufferSize = 8 * getpagesize() * mCodeUnitWidth;
164    ConstantInt * const bufferBytes = kb->getSize(initialBufferSize * mCodeUnitWidth/8);
165    PointerType * const codeUnitPtrTy = IntegerType::get(kb->getContext(), mCodeUnitWidth)->getPointerTo();
166    Value * const buffer = kb->CreatePointerCast(kb->CreateCacheAlignedMalloc(bufferBytes), codeUnitPtrTy);
167    kb->setScalarField("buffer", buffer);
168    kb->setScalarField("capacity", kb->getSize(initialBufferSize));
169    kb->setBaseAddress("sourceBuffer", buffer);
170    kb->setBufferedSize("sourceBuffer", kb->getSize(0));
[5501]171    kb->setCapacity("sourceBuffer", kb->getSize(initialBufferSize));
[5429]172}
173
[5500]174void ReadSourceKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> & kb) {
[5429]175
[5500]176    ConstantInt * const readSize = kb->getSize(getpagesize() * 8/mCodeUnitWidth);
177    PointerType * const codeUnitPtrTy = IntegerType::get(kb->getContext(), mCodeUnitWidth)->getPointerTo();
178    PointerType * const i8PtrTy = IntegerType::get(kb->getContext(), 8)->getPointerTo();
179    ConstantInt * const codeUnitBytes = kb->getSize(mCodeUnitWidth/8);
180    BasicBlock * const entryBlock = kb->GetInsertBlock();
181    BasicBlock * const exhaustedBuffer = kb->CreateBasicBlock("ExhaustedBuffer");
182    BasicBlock * const waitOnConsumers = kb->CreateBasicBlock("WaitOnConsumers");
183    BasicBlock * const readData = kb->CreateBasicBlock("ReadData");
184    BasicBlock * const stdInExit = kb->CreateBasicBlock("StdInExit");
[5429]185
[5500]186    assert(kb->getKernel() == this);
[5440]187
[5464]188    // Check whether we need to read another page of data
[5500]189    ConstantInt * const segmentSize = kb->getSize(mSegmentBlocks * kb->getBitBlockWidth());
190    Value * bufferedSize = kb->getBufferedSize("sourceBuffer");
191    Value * const produced = kb->getProducedItemCount("sourceBuffer");
192    Value * unreadSize = kb->CreateSub(bufferedSize, produced);
193    kb->CreateUnlikelyCondBr(kb->CreateICmpULT(unreadSize, segmentSize), exhaustedBuffer, stdInExit);
[5429]194
195    // If so, it checks whether it can simply append another page to the existing buffer or whether
196    // we need to perform a copyback.
197
[5500]198    kb->SetInsertPoint(exhaustedBuffer);
[5429]199
200    // Otherwise, we're going to have to perform a copy back...
201
[5500]202    // Let L be the logical buffer address (i.e., the position of the "first code unit" of the input stream)
[5429]203    // and B be the address pointing to the beginning of our actual buffer. Check whether:
204
[5500]205    //     L + produced + readSize < B + capacity
[5429]206
207    // If so, we can append to our existing buffer without impacting any subsequent kernel.
208
[5500]209    Value * inputStream = kb->getRawOutputPointer("sourceBuffer", kb->getInt32(0), kb->getInt32(0));
210    Value * const originalPtr = kb->CreateGEP(inputStream, produced);
[5464]211
[5500]212    Value * const buffer = kb->getScalarField("buffer");
213    Value * const capacity = kb->getScalarField("capacity");
[5464]214
[5500]215    Value * L = kb->CreateGEP(originalPtr, readSize);
216    Value * B = kb->CreateGEP(buffer, capacity);
217    Value * const canAppend = kb->CreateICmpULT(L, B);
218    kb->CreateLikelyCondBr(canAppend, readData, waitOnConsumers);
[5429]219
220    // First wait on any consumers to finish processing then check how much data has been consumed.
[5500]221    kb->SetInsertPoint(waitOnConsumers);
222    kb->CreateConsumerWait();
[5464]223
[5429]224    // Then determine how much data has been consumed and how much needs to be copied back, noting
225    // that our "unproduced" data must be block aligned.
[5500]226    const size_t blockAlignment = kb->getBitBlockWidth() / 8;
227    Constant * const alignmentMask = kb->getSize(-(blockAlignment * 8 / mCodeUnitWidth));
228    Value * const consumed = kb->CreateAnd(kb->getConsumedItemCount("sourceBuffer"), alignmentMask);
229    Value * const remaining = kb->CreateSub(bufferedSize, consumed);
230    Value * const unconsumedPtr = kb->CreateGEP(inputStream, consumed);
231    Value * const consumedMajority = kb->CreateICmpULT(kb->CreateGEP(buffer, remaining), unconsumedPtr);
232    Value * target = buffer;
233    Value * source = unconsumedPtr;
234    Value * toCopy = remaining;
235    if (mCodeUnitWidth != 8) {
236        source = kb->CreatePointerCast(unconsumedPtr, i8PtrTy);
237        toCopy = kb->CreateMul(remaining, codeUnitBytes);
238    }
[5464]239
[5500]240    BasicBlock * const copyBack = kb->CreateBasicBlock("CopyBack");
241    BasicBlock * const expandAndCopyBack = kb->CreateBasicBlock("ExpandAndCopyBack");
242    BasicBlock * const calculateLogicalAddress = kb->CreateBasicBlock("CalculateLogicalAddress");
[5493]243
[5429]244    // Have we consumed enough data that we can safely copy back the unconsumed data without needing
245    // a temporary buffer? (i.e., B + remaining < L + consumed)
[5500]246    kb->CreateLikelyCondBr(consumedMajority, copyBack, expandAndCopyBack);
247    kb->SetInsertPoint(copyBack);
[5429]248    // If so, just copy the data ...
[5500]249    if (mCodeUnitWidth != 8) {
250        target = kb->CreatePointerCast(buffer, i8PtrTy);
251    }
252    kb->CreateMemCpy(target, source, toCopy, 1);
253    kb->CreateBr(calculateLogicalAddress);
254   
[5429]255    // Otherwise, allocate a buffer with twice the capacity and copy the unconsumed data back into it
[5500]256    kb->SetInsertPoint(expandAndCopyBack);
257    Value * const expandedCapacity = kb->CreateShl(capacity, 1);
258    Value * const expandedBytes = mCodeUnitWidth == 8 ? expandedCapacity : kb->CreateMul(expandedCapacity, codeUnitBytes);
259    Value * const expandedBuffer = kb->CreatePointerCast(kb->CreateCacheAlignedMalloc(expandedBytes), codeUnitPtrTy);
260    target = mCodeUnitWidth == 8 ? expandedBuffer : kb->CreatePointerCast(expandedBuffer, i8PtrTy);
261    kb->CreateMemCpy(target, source, toCopy, 1);
262    kb->CreateFree(buffer);
263    kb->setScalarField("buffer", expandedBuffer);
264    kb->setScalarField("capacity", expandedCapacity);
[5501]265    kb->setCapacity("sourceBuffer", expandedCapacity);
[5500]266    kb->CreateBr(calculateLogicalAddress);
[5497]267
[5429]268    // Update the logical address for this buffer....
[5500]269    kb->SetInsertPoint(calculateLogicalAddress);
270    PHINode * const baseAddress = kb->CreatePHI(codeUnitPtrTy, 2);
[5429]271    baseAddress->addIncoming(buffer, copyBack);
[5500]272    baseAddress->addIncoming(expandedBuffer, expandAndCopyBack);
273    Value * const logicalAddress = kb->CreateGEP(baseAddress, kb->CreateNeg(consumed));
274    Value * const modifiedPtr = kb->CreateGEP(baseAddress, remaining);
275    kb->setBaseAddress("sourceBuffer", logicalAddress);
276    kb->CreateBr(readData);
[5493]277
[5429]278    // Regardless of whether we're simply appending data or had to allocate a new buffer, read a new page
279    // of data into the input source buffer. If we fail to read a full segment ...
280    readData->moveAfter(calculateLogicalAddress);
[5500]281    kb->SetInsertPoint(readData);
[5429]282    calculateLogicalAddress->moveAfter(calculateLogicalAddress);
[5500]283    PHINode * const addr = kb->CreatePHI(codeUnitPtrTy, 2);
[5429]284    addr->addIncoming(originalPtr, exhaustedBuffer);
285    addr->addIncoming(modifiedPtr, calculateLogicalAddress);
[5500]286    assert(kb->getKernel() == this);
287    Value * const fd = kb->getScalarField("fileDescriptor");
288    Value * toRead = readSize;
289    if (mCodeUnitWidth != 8) {
290        toRead = kb->CreateMul(toRead, codeUnitBytes);
291    }
292    Value * bytesRead = kb->CreateReadCall(fd, addr, toRead);
293    Value * itemsRead = bytesRead;
294    if (mCodeUnitWidth != 8) {
295        itemsRead = kb->CreateUDiv(bytesRead, codeUnitBytes);
296    }
297    unreadSize = kb->CreateAdd(unreadSize, itemsRead);
298    bufferedSize = kb->CreateAdd(bufferedSize, itemsRead);
299    kb->setBufferedSize("sourceBuffer", bufferedSize);
300    Value * const exhaustedInputSource = kb->CreateICmpULT(unreadSize, segmentSize);
301    BasicBlock * const setTermination = kb->CreateBasicBlock("SetTermination");
302    kb->CreateUnlikelyCondBr(exhaustedInputSource, setTermination, stdInExit);
[5429]303
304    // ... zero out the remaining bytes and set the termination signal.
[5500]305    kb->SetInsertPoint(setTermination);
306    Value * bytesToZero = kb->CreateSub(segmentSize, unreadSize);
307    Value * unreadPtr = kb->CreateGEP(addr, unreadSize);
308    bytesToZero = mCodeUnitWidth == 8 ? bytesToZero : kb->CreateMul(bytesToZero, codeUnitBytes);
309    if (mCodeUnitWidth != 8) {
310        bytesToZero = kb->CreateMul(bytesToZero, codeUnitBytes);
311        unreadPtr = kb->CreatePointerCast(unreadPtr, i8PtrTy);
312    }
313    kb->CreateMemZero(unreadPtr, bytesToZero);
314    kb->setTerminationSignal();
315    kb->CreateBr(stdInExit);
[5429]316
317    // finally add the segment item count to the produced item count to inform the subsequent kernels how
318    // much data is available for processing
[5500]319    kb->SetInsertPoint(stdInExit);
[5429]320    stdInExit->moveAfter(setTermination);
[5500]321    PHINode * const items = kb->CreatePHI(produced->getType(), 3);
[5429]322    items->addIncoming(segmentSize, entryBlock);
323    items->addIncoming(segmentSize, readData);
324    items->addIncoming(unreadSize, setTermination);
[5500]325    kb->setProducedItemCount("sourceBuffer", kb->CreateAdd(produced, items));
[5429]326}
327
[5500]328void ReadSourceKernel::generateFinalizeMethod(const std::unique_ptr<KernelBuilder> & kb) {
329    kb->CreateFree(kb->getScalarField("buffer"));
[5429]330}
331
[5500]332ReadSourceKernel::ReadSourceKernel(const std::unique_ptr<kernel::KernelBuilder> & kb, unsigned blocksPerSegment, unsigned codeUnitWidth)
[5693]333: SegmentOrientedKernel("read_source"  + std::to_string(blocksPerSegment) + "@" + std::to_string(codeUnitWidth)
[5429]334, {}
[5500]335, {Binding{kb->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}}
336, {Binding{kb->getInt32Ty(), "fileDescriptor"}}
[5429]337, {}
[5500]338, {Binding{IntegerType::get(kb->getContext(), codeUnitWidth)->getPointerTo(), "buffer"}, Binding{kb->getSizeTy(), "capacity"}})
[5429]339, mSegmentBlocks(blocksPerSegment)
340, mCodeUnitWidth(codeUnitWidth) {
341
342}
343
[5693]344// Hybrid MMap/Read source kernel
345   
346FDSourceKernel::FDSourceKernel(const std::unique_ptr<kernel::KernelBuilder> & kb, unsigned blocksPerSegment, unsigned codeUnitWidth)
347: SegmentOrientedKernel("FD_source" + std::to_string(blocksPerSegment) + "@" + std::to_string(codeUnitWidth)
348, {}
349, {Binding{kb->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}}
350, {Binding{kb->getInt32Ty(), "fileDescriptor"}}
351, {}
352, {Binding{IntegerType::get(kb->getContext(), codeUnitWidth)->getPointerTo(), "buffer"}, Binding{kb->getSizeTy(), "capacity"},
353    Binding{kb->getSizeTy(), "fileSize"}, Binding{kb->getInt8PtrTy(), "readableBuffer"}})
354, mSegmentBlocks(blocksPerSegment)
355, mCodeUnitWidth(codeUnitWidth)
356, mFileSizeFunction(nullptr) {
357   
358}
359
360void FDSourceKernel::generateFinalizeMethod(const std::unique_ptr<KernelBuilder> & kb) {
361    BasicBlock * finalizeRead = kb->CreateBasicBlock("finalizeRead");
362    BasicBlock * finalizeMMap = kb->CreateBasicBlock("finalizeMMap");
363    BasicBlock * finalizeDone = kb->CreateBasicBlock("finalizeDone");
364    // if the fileDescriptor is 0, the file is stdin, use readSource kernel logic, otherwise use mmap logic.
[5694]365    kb->CreateCondBr(kb->CreateICmpEQ(kb->getScalarField("fileDescriptor"), kb->getInt32(STDIN_FILENO)), finalizeRead, finalizeMMap);
[5693]366    kb->SetInsertPoint(finalizeRead);
367    reinterpret_cast<ReadSourceKernel *>(this)->ReadSourceKernel::generateFinalizeMethod(kb);
368    kb->CreateBr(finalizeDone);
369    kb->SetInsertPoint(finalizeMMap);
370    reinterpret_cast<MMapSourceKernel *>(this)->MMapSourceKernel::generateFinalizeMethod(kb);
371    kb->CreateBr(finalizeDone);
372    kb->SetInsertPoint(finalizeDone);
373}
374
375void FDSourceKernel::generateInitializeMethod(const std::unique_ptr<KernelBuilder> & kb) {
376    BasicBlock * initializeRead = kb->CreateBasicBlock("initializeRead");
377    BasicBlock * initializeMMap = kb->CreateBasicBlock("initializeMMap");
378    BasicBlock * initializeDone = kb->CreateBasicBlock("initializeDone");
379    // if the fileDescriptor is 0, the file is stdin, use readSource kernel logic, otherwise use MMap logic.
[5694]380    kb->CreateCondBr(kb->CreateICmpEQ(kb->getScalarField("fileDescriptor"), kb->getInt32(STDIN_FILENO)), initializeRead, initializeMMap);
[5693]381    kb->SetInsertPoint(initializeRead);
382    reinterpret_cast<ReadSourceKernel *>(this)->ReadSourceKernel::generateInitializeMethod(kb);
383    kb->CreateBr(initializeDone);
384    kb->SetInsertPoint(initializeMMap);
385    reinterpret_cast<MMapSourceKernel *>(this)->MMapSourceKernel::generateInitializeMethod(kb);
386    kb->CreateBr(initializeDone);
387    kb->SetInsertPoint(initializeDone);
388}
389
390void FDSourceKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> & kb) {
391    BasicBlock * DoSegmentRead = kb->CreateBasicBlock("DoSegmentRead");
392    BasicBlock * DoSegmentMMap = kb->CreateBasicBlock("DoSegmentMMap");
393    BasicBlock * DoSegmentDone = kb->CreateBasicBlock("DoSegmentDone");
394    // if the fileDescriptor is 0, the file is stdin, use readSource kernel logic, otherwise use MMap logic.
[5694]395    kb->CreateCondBr(kb->CreateICmpEQ(kb->getScalarField("fileDescriptor"), kb->getInt32(STDIN_FILENO)), DoSegmentRead, DoSegmentMMap);
[5693]396    kb->SetInsertPoint(DoSegmentRead);
397    reinterpret_cast<ReadSourceKernel *>(this)->ReadSourceKernel::generateDoSegmentMethod(kb);
398    kb->CreateBr(DoSegmentDone);
399    kb->SetInsertPoint(DoSegmentMMap);
400    reinterpret_cast<MMapSourceKernel *>(this)->MMapSourceKernel::generateDoSegmentMethod(kb);
401    kb->CreateBr(DoSegmentDone);
402    kb->SetInsertPoint(DoSegmentDone);
403}
404
405
406void FDSourceKernel::linkExternalMethods(const std::unique_ptr<kernel::KernelBuilder> & kb) {
407    mFileSizeFunction = kb->LinkFunction("file_size", &file_size);
408}
409   
410   
[5429]411/// MEMORY SOURCE KERNEL
412
[5500]413void MemorySourceKernel::generateInitializeMethod(const std::unique_ptr<KernelBuilder> & kb) {
[5634]414    kb->setBaseAddress("sourceBuffer", kb->CreatePointerCast(kb->getScalarField("fileSource"), kb->getVoidPtrTy()));
[5500]415    kb->setBufferedSize("sourceBuffer", kb->getScalarField("fileSize"));
[5513]416    kb->setCapacity("sourceBuffer", kb->getScalarField("fileSize"));
[5429]417}
418
[5500]419void MemorySourceKernel::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> & kb) {
[5429]420
[5500]421    BasicBlock * entryBlock = kb->GetInsertBlock();
422    BasicBlock * setTermination = kb->CreateBasicBlock("setTermination");
423    BasicBlock * mmapSourceExit = kb->CreateBasicBlock("sourceExit");
424    ConstantInt * segmentItems = kb->getSize(mSegmentBlocks * kb->getBitBlockWidth());
425    Value * fileItems = kb->getScalarField("fileSize");
[5429]426    if (mCodeUnitWidth > 8) {
[5500]427        fileItems = kb->CreateUDiv(fileItems, kb->getSize(mCodeUnitWidth / 8));
[5429]428    }
[5500]429    Value * produced = kb->getProducedItemCount("sourceBuffer");
430    produced = kb->CreateAdd(produced, segmentItems);
431    Value * lessThanFullSegment = kb->CreateICmpULT(fileItems, produced);
432    kb->CreateCondBr(lessThanFullSegment, setTermination, mmapSourceExit);
433    kb->SetInsertPoint(setTermination);
434    kb->setTerminationSignal();
435    kb->CreateBr(mmapSourceExit);
[5429]436
[5500]437    kb->SetInsertPoint(mmapSourceExit);
[5429]438
[5500]439    PHINode * itemsRead = kb->CreatePHI(produced->getType(), 2);
[5429]440    itemsRead->addIncoming(produced, entryBlock);
441    itemsRead->addIncoming(fileItems, setTermination);
[5500]442    kb->setProducedItemCount("sourceBuffer", itemsRead);
[5429]443}
444
[5500]445MemorySourceKernel::MemorySourceKernel(const std::unique_ptr<kernel::KernelBuilder> & kb, Type * type, unsigned blocksPerSegment, unsigned codeUnitWidth)
[5435]446: SegmentOrientedKernel("memory_source",
[5429]447    {},
[5500]448    {Binding{kb->getStreamSetTy(1, codeUnitWidth), "sourceBuffer"}},
449    {Binding{cast<PointerType>(type), "fileSource"}, Binding{kb->getSizeTy(), "fileSize"}}, {}, {})
[5429]450, mSegmentBlocks(blocksPerSegment)
451, mCodeUnitWidth(codeUnitWidth) {
452
453}
454
455}
Note: See TracBrowser for help on using the repository browser.