source: icGREP/icgrep-devel/icgrep/kernels/streamset.h @ 5706

Last change on this file since 5706 was 5706, checked in by nmedfort, 19 months ago

First stage of MultiBlockKernel? and pipeline restructuring

File size: 16.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 STREAMSET_H
7#define STREAMSET_H
8
9#include <llvm/IR/Type.h>  // for Type
10namespace IDISA { class IDISA_Builder; }
11namespace llvm { class Value; }
12namespace kernel { class Kernel; }
13namespace kernel { class KernelBuilder; }
14
15namespace parabix {
16   
17class StreamSetBuffer {
18    friend class kernel::Kernel;
19    friend class kernel::KernelBuilder;
20public:
21
22    enum class BufferKind : unsigned {
23        SourceBuffer
24        , ExternalBuffer
25        , CircularBuffer
26        , CircularCopybackBuffer
27        , SwizzledCopybackBuffer
28        , ExpandableBuffer
29        , DynamicBuffer
30    };
31
32    BufferKind getBufferKind() const {
33        return mBufferKind;
34    }
35   
36    std::string getUniqueID() const {
37        return mUniqueID;
38    }
39
40    llvm::Type * getType() const {
41        return mType;
42    }
43   
44    llvm::Type * getBaseType() const {
45        return mBaseType;
46    }
47
48    llvm::PointerType * getPointerType() const {
49        return getType()->getPointerTo(mAddressSpace);
50    }
51
52    size_t getBufferBlocks() const {
53        return mBufferBlocks;
54    }
55
56    llvm::Value * getStreamSetHandle() const {
57        return mStreamSetBufferPtr;
58    }
59   
60    virtual llvm::Type * getStreamSetBlockType() const;
61   
62    virtual void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb);
63
64    virtual void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const;
65
66    virtual llvm::Value * getStreamBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * addr, llvm::Value * streamIndex, const bool readOnly) const;
67
68    virtual llvm::Value * getStreamPackPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * packIndex, const bool readOnly) const;
69   
70    virtual llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const;
71
72    virtual llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * absolutePosition) const;
73
74    virtual void setBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * addr, llvm::Value *) const;
75
76    virtual void setBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * size, llvm::Value *) const;
77   
78    virtual llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const;
79   
80    virtual void setCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * size, llvm::Value *) const;
81   
82    virtual llvm::Value * getCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const;
83   
84    // The number of items that cam be linearly accessed from a given logical stream position.
85    virtual llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPos, llvm::Value * avail, bool reverse = false) const;
86   
87    virtual llvm::Value * copy(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * target, llvm::Value * source, llvm::Value * itemsToCopy, const unsigned alignment = 0) const;
88
89    void createBlockCopy(IDISA::IDISA_Builder * const iBuilder, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * blocksToCopy) const;
90
91    virtual void createBlockAlignedCopy(IDISA::IDISA_Builder * const iBuilder, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy) const;
92
93    virtual llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const;
94   
95    virtual bool supportsCopyBack() const {
96        return false;  // Overridden to return true by buffer types that support copyback.
97    }
98    virtual void genCopyBackLogic(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * priorProduced, llvm::Value * newProduced, const std::string) const;
99   
100    virtual ~StreamSetBuffer() = 0;
101
102    kernel::Kernel * getProducer() const {
103        return mProducer;
104    }
105
106    const std::vector<kernel::Kernel *> & getConsumers() const {
107        return mConsumers;
108    }
109
110protected:
111
112    StreamSetBuffer(BufferKind k, llvm::Type * baseType, llvm::Type * resolvedType, unsigned BufferBlocks, unsigned AddressSpace);
113
114    // Get the buffer pointer for a given block of the stream set.
115    virtual llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const = 0;
116
117    bool isCapacityGuaranteed(const llvm::Value * const index, const size_t capacity) const;
118
119    llvm::Value * modByBufferBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * const offset) const;
120
121    virtual llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const;
122
123    void setProducer(kernel::Kernel * const producer) {
124        assert (producer);
125        mProducer = producer;
126    }
127
128    void addConsumer(kernel::Kernel * const consumer) {
129        assert (consumer);
130        mConsumers.push_back(consumer);
131    }
132
133protected:
134    const BufferKind                 mBufferKind;
135    llvm::Type * const               mType;
136    const size_t                     mBufferBlocks;
137    const unsigned                   mAddressSpace;
138    llvm::Value *                    mStreamSetBufferPtr;
139    llvm::Type * const               mBaseType;
140    std::string                      mUniqueID;
141    kernel::Kernel *                 mProducer;
142    std::vector<kernel::Kernel *>    mConsumers;
143};   
144
145class SourceBuffer final : public StreamSetBuffer {
146public:
147    static inline bool classof(const StreamSetBuffer * b) {
148        return b->getBufferKind() == BufferKind::SourceBuffer;
149    }
150
151    SourceBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, unsigned MemoryAddressSpace = 0, unsigned StructAddressSpace = 0);
152
153    void setBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * addr) const override;
154
155    void setBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * size) const override;
156
157    void setCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * c) const override;
158
159    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
160   
161    llvm::Value * getCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
162   
163    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const override;
164
165    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
166
167    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
168
169    llvm::Type * getStreamSetBlockType() const override;
170
171    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) override;
172
173    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
174
175protected:
176   
177    enum class Field {BaseAddress, BufferedSize, Capacity};
178
179    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
180
181};
182
183class ExternalBuffer final : public StreamSetBuffer {
184public:
185    static inline bool classof(const StreamSetBuffer * b) {
186        return b->getBufferKind() == BufferKind::ExternalBuffer;
187    }
188
189    ExternalBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, llvm::Value * addr, unsigned AddressSpace = 0);
190
191    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
192   
193    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
194
195    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
196
197    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
198
199protected:
200    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const override;
201};
202
203class CircularBuffer : public StreamSetBuffer {
204public:
205    static inline bool classof(const StreamSetBuffer * b) {
206        return b->getBufferKind() == BufferKind::CircularBuffer;
207    }
208   
209    CircularBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
210
211    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * absolutePosition) const final;
212
213protected:
214
215    CircularBuffer(const BufferKind kind, const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
216
217    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockIndex) const final;
218};
219   
220
221//
222//  A CircularCopybackBuffer operates as a circular buffer buffer with an overflow area
223//  for temporary use by the kernel that writes to it.   If the kernel uses the overflow
224//  area, it must perform the doCopyBack action before releasing the buffer for use by
225//  subsequent kernels.
226//  Kernels that read from a CircularCopybackBuffer must not access the overflow area.
227//
228class CircularCopybackBuffer final : public CircularBuffer {
229public:
230    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::CircularCopybackBuffer;}
231   
232    CircularCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace = 0);
233   
234    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
235   
236    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
237
238    bool supportsCopyBack() const override {
239        return mOverflowBlocks > 0; 
240    }
241   
242    void genCopyBackLogic(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * priorProduced, llvm::Value * newProduced, const std::string) const override;
243   
244   
245private:
246    size_t mOverflowBlocks;
247
248};
249   
250class SwizzledCopybackBuffer final : public StreamSetBuffer {
251public:
252    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::SwizzledCopybackBuffer;}
253   
254    SwizzledCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned fieldwidth = 64, unsigned AddressSpace = 0);
255       
256    void createBlockAlignedCopy(IDISA::IDISA_Builder * const iBuilder, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy) const override;
257
258    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
259   
260    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
261
262    bool supportsCopyBack() const override {
263        return mOverflowBlocks > 0; 
264    }
265   
266    void genCopyBackLogic(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * priorProduced, llvm::Value * newProduced, const std::string) const override;
267
268protected:
269    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockIndex) const override;
270private:
271    size_t mOverflowBlocks;
272    unsigned mFieldWidth;
273   
274};
275
276// ExpandableBuffers do not allow access to the base stream set but will automatically increase the number of streams
277// within their set whenever the index exceeds its capacity
278//
279class ExpandableBuffer final : public StreamSetBuffer {
280public:
281    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::ExpandableBuffer;}
282
283    ExpandableBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
284
285    llvm::Value * getStreamBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const override;
286
287    llvm::Value * getStreamPackPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * blockIndex, llvm::Value * packIndex, const bool readOnly) const override;
288
289    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
290   
291    llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
292
293    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
294
295    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
296
297protected:
298
299    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
300
301    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * blockIndex, llvm::Value *) const override;
302
303private:
304
305    std::pair<llvm::Value *, llvm::Value *> getInternalStreamBuffer(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const;
306
307private:
308
309    const uint64_t  mInitialCapacity;
310
311};
312   
313// Dynamically allocated circular buffers: TODO: add copyback, swizzle support, dynamic allocation, producer, consumer, length
314class DynamicBuffer: public StreamSetBuffer {
315public:
316    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::DynamicBuffer;}
317   
318    DynamicBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t initialCapacity, size_t overflowBlocks = 0, unsigned swizzleFactor = 1, unsigned addrSpace = 0);
319   
320    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
321   
322    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
323   
324    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
325
326    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
327
328    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const override;
329   
330    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
331   
332    void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle);
333
334    bool supportsCopyBack() const override {
335        return mOverflowBlocks > 0; 
336    }
337       
338    void genCopyBackLogic(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * priorProduced, llvm::Value * newProduced, const std::string) const override;
339
340protected:
341    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
342   
343    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
344
345   
346private:
347    /* Static data */
348    llvm::Type * mBufferStructType;      /* The type of the buffer struct. */
349    unsigned   mSwizzleFactor;     /* Number of streams swizzled together per block.  Must be a small power of 2. Default: 1. */
350    size_t     mOverflowBlocks;    /* Number of data blocks of additional space at the end of the buffer for writing only. */
351   
352    /* Dynamic data fields stored in the buffer struct */
353   
354    enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
355   
356    /* BaseAddress - the physical base address of the memory area for stream set data.
357     PriorBaseAddress - the physical base address of the previous memory area for stream set data
358     (the immediately prior memory area is preserved in case any users in other threads
359     are accessing it).
360     WorkingBlocks - the physical size of the buffer for use in reading and writing data.
361     AllocatedCapacity - physical size available for expansion in place
362     Length - actual final length of stream set or -1 for unknown
363     ProducedPosition - the total number of items ever generated and stored in the buffer
364     ConsumedPosition - the number of buffer items that are known to have been fully processed by all users
365     */
366   
367};
368
369
370}
371#endif // STREAMSET_H
Note: See TracBrowser for help on using the repository browser.