source: icGREP/icgrep-devel/icgrep/kernels/kernel.h @ 5283

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

Optimized Symbol Generation (and fixed potential bug that could allow duplicate names being constructed); made PabloKernel? extend PabloAST (temporarily removed PabloAST::getName() to avoid diamond problem); added an internal scalar to PabloKernel? struct for each Count to avoid InOut? output scalar variable problem; allowed CodeMotionPass? to move code within the same scope but across a branch statement. Began work on separating Kernels into either Block-Oriented or Segment-Oriented kernels.

File size: 10.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
6#ifndef KERNEL_BUILDER_H
7#define KERNEL_BUILDER_H
8
9#include <string>           // for string
10#include <memory>           // for unique_ptr
11#include "interface.h"      // for KernelInterface
12#include <boost/container/flat_map.hpp>
13#include <IR_Gen/idisa_builder.h>
14namespace llvm { class ConstantInt; }
15namespace llvm { class Function; }
16namespace llvm { class IntegerType; }
17namespace llvm { class LoadInst; }
18namespace llvm { class Type; }
19namespace llvm { class Value; }
20namespace parabix { class StreamSetBuffer; }
21
22const std::string blockNoScalar = "blockNo";
23const std::string logicalSegmentNoScalar = "logicalSegNo";
24const std::string processedItemCountSuffix = "_processedItemCount";
25const std::string producedItemCountSuffix = "_producedItemCount";
26const std::string terminationSignal = "terminationSignal";
27const std::string bufferPtrSuffix = "_bufferPtr";
28const std::string blkMaskSuffix = "_blkMask";
29
30namespace kernel {
31   
32class KernelBuilder : public KernelInterface {
33    using NameMap = boost::container::flat_map<std::string, unsigned>;
34public:
35   
36    // Create a module for the kernel, including the kernel state type declaration and
37    // the full implementation of all required methods.     
38    //
39    std::unique_ptr<llvm::Module> createKernelModule(const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs);
40   
41    // Generate the Kernel to the current module (iBuilder->getModule()).
42    void generateKernel(const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs);
43   
44    void createInstance() override;
45
46    llvm::Value * getBlockNo(llvm::Value * self) const;
47
48    virtual llvm::Value * getProcessedItemCount(llvm::Value * self, const std::string & ssName) const override;
49
50    virtual llvm::Value * getProducedItemCount(llvm::Value * self, const std::string & ssName) const override;
51   
52    bool hasNoTerminateAttribute() { return mNoTerminateAttribute;}
53   
54    llvm::Value * getTerminationSignal(llvm::Value * self) const override;
55   
56    inline llvm::IntegerType * getSizeTy() const {
57        return getBuilder()->getSizeTy();
58    }
59
60    inline llvm::Type * getStreamTy(const unsigned FieldWidth = 1) {
61        return getBuilder()->getStreamTy(FieldWidth);
62    }
63   
64    inline llvm::Type * getStreamSetTy(const unsigned NumElements = 1, const unsigned FieldWidth = 1) {
65        return getBuilder()->getStreamSetTy(NumElements, FieldWidth);
66    }
67   
68    // Synchronization actions for executing a kernel for a particular logical segment.
69    //
70    // Before the segment is processed, acquireLogicalSegmentNo must be used to load
71    // the segment number of the kernel state to ensure that the previous segment is
72    // complete (by checking that the acquired segment number is equal to the desired segment
73    // number).
74    // After all segment processing actions for the kernel are complete, and any necessary
75    // data has been extracted from the kernel for further pipeline processing, the
76    // segment number must be incremented and stored using releaseLogicalSegmentNo.
77    llvm::LoadInst * acquireLogicalSegmentNo(llvm::Value * self) const;
78
79    void releaseLogicalSegmentNo(llvm::Value * self, llvm::Value * newFieldVal) const;
80
81    virtual ~KernelBuilder() = 0;
82   
83    const std::vector<const parabix::StreamSetBuffer *> & getStreamSetInputBuffers() const { return mStreamSetInputBuffers; }
84
85    const std::vector<const parabix::StreamSetBuffer *> & getStreamSetOutputBuffers() const { return mStreamSetOutputBuffers; }
86
87    void setTerminationSignal(llvm::Value * self) const;
88
89protected:
90
91    // Constructor
92    KernelBuilder(IDISA::IDISA_Builder * builder,
93                    std::string && kernelName,
94                    std::vector<Binding> && stream_inputs,
95                    std::vector<Binding> && stream_outputs,
96                    std::vector<Binding> && scalar_parameters,
97                    std::vector<Binding> && scalar_outputs,
98                    std::vector<Binding> && internal_scalars);
99
100    //
101    // Kernel builder subtypes define their logic of kernel construction
102    // in terms of 3 virtual methods for
103    // (a) preparing the Kernel state data structure
104    // (b) defining the logic of the doBlock function, and
105    // (c) defining the logic of the finalBlock function.
106    //
107    // Note: the kernel state data structure must only be finalized after
108    // all scalar fields have been added.   If there are no fields to
109    // be added, the default method for preparing kernel state may be used.
110   
111    void setNoTerminateAttribute(const bool noTerminate = true) {
112        mNoTerminateAttribute = noTerminate;
113    }
114
115    void setDoBlockUpdatesProducedItemCountsAttribute(const bool doesUpdate = true) {
116        mDoBlockUpdatesProducedItemCountsAttribute = doesUpdate;
117    }
118   
119    virtual void prepareKernel();
120       
121    virtual void generateInitMethod() const;
122   
123    virtual void generateDoSegmentMethod() const = 0;
124   
125    // Add an additional scalar field to the KernelState struct.
126    // Must occur before any call to addKernelDeclarations or createKernelModule.
127    unsigned addScalar(llvm::Type * type, const std::string & name);
128
129    unsigned addUnnamedScalar(llvm::Type * type);
130
131    unsigned getScalarCount() const;
132
133    // Run-time access of Kernel State and parameters of methods for
134    // use in implementing kernels.
135   
136    // Get the index of a named scalar field within the kernel state struct.
137    llvm::ConstantInt * getScalarIndex(const std::string & name) const;
138   
139    // Get the value of a scalar field for a given instance.
140    llvm::Value * getScalarField(llvm::Value * self, const std::string & fieldName) const;
141
142    llvm::Value * getScalarField(llvm::Value * self, llvm::Value * index) const;
143
144    // Set the value of a scalar field for a given instance.
145    void setScalarField(llvm::Value * self, const std::string & fieldName, llvm::Value * value) const;
146
147    void setScalarField(llvm::Value * self, llvm::Value * index, llvm::Value * value) const;
148
149    // Get a parameter by name.
150    llvm::Argument * getParameter(llvm::Function * f, const std::string & name) const;
151
152    llvm::Value * getStream(llvm::Value * self, const std::string & name, llvm::Value * blockNo, llvm::Value * index) const;
153
154    llvm::Value * getStream(llvm::Value * self, const std::string & name, llvm::Value * blockNo, llvm::Value * index1, llvm::Value * index2) const;
155
156    llvm::Value * getStreamView(llvm::Value * self, const std::string & name, llvm::Value * blockNo, llvm::Value * index) const;
157
158    llvm::Value * getStreamView(llvm::Type * type, llvm::Value * self, const std::string & name, llvm::Value * blockNo, llvm::Value * index) const;
159
160    // Stream set helpers.
161    unsigned getStreamSetIndex(const std::string & name) const;
162   
163    llvm::Value * getScalarFieldPtr(llvm::Value * self, const std::string & name) const;
164
165    llvm::Value * getScalarFieldPtr(llvm::Value * self, llvm::Value * index) const;
166
167    llvm::Value * getStreamSetBufferPtr(llvm::Value * self, const std::string & name) const;
168
169    llvm::Value * getStreamSetBufferPtr(llvm::Value * self, llvm::Value * index) const;
170
171    llvm::Value * getStreamSetPtr(llvm::Value * self, const std::string & name, llvm::Value * blockNo) const;
172   
173    void setBlockNo(llvm::Value * self, llvm::Value * value) const;
174
175    virtual void setProcessedItemCount(llvm::Value * self, const std::string & name, llvm::Value * value) const;
176
177    virtual void setProducedItemCount(llvm::Value * self, const std::string & name, llvm::Value * value) const;
178
179protected:
180
181    const parabix::StreamSetBuffer * getStreamSetBuffer(const std::string & name) const;
182
183protected:
184
185    std::vector<llvm::Type *>                       mKernelFields;
186    NameMap                                         mKernelMap;
187    NameMap                                         mStreamSetNameMap;
188    std::vector<const parabix::StreamSetBuffer *>   mStreamSetInputBuffers;
189    std::vector<const parabix::StreamSetBuffer *>   mStreamSetOutputBuffers;
190    bool                                            mNoTerminateAttribute;
191    bool                                            mDoBlockUpdatesProducedItemCountsAttribute;
192
193};
194
195class BlockOrientedKernel : public KernelBuilder {
196protected:
197
198    // Each kernel builder subtype must provide its own logic for generating
199    // doBlock calls.
200    virtual void generateDoBlockMethod() const = 0;
201
202    virtual void generateDoBlockLogic(llvm::Value * self, llvm::Value * blockNo) const;
203
204    // Each kernel builder subtypre must also specify the logic for processing the
205    // final block of stream data, if there is any special processing required
206    // beyond simply calling the doBlock function.   In the case that the final block
207    // processing may be trivially implemented by dispatching to the doBlock method
208    // without additional preparation, the default generateFinalBlockMethod need
209    // not be overridden.
210
211    virtual void generateFinalBlockMethod() const;
212
213    virtual void generateDoSegmentMethod() const final;
214
215    BlockOrientedKernel(IDISA::IDISA_Builder * builder,
216                        std::string && kernelName,
217                        std::vector<Binding> && stream_inputs,
218                        std::vector<Binding> && stream_outputs,
219                        std::vector<Binding> && scalar_parameters,
220                        std::vector<Binding> && scalar_outputs,
221                        std::vector<Binding> && internal_scalars);
222
223    virtual ~BlockOrientedKernel() { }
224};
225
226class SegmentOrientedKernel : public KernelBuilder {
227protected:
228    SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
229                          std::string && kernelName,
230                          std::vector<Binding> && stream_inputs,
231                          std::vector<Binding> && stream_outputs,
232                          std::vector<Binding> && scalar_parameters,
233                          std::vector<Binding> && scalar_outputs,
234                          std::vector<Binding> && internal_scalars);
235
236    virtual ~SegmentOrientedKernel() { }
237};
238
239
240
241}
242#endif
Note: See TracBrowser for help on using the repository browser.