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

Last change on this file since 5435 was 5435, checked in by nmedfort, 2 years ago

Continued refactoring work.

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