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

Last change on this file since 5317 was 5317, checked in by cameron, 2 years ago

Simplify stream set access; better naming of access functions

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