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

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

Bug fixes for last check in

File size: 13.5 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>
14
15//namespace llvm { class ConstantInt; }
16#include <llvm/IR/Constants.h>
17namespace llvm { class Function; }
18namespace llvm { class IntegerType; }
19namespace llvm { class LoadInst; }
20namespace llvm { class Type; }
21namespace llvm { class Value; }
22namespace parabix { class StreamSetBuffer; }
23
24namespace kernel {
25   
26class KernelBuilder : public KernelInterface {
27    using NameMap = boost::container::flat_map<std::string, unsigned>;
28public:
29   
30    // Create a module for the kernel, including the kernel state type declaration and
31    // the full implementation of all required methods.     
32    //
33    std::unique_ptr<llvm::Module> createKernelModule(const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs);
34   
35    // Generate the Kernel to the current module (iBuilder->getModule()).
36    void generateKernel(const std::vector<parabix::StreamSetBuffer *> & inputs, const std::vector<parabix::StreamSetBuffer *> & outputs);
37   
38    void createInstance() override;
39
40    virtual llvm::Value * getProcessedItemCount(llvm::Value * instance, const std::string & name) const override;
41
42    virtual void setProcessedItemCount(llvm::Value * instance, const std::string & name, llvm::Value * value) const;
43
44    llvm::Value * getProducedItemCount(llvm::Value * instance, const std::string & name, llvm::Value * doFinal) const;
45
46    llvm::Value * getProducedItemCount(llvm::Value * instance, const std::string & name) const;
47
48    virtual void setProducedItemCount(llvm::Value * instance, const std::string & name, llvm::Value * value) const;
49
50    virtual void reserveBytes(llvm::Value * instance, const std::string & name, llvm::Value * requested) const;
51
52    bool hasNoTerminateAttribute() { return mNoTerminateAttribute;}
53   
54    llvm::Value * getTerminationSignal(llvm::Value * instance) const override final;
55
56    void setTerminationSignal(llvm::Value * instance) const override final;
57
58    // Get the value of a scalar field for a given instance.
59    llvm::Value * getScalarField(llvm::Value * instance, const std::string & fieldName) const;
60
61    llvm::Value * getScalarField(llvm::Value * instance, llvm::Value * index) const;
62
63    // Set the value of a scalar field for a given instance.
64    void setScalarField(llvm::Value *instance, const std::string & fieldName, llvm::Value * value) const;
65
66    void setScalarField(llvm::Value * instance, llvm::Value * index, llvm::Value * value) const;
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 * instance) const;
78
79    void releaseLogicalSegmentNo(llvm::Value * instance, llvm::Value * newFieldVal) const;
80
81    // Get a parameter by name.
82    llvm::Argument * getParameter(llvm::Function * f, const std::string & name) const;
83
84    inline llvm::IntegerType * getSizeTy() const {
85        return getBuilder()->getSizeTy();
86    }
87
88    inline llvm::Type * getStreamTy(const unsigned FieldWidth = 1) {
89        return getBuilder()->getStreamTy(FieldWidth);
90    }
91   
92    inline llvm::Type * getStreamSetTy(const unsigned NumElements = 1, const unsigned FieldWidth = 1) {
93        return getBuilder()->getStreamSetTy(NumElements, FieldWidth);
94    }
95   
96    virtual ~KernelBuilder() = 0;
97   
98    const std::vector<const parabix::StreamSetBuffer *> & getStreamSetInputBuffers() const { return mStreamSetInputBuffers; }
99
100    const std::vector<const parabix::StreamSetBuffer *> & getStreamSetOutputBuffers() const { return mStreamSetOutputBuffers; }
101
102    llvm::Value * createDoSegmentCall(const std::vector<llvm::Value *> & args) const;
103
104    llvm::Value * createGetAccumulatorCall(llvm::Value * self, const std::string & accumName) const;
105
106protected:
107
108    // Constructor
109    KernelBuilder(IDISA::IDISA_Builder * builder,
110                    std::string && kernelName,
111                    std::vector<Binding> && stream_inputs,
112                    std::vector<Binding> && stream_outputs,
113                    std::vector<Binding> && scalar_parameters,
114                    std::vector<Binding> && scalar_outputs,
115                    std::vector<Binding> && internal_scalars);
116
117    //
118    // Kernel builder subtypes define their logic of kernel construction
119    // in terms of 3 virtual methods for
120    // (a) preparing the Kernel state data structure
121    // (b) defining the logic of the doBlock function, and
122    // (c) defining the logic of the finalBlock function.
123    //
124    // Note: the kernel state data structure must only be finalized after
125    // all scalar fields have been added.   If there are no fields to
126    // be added, the default method for preparing kernel state may be used.
127   
128    void setNoTerminateAttribute(const bool noTerminate = true) {
129        mNoTerminateAttribute = noTerminate;
130    }
131
132    void prepareKernelSignature();
133
134    virtual void prepareKernel();
135
136    virtual void generateInitMethod() { }
137   
138    virtual void generateDoSegmentMethod(llvm::Value * doFinal, const std::vector<llvm::Value *> & producerPos) = 0;
139
140    // Add an additional scalar field to the KernelState struct.
141    // Must occur before any call to addKernelDeclarations or createKernelModule.
142    unsigned addScalar(llvm::Type * type, const std::string & name);
143
144    unsigned addUnnamedScalar(llvm::Type * type);
145
146    unsigned getScalarCount() const;
147
148    // Run-time access of Kernel State and parameters of methods for
149    // use in implementing kernels.
150   
151    // Get the index of a named scalar field within the kernel state struct.
152    llvm::ConstantInt * getScalarIndex(const std::string & name) const;
153
154    // Get the value of a scalar field for a given instance.
155    llvm::Value * getScalarField(const std::string & fieldName) const {
156        return getScalarField(getSelf(), fieldName);
157    }
158
159    llvm::Value * getScalarField(llvm::Value * index) const {
160        return getScalarField(getSelf(), index);
161    }
162
163    // Set the value of a scalar field for a given instance.
164    void setScalarField(const std::string & fieldName, llvm::Value * value) const {
165        return setScalarField(getSelf(), fieldName, value);
166    }
167
168    void setScalarField(llvm::Value * index, llvm::Value * value) const {
169        return setScalarField(getSelf(), index, value);
170    }
171
172    llvm::Value * getInputStreamBlockPtr(const std::string & name, llvm::Value * streamIndex) const;
173
174    llvm::Value * loadInputStreamBlock(const std::string & name, llvm::Value * streamIndex) const;
175   
176    llvm::Value * getInputStreamPackPtr(const std::string & name, llvm::Value * streamIndex, llvm::Value * packIndex) const;
177   
178    llvm::Value * loadInputStreamPack(const std::string & name, llvm::Value * streamIndex, llvm::Value * packIndex) const;
179   
180    llvm::Value * getInputStreamSetCount(const std::string & name) const;
181
182    llvm::Value * getOutputStreamBlockPtr(const std::string & name, llvm::Value * streamIndex) const;
183   
184    void storeOutputStreamBlock(const std::string & name, llvm::Value * streamIndex, llvm::Value * toStore) const;
185   
186    llvm::Value * getOutputStreamPackPtr(const std::string & name, llvm::Value * streamIndex, llvm::Value * packIndex) const;
187   
188    void storeOutputStreamPack(const std::string & name, llvm::Value * streamIndex, llvm::Value * packIndex, llvm::Value * toStore) const;
189
190    llvm::Value * getOutputStreamSetCount(const std::string & name) const;
191
192    llvm::Value * getAdjustedInputStreamBlockPtr(llvm::Value * blockAdjustment, const std::string & name, llvm::Value * streamIndex) const;
193
194    llvm::Value * getRawInputPointer(const std::string & name, llvm::Value * streamIndex, llvm::Value * absolutePosition) const;
195
196    llvm::Value * getRawOutputPointer(const std::string & name, llvm::Value * streamIndex, llvm::Value * absolutePosition) const;
197
198    void reserveBytes(const std::string & name, llvm::Value * requested) const {
199        reserveBytes(getSelf(), name, requested);
200    }
201
202    llvm::Value * getScalarFieldPtr(const std::string & name) const {
203        return getScalarFieldPtr(getSelf(), name);
204    }
205
206    llvm::Value * getScalarFieldPtr(llvm::Value * index) const {
207        return getScalarFieldPtr(getSelf(), index);
208    }
209
210    inline llvm::Value * getProcessedItemCount(const std::string & name) const {
211        return getProcessedItemCount(getSelf(), name);
212    }
213
214    inline void setProcessedItemCount(const std::string & name, llvm::Value * value) const {
215        setProcessedItemCount(getSelf(), name, value);
216    }
217
218    inline llvm::Value * getProducedItemCount(const std::string & name) const {
219        return getProducedItemCount(getSelf(), name);
220    }
221
222    inline void setProducedItemCount(const std::string & name, llvm::Value * value) const {
223        setProducedItemCount(getSelf(), name, value);
224    }
225
226    llvm::Value * getTerminationSignal() const {
227        return getTerminationSignal(getSelf());
228    }
229
230    void setTerminationSignal() const {
231        return setTerminationSignal(getSelf());
232    }
233
234    llvm::Value * getSelf() const {
235        return mSelf;
236    }
237
238    llvm::BasicBlock * CreateBasicBlock(std::string && name) const;
239
240    // Stream set helpers.
241
242    llvm::Value * getStreamSetBufferPtr(const std::string & name) const;
243
244    llvm::Value * getScalarFieldPtr(llvm::Value * instance, const std::string & name) const;
245
246    llvm::Value * getScalarFieldPtr(llvm::Value * instance, llvm::Value * index) const;
247
248    unsigned getStreamSetIndex(const std::string & name) const;
249
250    const parabix::StreamSetBuffer * getInputStreamSetBuffer(const std::string & name) const {
251        return mStreamSetInputBuffers[getStreamSetIndex(name)];
252    }
253
254    const parabix::StreamSetBuffer * getOutputStreamSetBuffer(const std::string & name) const {
255        return mStreamSetOutputBuffers[getStreamSetIndex(name)];
256    }
257
258    void callGenerateInitMethod();
259
260    void callGenerateDoSegmentMethod();
261
262private:
263
264    llvm::Value * computeBlockIndex(const std::vector<Binding> & binding, const std::string & name, llvm::Value * itemCount) const;
265
266protected:
267
268    llvm::Value *                                   mSelf;
269    llvm::Function *                                mCurrentMethod;
270
271    std::vector<llvm::Type *>                       mKernelFields;
272    NameMap                                         mKernelMap;
273    NameMap                                         mStreamSetNameMap;
274    std::vector<const parabix::StreamSetBuffer *>   mStreamSetInputBuffers;
275    std::vector<const parabix::StreamSetBuffer *>   mStreamSetOutputBuffers;
276    bool                                            mNoTerminateAttribute;
277
278};
279
280class SegmentOrientedKernel : public KernelBuilder {
281protected:
282
283    SegmentOrientedKernel(IDISA::IDISA_Builder * builder,
284                          std::string && kernelName,
285                          std::vector<Binding> && stream_inputs,
286                          std::vector<Binding> && stream_outputs,
287                          std::vector<Binding> && scalar_parameters,
288                          std::vector<Binding> && scalar_outputs,
289                          std::vector<Binding> && internal_scalars);
290
291    virtual ~SegmentOrientedKernel() { }
292
293};
294
295class BlockOrientedKernel : public KernelBuilder {
296protected:
297
298    void CreateDoBlockMethodCall();
299
300    // Each kernel builder subtype must provide its own logic for generating
301    // doBlock calls.
302    virtual void generateDoBlockMethod() = 0;
303
304    // Each kernel builder subtypre must also specify the logic for processing the
305    // final block of stream data, if there is any special processing required
306    // beyond simply calling the doBlock function.   In the case that the final block
307    // processing may be trivially implemented by dispatching to the doBlock method
308    // without additional preparation, the default generateFinalBlockMethod need
309    // not be overridden.
310
311    virtual void generateFinalBlockMethod(llvm::Value * remainingItems);
312
313    void generateDoSegmentMethod(llvm::Value * doFinal, const std::vector<llvm::Value *> & producerPos) override final;
314
315    BlockOrientedKernel(IDISA::IDISA_Builder * builder,
316                        std::string && kernelName,
317                        std::vector<Binding> && stream_inputs,
318                        std::vector<Binding> && stream_outputs,
319                        std::vector<Binding> && scalar_parameters,
320                        std::vector<Binding> && scalar_outputs,
321                        std::vector<Binding> && internal_scalars);
322
323    virtual ~BlockOrientedKernel() { }
324
325private:
326
327    bool useIndirectBr() const {
328        return iBuilder->supportsIndirectBr();
329    }
330
331    void writeDoBlockMethod();
332
333    void writeFinalBlockMethod(llvm::Value * remainingItems);
334
335private:
336
337    llvm::Function *        mDoBlockMethod;
338    llvm::BasicBlock *      mStrideLoopBody;
339    llvm::IndirectBrInst *  mStrideLoopBranch;
340    llvm::PHINode *         mStrideLoopTarget;
341};
342
343
344}
345#endif
Note: See TracBrowser for help on using the repository browser.