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

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

Bug fixes for MultiBlockKernel?, StdOutKernel?

File size: 7.0 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    iBuilder->CreateWriteCall(fileDes, bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
95   
96    processed = iBuilder->CreateAdd(processed, itemsToDo);
97    iBuilder->setProcessedItemCount("codeUnitBuffer", processed);
98   
99    // Now we may process the second area (if required).
100    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
101        BasicBlock * wrapAroundWrite = iBuilder->CreateBasicBlock("wrapAroundWrite");
102        BasicBlock * checkFinal = iBuilder->CreateBasicBlock("checkFinal");
103        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, checkFinal);
104        iBuilder->SetInsertPoint(wrapAroundWrite);
105       
106        // Calculate from the updated value of processed;
107        byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
108        Value * bytePtr = iBuilder->CreatePointerCast(iBuilder->getInputStreamBlockPtr("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
109        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
110        itemsToDo = iBuilder->CreateSub(available, processed);
111        iBuilder->CreateWriteCall(fileDes, bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
112        processed = iBuilder->CreateAdd(processed, itemsToDo);
113        iBuilder->setProcessedItemCount("codeUnitBuffer", available);
114        iBuilder->CreateBr(checkFinal);
115        iBuilder->SetInsertPoint(checkFinal);
116    }
117    iBuilder->CreateCondBr(mIsFinal, closeFile, fileOutExit);
118
119    iBuilder->SetInsertPoint(closeFile);
120    iBuilder->CreateCloseCall(fileDes);
121    Value * newFileNamePtr = iBuilder->getScalarField("fileName");
122    Value * tmpFileNamePtr = iBuilder->getScalarField("tmpFileName");
123    iBuilder->CreateRenameCall(tmpFileNamePtr, newFileNamePtr);
124    iBuilder->CreateFree(tmpFileNamePtr);
125   
126    iBuilder->CreateBr(fileOutExit);
127
128    iBuilder->SetInsertPoint(fileOutExit);
129}
130
131FileSink::FileSink(const std::unique_ptr<kernel::KernelBuilder> & iBuilder, unsigned codeUnitWidth)
132: SegmentOrientedKernel("filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
133                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getInt8PtrTy(), "tmpFileName"}, Binding{iBuilder->getInt32Ty(), "fileDes"}})
134, mCodeUnitWidth(codeUnitWidth) {
135}
136
137}
138
139
140
141
Note: See TracBrowser for help on using the repository browser.