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

Last change on this file since 5985 was 5985, checked in by nmedfort, 12 months ago

Restructured MultiBlock? kernel. Removal of Swizzled buffers. Inclusion of PopCount? rates / non-linear access. Modifications to several kernels to better align them with the kernel and pipeline changes.

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