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

Last change on this file since 5843 was 5843, checked in by cameron, 14 months ago

CC Compiler refactoring step

File size: 15.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    // 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 * addr, 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 * addr, 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 void createBlockAlignedCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy, const unsigned alignment = 1) const;
111
112    virtual llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const;
113   
114    bool supportsCopyBack() const {
115        return mOverflowBlocks != 0;
116    }
117
118    size_t overflowSize() const {
119        return mOverflowBlocks;
120    }
121   
122    virtual ~StreamSetBuffer() = 0;
123
124    kernel::Kernel * getProducer() const {
125        return mProducer;
126    }
127
128    const std::vector<kernel::Kernel *> & getConsumers() const {
129        return mConsumers;
130    }
131
132
133
134protected:
135
136    StreamSetBuffer(BufferKind k, llvm::Type * baseType, llvm::Type * resolvedType, unsigned BufferBlocks, unsigned OverflowBlocks, unsigned AddressSpace);
137
138    virtual llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockNo) const;
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    void setProducer(kernel::Kernel * const producer) {
147        assert (producer);
148        mProducer = producer;
149    }
150
151    void addConsumer(kernel::Kernel * const consumer) {
152        assert (consumer);
153        mConsumers.push_back(consumer);
154    }
155
156protected:
157    const BufferKind                 mBufferKind;
158    llvm::Type * const               mType;
159    const size_t                     mBufferBlocks;
160    size_t                           mOverflowBlocks;    /* Number of data blocks of additional space at the end of the buffer for writing only. */
161    const unsigned                   mAddressSpace;
162    llvm::Value *                    mStreamSetBufferPtr;
163    llvm::Type * const               mBaseType;
164    std::string                      mUniqueID;
165    kernel::Kernel *                 mProducer;
166    std::vector<kernel::Kernel *>    mConsumers;
167};   
168
169class SourceBuffer final : public StreamSetBuffer {
170public:
171    static inline bool classof(const StreamSetBuffer * b) {
172        return b->getBufferKind() == BufferKind::SourceBuffer;
173    }
174
175    SourceBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, unsigned MemoryAddressSpace = 0, unsigned StructAddressSpace = 0);
176
177    void setBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr) const override;
178
179    void setBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * size) const override;
180
181    void setCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * c) const override;
182
183    llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
184   
185    llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
186   
187    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
188
189    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override;
190
191    llvm::Type * getStreamSetBlockType() const override;
192
193    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) override;
194
195    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
196
197protected:
198   
199    enum class Field {BaseAddress, BufferedSize, Capacity};
200
201    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
202
203};
204
205class ExternalBuffer final : public StreamSetBuffer {
206public:
207    static inline bool classof(const StreamSetBuffer * b) {
208        return b->getBufferKind() == BufferKind::ExternalBuffer;
209    }
210
211    ExternalBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, llvm::Value * addr, unsigned AddressSpace = 0);
212
213    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
214   
215    llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override;
216
217    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
218
219    void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override;
220
221    llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
222};
223
224class CircularBuffer : public StreamSetBuffer {
225public:
226    static inline bool classof(const StreamSetBuffer * b) {
227        return b->getBufferKind() == BufferKind::CircularBuffer;
228    }
229   
230    CircularBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0);
231
232    llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const final;
233
234protected:
235
236    CircularBuffer(const BufferKind kind, const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace);
237
238    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const final;
239};
240   
241
242//
243//  A CircularCopybackBuffer operates as a circular buffer buffer with an overflow area
244//  for temporary use by the kernel that writes to it.   If the kernel uses the overflow
245//  area, it must perform the doCopyBack action before releasing the buffer for use by
246//  subsequent kernels.
247//  Kernels that read from a CircularCopybackBuffer must not access the overflow area.
248//
249class CircularCopybackBuffer final : public CircularBuffer {
250public:
251    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::CircularCopybackBuffer;}
252   
253    CircularCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace = 0);
254       
255    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
256
257};
258   
259class SwizzledCopybackBuffer final : public StreamSetBuffer {
260public:
261    static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::SwizzledCopybackBuffer;}
262   
263    SwizzledCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned fieldwidth = 64, unsigned AddressSpace = 0);
264       
265    void createBlockAlignedCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy, const unsigned alignment = 1) const override;
266
267    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override;
268
269protected:
270    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
271private:
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 b, llvm::Value * handle, llvm::Value * addr, llvm::Value * streamIndex, llvm::Value * blockIndex, const bool readOnly) const override;
286
287    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;
288
289    llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override;
290   
291    llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
292
293    void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) 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 b, llvm::Value * handle) const override;
300
301    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * blockIndex, llvm::Value *) const override;
302
303private:
304
305    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;
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 b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, 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 b, llvm::Value * handle) const override;
331   
332    void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle);
333
334protected:
335    llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override;
336   
337    llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override;
338
339   
340private:
341    /* Static data */
342    llvm::Type * mBufferStructType;      /* The type of the buffer struct. */
343    unsigned   mSwizzleFactor;     /* Number of streams swizzled together per block.  Must be a small power of 2. Default: 1. */
344   
345    /* Dynamic data fields stored in the buffer struct */
346   
347    enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount};
348   
349    /* BaseAddress - the physical base address of the memory area for stream set data.
350     PriorBaseAddress - the physical base address of the previous memory area for stream set data
351     (the immediately prior memory area is preserved in case any users in other threads
352     are accessing it).
353     WorkingBlocks - the physical size of the buffer for use in reading and writing data.
354     AllocatedCapacity - physical size available for expansion in place
355     Length - actual final length of stream set or -1 for unknown
356     ProducedPosition - the total number of items ever generated and stored in the buffer
357     ConsumedPosition - the number of buffer items that are known to have been fully processed by all users
358     */
359   
360};
361
362
363}
364#endif // STREAMSET_H
Note: See TracBrowser for help on using the repository browser.