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

Last change on this file since 5618 was 5618, checked in by cameron, 20 months ago

Dynamic buffer tracing; calculations for available items/blocks in reverse mode

File size: 16.3 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 * streamIndex, llvm::Value * blockIndex, const bool readOnly) const;
67
68    virtual llvm::Value * getStreamPackPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * blockIndex, 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 * streamIndex, 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 * fromPosition, bool reverse = false) const;
86   
87    virtual llvm::Value * getLinearlyAccessibleBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) 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 llvm::Value * getLinearlyWritableBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) const;
96   
97    virtual ~StreamSetBuffer() = 0;
98
99    kernel::Kernel * getProducer() const {
100        return mProducer;
101    }
102
103    const std::vector<kernel::Kernel *> & getConsumers() const {
104        return mConsumers;
105    }
106
107protected:
108
109    StreamSetBuffer(BufferKind k, llvm::Type * baseType, llvm::Type * resolvedType, unsigned BufferBlocks, unsigned AddressSpace);
110
111    // Get the buffer pointer for a given block of the stream set.
112    virtual llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const = 0;
113
114    bool isCapacityGuaranteed(const llvm::Value * const index, const size_t capacity) const;
115
116    llvm::Value * modByBufferBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * const offset) const;
117
118    virtual llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const;
119
120    void setProducer(kernel::Kernel * const producer) {
121        assert (producer);
122        mProducer = producer;
123    }
124
125    void addConsumer(kernel::Kernel * const consumer) {
126        assert (consumer);
127        mConsumers.push_back(consumer);
128    }
129
130protected:
131    const BufferKind                 mBufferKind;
132    llvm::Type * const               mType;
133    const size_t                     mBufferBlocks;
134    const unsigned                   mAddressSpace;
135    llvm::Value *                    mStreamSetBufferPtr;
136    llvm::Type * const               mBaseType;
137    std::string                      mUniqueID;
138    kernel::Kernel *                 mProducer;
139    std::vector<kernel::Kernel *>    mConsumers;
140};   
141
142class SourceBuffer final : public StreamSetBuffer {
143public:
144    static inline bool classof(const StreamSetBuffer * b) {
145        return b->getBufferKind() == BufferKind::SourceBuffer;
146    }
147
148    SourceBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, unsigned MemoryAddressSpace = 0, unsigned StructAddressSpace = 0);
149
150    void setBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * addr) const override;
151
152    void setBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * size) const override;
153
154    void setCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * c) const override;
155
156    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
157   
158    llvm::Value * getCapacity(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
159   
160    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
161   
162    llvm::Value * getLinearlyAccessibleBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) const override;
163
164    llvm::Type * getStreamSetBlockType() const override;
165
166    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) override;
167
168    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
169
170protected:
171   
172    enum class Field {BaseAddress, BufferedSize, Capacity};
173
174    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
175
176    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const override;
177
178};
179
180class ExternalBuffer final : public StreamSetBuffer {
181public:
182    static inline bool classof(const StreamSetBuffer * b) {
183        return b->getBufferKind() == BufferKind::ExternalBuffer;
184    }
185
186    ExternalBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, llvm::Value * addr, unsigned AddressSpace = 0);
187
188    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
189
190    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
191
192    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
193
194protected:
195    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockNo) const override;
196};
197
198class CircularBuffer : public StreamSetBuffer {
199public:
200    static inline bool classof(const StreamSetBuffer * b) {
201        return b->getBufferKind() == BufferKind::CircularBuffer;
202    }
203   
204    CircularBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
205
206    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * absolutePosition) const final;
207
208protected:
209
210    CircularBuffer(const BufferKind kind, const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
211
212    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockIndex) const final;
213};
214   
215
216//
217//  A CircularCopybackBuffer operates as a circular buffer buffer with an overflow area
218//  for temporary use by the kernel that writes to it.   If the kernel uses the overflow
219//  area, it must perform the doCopyBack action before releasing the buffer for use by
220//  subsequent kernels.
221//  Kernels that read from a CircularCopybackBuffer must not access the overflow area.
222//
223class CircularCopybackBuffer final : public CircularBuffer {
224public:
225    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::CircularCopybackBuffer;}
226   
227    CircularCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace = 0);
228   
229    // Generate copyback code for the given number of overflowItems.
230    void createCopyBack(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * overflowItems) const;
231       
232    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
233   
234    llvm::Value * getLinearlyWritableBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) const override;
235
236    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
237
238private:
239    size_t mOverflowBlocks;
240
241};
242   
243class SwizzledCopybackBuffer final : public StreamSetBuffer {
244public:
245    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::SwizzledCopybackBuffer;}
246   
247    SwizzledCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned fieldwidth = 64, unsigned AddressSpace = 0);
248       
249    void createBlockAlignedCopy(IDISA::IDISA_Builder * const iBuilder, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy) const override;
250
251    // Generate copyback code for the given number of overflowItems.
252    void createCopyBack(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * overflowItems) const;
253   
254    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
255   
256    llvm::Value * getLinearlyWritableBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) const override;
257   
258    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) override;
259
260protected:
261    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * blockIndex) const override;
262private:
263    size_t mOverflowBlocks;
264    unsigned mFieldWidth;
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 iBuilder, llvm::Value * self, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const override;
278
279    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;
280
281    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromPosition, bool reverse = false) const override;
282
283    llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
284
285    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & iBuilder) 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 iBuilder, llvm::Value * self) const override;
292
293    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const iBuilder, llvm::Value * blockIndex, llvm::Value *) const override;
294
295private:
296
297    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;
298
299private:
300
301    const uint64_t  mInitialCapacity;
302
303};
304   
305// Dynamically allocated circular buffers: TODO: add copyback, swizzle support, dynamic allocation, producer, consumer, length
306class DynamicBuffer: public StreamSetBuffer {
307public:
308    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::DynamicBuffer;}
309   
310    DynamicBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t initialCapacity, size_t overflowBlocks = 0, unsigned swizzleFactor = 1, unsigned addrSpace = 0);
311   
312    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, bool reverse = false) const override;
313   
314    llvm::Value * getLinearlyAccessibleBlocks(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self, llvm::Value * fromBlock, bool reverse = false) const override;
315
316    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
317
318    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
319
320    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * streamIndex, llvm::Value * absolutePosition) const override;
321   
322    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const iBuilder, llvm::Value * self) const override;
323   
324    void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle);
325
326
327protected:
328    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
329   
330    llvm::Value * getStreamSetBlockPtr(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
331
332   
333private:
334    /* Static data */
335    llvm::Type * mBufferStructType;      /* The type of the buffer struct. */
336    unsigned   mSwizzleFactor;     /* Number of streams swizzled together per block.  Must be a small power of 2. Default: 1. */
337    size_t     mOverflowBlocks;    /* Number of data blocks of additional space at the end of the buffer for writing only. */
338   
339    /* Dynamic data fields stored in the buffer struct */
340   
341    enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
342   
343    /* BaseAddress - the physical base address of the memory area for stream set data.
344     PriorBaseAddress - the physical base address of the previous memory area for stream set data
345     (the immediately prior memory area is preserved in case any users in other threads
346     are accessing it).
347     WorkingBlocks - the physical size of the buffer for use in reading and writing data.
348     AllocatedCapacity - physical size available for expansion in place
349     Length - actual final length of stream set or -1 for unknown
350     ProducedPosition - the total number of items ever generated and stored in the buffer
351     ConsumedPosition - the number of buffer items that are known to have been fully processed by all users
352     */
353   
354};
355
356
357}
358#endif // STREAMSET_H
Note: See TracBrowser for help on using the repository browser.