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 | namespace IDISA { class IDISA_Builder; } |
---|
11 | namespace llvm { class Value; } |
---|
12 | namespace kernel { class Kernel; } |
---|
13 | namespace kernel { class KernelBuilder; } |
---|
14 | |
---|
15 | namespace parabix { |
---|
16 | |
---|
17 | class StreamSetBuffer { |
---|
18 | friend class kernel::Kernel; |
---|
19 | friend class kernel::KernelBuilder; |
---|
20 | public: |
---|
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 | virtual void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const; |
---|
115 | |
---|
116 | bool supportsCopyBack() const { |
---|
117 | return mOverflowBlocks != 0; |
---|
118 | } |
---|
119 | |
---|
120 | size_t overflowSize() const { |
---|
121 | return mOverflowBlocks; |
---|
122 | } |
---|
123 | |
---|
124 | virtual ~StreamSetBuffer() = 0; |
---|
125 | |
---|
126 | kernel::Kernel * getProducer() const { |
---|
127 | return mProducer; |
---|
128 | } |
---|
129 | |
---|
130 | const std::vector<kernel::Kernel *> & getConsumers() const { |
---|
131 | return mConsumers; |
---|
132 | } |
---|
133 | |
---|
134 | |
---|
135 | |
---|
136 | protected: |
---|
137 | |
---|
138 | StreamSetBuffer(BufferKind k, llvm::Type * baseType, llvm::Type * resolvedType, unsigned BufferBlocks, unsigned OverflowBlocks, unsigned AddressSpace); |
---|
139 | |
---|
140 | virtual llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockNo) const; |
---|
141 | |
---|
142 | bool isCapacityGuaranteed(const llvm::Value * const index, const size_t capacity) const; |
---|
143 | |
---|
144 | llvm::Value * modBufferSize(IDISA::IDISA_Builder * const b, llvm::Value * const offset) const; |
---|
145 | |
---|
146 | virtual llvm::Value * getBaseAddress(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 | |
---|
158 | protected: |
---|
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 | |
---|
171 | class SourceBuffer final : public StreamSetBuffer { |
---|
172 | public: |
---|
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 | void setBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * addr) const override; |
---|
180 | |
---|
181 | void setBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * size) const override; |
---|
182 | |
---|
183 | void setCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * c) const override; |
---|
184 | |
---|
185 | llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
186 | |
---|
187 | llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
188 | |
---|
189 | llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override; |
---|
190 | |
---|
191 | llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override; |
---|
192 | |
---|
193 | llvm::Type * getStreamSetBlockType() const override; |
---|
194 | |
---|
195 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) override; |
---|
196 | |
---|
197 | void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override; |
---|
198 | |
---|
199 | protected: |
---|
200 | |
---|
201 | enum class Field {BaseAddress, BufferedSize, Capacity}; |
---|
202 | |
---|
203 | llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
204 | |
---|
205 | }; |
---|
206 | |
---|
207 | class ExternalBuffer final : public StreamSetBuffer { |
---|
208 | public: |
---|
209 | static inline bool classof(const StreamSetBuffer * b) { |
---|
210 | return b->getBufferKind() == BufferKind::ExternalBuffer; |
---|
211 | } |
---|
212 | |
---|
213 | ExternalBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, llvm::Value * addr, unsigned AddressSpace = 0); |
---|
214 | |
---|
215 | llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override; |
---|
216 | |
---|
217 | llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override; |
---|
218 | |
---|
219 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override; |
---|
220 | |
---|
221 | void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override; |
---|
222 | |
---|
223 | llvm::Value * getCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
224 | }; |
---|
225 | |
---|
226 | class CircularBuffer : public StreamSetBuffer { |
---|
227 | public: |
---|
228 | static inline bool classof(const StreamSetBuffer * b) { |
---|
229 | return b->getBufferKind() == BufferKind::CircularBuffer; |
---|
230 | } |
---|
231 | |
---|
232 | CircularBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0); |
---|
233 | |
---|
234 | llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const final; |
---|
235 | |
---|
236 | protected: |
---|
237 | |
---|
238 | CircularBuffer(const BufferKind kind, const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace); |
---|
239 | |
---|
240 | llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const final; |
---|
241 | }; |
---|
242 | |
---|
243 | |
---|
244 | // |
---|
245 | // A CircularCopybackBuffer operates as a circular buffer buffer with an overflow area |
---|
246 | // for temporary use by the kernel that writes to it. If the kernel uses the overflow |
---|
247 | // area, it must perform the doCopyBack action before releasing the buffer for use by |
---|
248 | // subsequent kernels. |
---|
249 | // Kernels that read from a CircularCopybackBuffer must not access the overflow area. |
---|
250 | // |
---|
251 | class CircularCopybackBuffer final : public CircularBuffer { |
---|
252 | public: |
---|
253 | static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::CircularCopybackBuffer;} |
---|
254 | |
---|
255 | CircularCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned AddressSpace = 0); |
---|
256 | |
---|
257 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override; |
---|
258 | |
---|
259 | }; |
---|
260 | |
---|
261 | class SwizzledCopybackBuffer final : public StreamSetBuffer { |
---|
262 | public: |
---|
263 | static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::SwizzledCopybackBuffer;} |
---|
264 | |
---|
265 | SwizzledCopybackBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, size_t overflowBlocks, unsigned fieldwidth = 64, unsigned AddressSpace = 0); |
---|
266 | |
---|
267 | void createBlockAlignedCopy(IDISA::IDISA_Builder * const b, llvm::Value * targetBlockPtr, llvm::Value * sourceBlockPtr, llvm::Value * itemsToCopy, const unsigned alignment = 1) const override; |
---|
268 | |
---|
269 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override; |
---|
270 | |
---|
271 | protected: |
---|
272 | llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override; |
---|
273 | private: |
---|
274 | unsigned mFieldWidth; |
---|
275 | |
---|
276 | }; |
---|
277 | |
---|
278 | // ExpandableBuffers do not allow access to the base stream set but will automatically increase the number of streams |
---|
279 | // within their set whenever the index exceeds its capacity |
---|
280 | // |
---|
281 | class ExpandableBuffer final : public StreamSetBuffer { |
---|
282 | public: |
---|
283 | static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::ExpandableBuffer;} |
---|
284 | |
---|
285 | ExpandableBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t bufferBlocks, unsigned AddressSpace = 0); |
---|
286 | |
---|
287 | 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; |
---|
288 | |
---|
289 | 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; |
---|
290 | |
---|
291 | llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override; |
---|
292 | |
---|
293 | llvm::Value * getStreamSetCount(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
294 | |
---|
295 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override; |
---|
296 | |
---|
297 | void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & kb) const override; |
---|
298 | |
---|
299 | protected: |
---|
300 | |
---|
301 | llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
302 | |
---|
303 | llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * blockIndex, llvm::Value *) const override; |
---|
304 | |
---|
305 | private: |
---|
306 | |
---|
307 | 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; |
---|
308 | |
---|
309 | private: |
---|
310 | |
---|
311 | const uint64_t mInitialCapacity; |
---|
312 | |
---|
313 | }; |
---|
314 | |
---|
315 | // Dynamically allocated circular buffers: TODO: add copyback, swizzle support, dynamic allocation, producer, consumer, length |
---|
316 | class DynamicBuffer final : public StreamSetBuffer { |
---|
317 | public: |
---|
318 | static inline bool classof(const StreamSetBuffer * b) {return b->getBufferKind() == BufferKind::DynamicBuffer;} |
---|
319 | |
---|
320 | DynamicBuffer(const std::unique_ptr<kernel::KernelBuilder> & b, llvm::Type * type, size_t initialCapacity, size_t overflowBlocks = 0, unsigned swizzleFactor = 1, unsigned addrSpace = 0); |
---|
321 | |
---|
322 | llvm::Value * getLinearlyAccessibleItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * avail, bool reverse = false) const override; |
---|
323 | |
---|
324 | llvm::Value * getLinearlyWritableItems(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * fromPosition, llvm::Value * consumed, bool reverse = false) const override; |
---|
325 | |
---|
326 | void allocateBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) override; |
---|
327 | |
---|
328 | void releaseBuffer(const std::unique_ptr<kernel::KernelBuilder> & b) const override; |
---|
329 | |
---|
330 | llvm::Value * getRawItemPointer(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * absolutePosition) const override; |
---|
331 | |
---|
332 | llvm::Value * getBufferedSize(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
333 | |
---|
334 | void doubleCapacity(IDISA::IDISA_Builder * const b, llvm::Value * handle) const final; |
---|
335 | |
---|
336 | protected: |
---|
337 | llvm::Value * getBaseAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle) const override; |
---|
338 | |
---|
339 | llvm::Value * getBlockAddress(IDISA::IDISA_Builder * const b, llvm::Value * handle, llvm::Value * blockIndex) const override; |
---|
340 | |
---|
341 | |
---|
342 | private: |
---|
343 | /* Static data */ |
---|
344 | llvm::Type * mBufferStructType; /* The type of the buffer struct. */ |
---|
345 | unsigned mSwizzleFactor; /* Number of streams swizzled together per block. Must be a small power of 2. Default: 1. */ |
---|
346 | |
---|
347 | /* Dynamic data fields stored in the buffer struct */ |
---|
348 | |
---|
349 | enum class Field {BaseAddress, PriorBaseAddress, AllocatedCapacity, WorkingBlocks, Length, ProducedPosition, ConsumedPosition, FieldCount}; |
---|
350 | |
---|
351 | /* BaseAddress - the physical base address of the memory area for stream set data. |
---|
352 | PriorBaseAddress - the physical base address of the previous memory area for stream set data |
---|
353 | (the immediately prior memory area is preserved in case any users in other threads |
---|
354 | are accessing it). |
---|
355 | WorkingBlocks - the physical size of the buffer for use in reading and writing data. |
---|
356 | AllocatedCapacity - physical size available for expansion in place |
---|
357 | Length - actual final length of stream set or -1 for unknown |
---|
358 | ProducedPosition - the total number of items ever generated and stored in the buffer |
---|
359 | ConsumedPosition - the number of buffer items that are known to have been fully processed by all users |
---|
360 | */ |
---|
361 | |
---|
362 | }; |
---|
363 | |
---|
364 | |
---|
365 | } |
---|
366 | #endif // STREAMSET_H |
---|