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

Last change on this file since 5793 was 5793, checked in by nmedfort, 16 months ago

Bug fix for pipeline: it was terminating too early when there was insufficient output space to process all of the input for a kernel.

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