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

Last change on this file since 5310 was 5310, checked in by nmedfort, 3 years ago

Adjusted pablo compiler to use getInputStream and getOutputStream when accessing packed stream fields.

File size: 7.3 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(Value *doFinal, const std::vector<Value *> &producerPos) {
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(producerPos[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 * accessible = b->getLinearlyAccessibleItems(processed);
32        wraparound = iBuilder->CreateICmpULT(accessible, itemsToDo);
33        itemsToDo = iBuilder->CreateSelect(wraparound, accessible, itemsToDo);
34    }
35   
36    Value * byteOffset = iBuilder->CreateMul(iBuilder->CreateAnd(processed, blockItems), itemBytes);
37    Value * bytePtr = iBuilder->CreatePointerCast(getInputStream("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
38    bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
39
40    iBuilder->CreateWriteCall(iBuilder->getInt32(1), bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
41
42    processed = iBuilder->CreateAdd(processed, itemsToDo);
43    setProcessedItemCount("codeUnitBuffer", processed);
44   
45    // Now we may process the second area (if required).
46    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
47        BasicBlock * wrapAroundWrite = CreateBasicBlock("wrapAroundWrite");
48        BasicBlock * stdoutExit = CreateBasicBlock("stdoutExit");
49        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, stdoutExit);
50        iBuilder->SetInsertPoint(wrapAroundWrite);
51       
52        // Calculate from the updated value of processed;
53        byteOffset = iBuilder->CreateMul(iBuilder->CreateAnd(processed, blockItems), itemBytes);
54        Value * bytePtr = iBuilder->CreatePointerCast(getInputStream("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
55        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
56
57        itemsToDo = iBuilder->CreateSub(producerPos[0], processed);
58        iBuilder->CreateWriteCall(iBuilder->getInt32(1), bytePtr, iBuilder->CreateMul(itemsToDo, itemBytes));
59        processed = iBuilder->CreateAdd(processed, itemsToDo);
60        setProcessedItemCount("codeUnitBuffer", producerPos[0]);
61        iBuilder->CreateBr(stdoutExit);
62        iBuilder->SetInsertPoint(stdoutExit);
63    }
64}
65
66StdOutKernel::StdOutKernel(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
67: SegmentOrientedKernel(iBuilder, "stdout", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {}, {}, {}, {})
68, mCodeUnitWidth(codeUnitWidth) {
69    setNoTerminateAttribute(true);
70}
71
72void FileSink::generateInitMethod() {
73    BasicBlock * setTerminationOnFailure = CreateBasicBlock("setTerminationOnFailure");
74    BasicBlock * fileSinkInitExit = CreateBasicBlock("fileSinkInitExit");
75    Value * handle = iBuilder->CreateFOpenCall(getScalarField("fileName"), iBuilder->CreateGlobalStringPtr("w"));
76    setScalarField("IOstreamPtr", handle);
77    Value * failure = iBuilder->CreateICmpEQ(iBuilder->CreatePtrToInt(handle, iBuilder->getSizeTy()), iBuilder->getSize(0));
78    iBuilder->CreateCondBr(failure, setTerminationOnFailure, fileSinkInitExit);
79    iBuilder->SetInsertPoint(setTerminationOnFailure);
80    setTerminationSignal();
81    iBuilder->CreateBr(fileSinkInitExit);
82    iBuilder->SetInsertPoint(fileSinkInitExit);
83}
84
85void FileSink::generateDoSegmentMethod(Value *doFinal, const std::vector<Value *> &producerPos) {
86
87    PointerType * i8PtrTy = iBuilder->getInt8PtrTy();
88
89    BasicBlock * closeFile = CreateBasicBlock("closeFile");
90    BasicBlock * fileOutExit = CreateBasicBlock("fileOutExit");
91    Constant * blockItems = iBuilder->getSize(iBuilder->getBitBlockWidth());
92    Constant * itemBytes = iBuilder->getSize(mCodeUnitWidth/8);
93
94    Value * IOstreamPtr = getScalarField("IOstreamPtr");
95    Value * processed = getProcessedItemCount("codeUnitBuffer");
96    Value * itemsToDo = iBuilder->CreateSub(producerPos[0], processed);
97    // There may be two memory areas if we are at the physical end of a circular buffer.
98    const auto b  = getInputStreamSetBuffer("codeUnitBuffer");
99    Value * wraparound = nullptr;
100    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
101        Value * accessible = b->getLinearlyAccessibleItems(processed);
102        wraparound = iBuilder->CreateICmpULT(accessible, itemsToDo);
103        itemsToDo = iBuilder->CreateSelect(wraparound, accessible, itemsToDo);
104    }
105   
106    Value * byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
107    Value * bytePtr = iBuilder->CreatePointerCast(getInputStream("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
108    bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
109
110    iBuilder->CreateFWriteCall(bytePtr, itemsToDo, itemBytes, IOstreamPtr);
111
112   
113    processed = iBuilder->CreateAdd(processed, itemsToDo);
114    setProcessedItemCount("codeUnitBuffer", processed);
115   
116    // Now we may process the second area (if required).
117    if (isa<CircularBuffer>(b) || isa<CircularCopybackBuffer>(b)) {
118        BasicBlock * wrapAroundWrite = CreateBasicBlock("wrapAroundWrite");
119        BasicBlock * checkFinal = CreateBasicBlock("checkFinal");
120        iBuilder->CreateCondBr(wraparound, wrapAroundWrite, checkFinal);
121        iBuilder->SetInsertPoint(wrapAroundWrite);
122       
123        // Calculate from the updated value of processed;
124        byteOffset = iBuilder->CreateMul(iBuilder->CreateURem(processed, blockItems), itemBytes);
125        Value * bytePtr = iBuilder->CreatePointerCast(getInputStream("codeUnitBuffer", iBuilder->getInt32(0)), i8PtrTy);
126        bytePtr = iBuilder->CreateGEP(bytePtr, byteOffset);
127        itemsToDo = iBuilder->CreateSub(producerPos[0], processed);
128        iBuilder->CreateFWriteCall(bytePtr, itemsToDo, itemBytes, IOstreamPtr);
129        processed = iBuilder->CreateAdd(processed, itemsToDo);
130        setProcessedItemCount("codeUnitBuffer", producerPos[0]);
131        iBuilder->CreateBr(checkFinal);
132        iBuilder->SetInsertPoint(checkFinal);
133    }
134    iBuilder->CreateCondBr(doFinal, closeFile, fileOutExit);
135
136    iBuilder->SetInsertPoint(closeFile);
137    iBuilder->CreateFCloseCall(IOstreamPtr);
138    iBuilder->CreateBr(fileOutExit);
139
140    iBuilder->SetInsertPoint(fileOutExit);
141}
142
143FileSink::FileSink(IDISA::IDISA_Builder * iBuilder, unsigned codeUnitWidth)
144: SegmentOrientedKernel(iBuilder, "filesink", {Binding{iBuilder->getStreamSetTy(1, codeUnitWidth), "codeUnitBuffer"}}, {},
145                {Binding{iBuilder->getInt8PtrTy(), "fileName"}}, {}, {Binding{iBuilder->getFILEptrTy(), "IOstreamPtr"}})
146, mCodeUnitWidth(codeUnitWidth) {
147}
148
149}
150
151
152
153
Note: See TracBrowser for help on using the repository browser.