source: icGREP/icgrep-devel/icgrep/kernels/stdout_kernel.cpp @ 5448

Last change on this file since 5448 was 5448, checked in by cameron, 23 months ago

Hack for source/external buffers with mBufferBlocks=1; u8u16 test with segment-pipeline-parallel; simplified copying

File size: 7.1 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#include "stdout_kernel.h"
6#include <llvm/IR/Module.h>
7#include <kernels/kernel_builder.h>
8#include <kernels/streamset.h>
9
10namespace llvm { class Type; }
11
12using namespace llvm;
13using namespace parabix;
14
15namespace kernel {
16
17// Rather than using doBlock logic to write one block at a time, this custom
18// doSegment method attempts to write the entire segment with a single write call.
19// However, if the segment spans two memory areas (e.g., because of wraparound),
20// then two write calls are made.
21void StdOutKernel::generateMultiBlockLogic(const std::unique_ptr<KernelBuilder> & iBuilder) {
22    PointerType * i8PtrTy = iBuilder->getInt8PtrTy();
23    Constant * itemBytes = iBuilder->getSize(mCodeUnitWidth / 8);
24   
25    Function::arg_iterator args = mCurrentMethod->arg_begin();
26    /* self = */ args++;
27    Value * itemsToDo = &*(args++);
28    Value * codeUnitBuffer = &*(args++);
29
30    Value * bytesToDo = mCodeUnitWidth == 8 ? itemsToDo : iBuilder->CreateMul(itemsToDo, itemBytes);
31    Value * bytePtr = iBuilder->CreatePointerCast(codeUnitBuffer, i8PtrTy);
32    iBuilder->CreateWriteCall(iBuilder->getInt32(1), bytePtr, bytesToDo);
33}
34
35StdOutKernel::StdOutKernel(const std::unique_ptr<kernel::KernelBuilder> & iBuilder, unsigned codeUnitWidth)
36: MultiBlockKernel("stdout", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {}, {})
37, mCodeUnitWidth(codeUnitWidth) {
38    setNoTerminateAttribute(true);
39}
40
41void FileSink::generateInitializeMethod(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) {
42    BasicBlock * setTerminationOnFailure = iBuilder->CreateBasicBlock("setTerminationOnFailure");
43    BasicBlock * fileSinkInitExit = iBuilder->CreateBasicBlock("fileSinkInitExit");
44    Value * fileName = iBuilder->getScalarField("fileName");
45    Value * fileNameLength = iBuilder->CreateStrlenCall(fileName);
46    // Make a temporary file name template with the characters "XXXXXX" appended
47    // as required by mkstemp.
48    Constant * suffixPlusNullLength = iBuilder->getSize(7);
49    Value * tmpFileNamePtr = iBuilder->CreatePointerCast(iBuilder->CreateMalloc(iBuilder->CreateAdd(fileNameLength, suffixPlusNullLength)), iBuilder->getInt8PtrTy());
50    iBuilder->setScalarField("tmpFileName", tmpFileNamePtr);
51    iBuilder->CreateMemCpy(tmpFileNamePtr, fileName, fileNameLength, 1);
52#ifdef BACKUP_OLDFILE
53    iBuilder->CreateMemCpy(iBuilder->CreateGEP(tmpFileNamePtr, fileNameLength), iBuilder->GetString(".saved"), suffixPlusNullLength, 1);
54    iBuilder->CreateRenameCall(fileName, tmpFileNamePtr);
55#else
56    iBuilder->CreateUnlinkCall(fileName);
57#endif
58    iBuilder->CreateMemCpy(iBuilder->CreateGEP(tmpFileNamePtr, fileNameLength), iBuilder->GetString("XXXXXX"), suffixPlusNullLength, 1);
59    Value * fileDes = iBuilder->CreateMkstempCall(tmpFileNamePtr);
60    iBuilder->setScalarField("fileDes", fileDes);
61    Value * failure = iBuilder->CreateICmpEQ(fileDes, iBuilder->getInt32(-1));
62    iBuilder->CreateCondBr(failure, setTerminationOnFailure, fileSinkInitExit);
63    iBuilder->SetInsertPoint(setTerminationOnFailure);
64    iBuilder->setTerminationSignal();
65    iBuilder->CreateBr(fileSinkInitExit);
66    iBuilder->SetInsertPoint(fileSinkInitExit);
67}
68
69void FileSink::generateDoSegmentMethod(const std::unique_ptr<KernelBuilder> &iBuilder) {
70
71    PointerType * i8PtrTy = iBuilder->getInt8PtrTy();
72
73    BasicBlock * closeFile = iBuilder->CreateBasicBlock("closeFile");
74    BasicBlock * fileOutExit = iBuilder->CreateBasicBlock("fileOutExit");
75    Constant * blockItems = iBuilder->getSize(iBuilder->getBitBlockWidth());
76    Constant * itemBytes = iBuilder->getSize(mCodeUnitWidth/8);
77
78    Value * fileDes = iBuilder->getScalarField("fileDes");
79    Value * available = iBuilder->getAvailableItemCount("codeUnitBuffer");
80    Value * processed = iBuilder->getProcessedItemCount("codeUnitBuffer");
81    Value * itemsToDo = iBuilder->CreateSub(available, processed);
82    // There may be two memory areas if we are at the physical end of a circular buffer.
83    const auto b  = getInputStreamSetBuffer("codeUnitBuffer");
84    Value * wraparound = nullptr;
85    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
86        Value * accessible = iBuilder->getLinearlyAccessibleItems("codeUnitBuffer", processed);
87        wraparound = iBuilder->CreateICmpULT(accessible, itemsToDo);
88        itemsToDo = iBuilder->CreateSelect(wraparound, accessible, itemsToDo);
89    }
90   
91    Value * byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
92    Value * bytePtr = iBuilder->CreatePointerCast(iBuilder->getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
93    bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
94    Value * bytesToDo = mCodeUnitWidth == 8 ? itemsToDo : iBuilder->CreateMul(itemsToDo, itemBytes);
95    iBuilder->CreateWriteCall(fileDes, bytePtr, bytesToDo);
96   
97    processed = iBuilder->CreateAdd(processed, itemsToDo);
98    iBuilder->setProcessedItemCount("codeUnitBuffer", processed);
99   
100    // Now we may process the second area (if required).
101    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
102        BasicBlock * wrapAroundWrite = iBuilder->CreateBasicBlock("wrapAroundWrite");
103        BasicBlock * checkFinal = iBuilder->CreateBasicBlock("checkFinal");
104        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, checkFinal);
105        iBuilder->SetInsertPoint(wrapAroundWrite);
106       
107        // Calculate from the updated value of processed;
108        byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
109        Value * bytePtr = iBuilder->CreatePointerCast(iBuilder->getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
110        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
111        itemsToDo = iBuilder->CreateSub(available, processed);
112        bytesToDo = mCodeUnitWidth == 8 ? itemsToDo : iBuilder->CreateMul(itemsToDo, itemBytes);
113        iBuilder->CreateWriteCall(fileDes, bytePtr, bytesToDo);
114        processed = iBuilder->CreateAdd(processed, itemsToDo);
115        iBuilder->setProcessedItemCount("codeUnitBuffer", available);
116        iBuilder->CreateBr(checkFinal);
117        iBuilder->SetInsertPoint(checkFinal);
118    }
119    iBuilder->CreateCondBr(mIsFinal, closeFile, fileOutExit);
120
121    iBuilder->SetInsertPoint(closeFile);
122    iBuilder->CreateCloseCall(fileDes);
123    Value * newFileNamePtr = iBuilder->getScalarField("fileName");
124    Value * tmpFileNamePtr = iBuilder->getScalarField("tmpFileName");
125    iBuilder->CreateRenameCall(tmpFileNamePtr, newFileNamePtr);
126    iBuilder->CreateFree(tmpFileNamePtr);
127   
128    iBuilder->CreateBr(fileOutExit);
129
130    iBuilder->SetInsertPoint(fileOutExit);
131}
132
133FileSink::FileSink(const std::unique_ptr<kernel::KernelBuilder> & iBuilder, unsigned codeUnitWidth)
134: SegmentOrientedKernel("filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
135                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getInt8PtrTy(), "tmpFileName"}, Binding{iBuilder->getInt32Ty(), "fileDes"}})
136, mCodeUnitWidth(codeUnitWidth) {
137}
138
139}
140
141
142
143
Note: See TracBrowser for help on using the repository browser.