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

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

More changes towards simplifying the KernelBuilder?

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