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

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

Removed 'function' and 'self' parameters from generateXXXMethod() functions.

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