1 // common.h (Oclgrind)
2 // Copyright (c) 2013-2019, James Price and Simon McIntosh-Smith,
3 // University of Bristol. All rights reserved.
4 //
5 // This program is provided under a three-clause BSD license. For full
6 // license terms please see the LICENSE file distributed with this
7 // source code.
8 
9 #ifndef __common_h_
10 #define __common_h_
11 
12 #define CL_TARGET_OPENCL_VERSION 300
13 #include "CL/cl.h"
14 
15 #include <cassert>
16 #include <cstdio>
17 #include <cstdlib>
18 #include <cstring>
19 #include <iomanip>
20 #include <iostream>
21 #include <list>
22 #include <map>
23 #include <memory>
24 #include <queue>
25 #include <set>
26 #include <sstream>
27 #include <stack>
28 #include <stdexcept>
29 #include <stdint.h>
30 #include <unordered_map>
31 #include <vector>
32 
33 #if defined(_WIN32) && !defined(__MINGW32__)
34 #define snprintf _snprintf
35 #undef ERROR
36 #endif
37 
38 #ifdef __APPLE__
39 // TODO: Remove this when thread_local fixed on OS X
40 #define THREAD_LOCAL __thread
41 #elif defined(_WIN32) && !defined(__MINGW32__)
42 // TODO: Remove this when thread_local fixed on Windows
43 #define THREAD_LOCAL __declspec(thread)
44 #else
45 #define THREAD_LOCAL thread_local
46 #endif
47 
48 #define CLK_NORMALIZED_COORDS_TRUE 0x0001
49 
50 #define CLK_ADDRESS_NONE 0x0000
51 #define CLK_ADDRESS_CLAMP_TO_EDGE 0x0002
52 #define CLK_ADDRESS_CLAMP 0x0004
53 #define CLK_ADDRESS_REPEAT 0x0006
54 #define CLK_ADDRESS_MIRRORED_REPEAT 0x0008
55 #define CLK_ADDRESS_MASK 0x000E
56 
57 #define CLK_FILTER_NEAREST 0x0010
58 #define CLK_FILTER_LINEAR 0x0020
59 
60 namespace llvm
61 {
62 class Constant;
63 class ConstantExpr;
64 class ConstantInt;
65 class Instruction;
66 class Metadata;
67 class StructType;
68 class Type;
69 class Value;
70 } // namespace llvm
71 
72 namespace oclgrind
73 {
74 class Kernel;
75 
76 // Enumeration for address spaces
77 enum AddressSpace
78 {
79   AddrSpacePrivate = 0,
80   AddrSpaceGlobal = 1,
81   AddrSpaceConstant = 2,
82   AddrSpaceLocal = 3,
83 };
84 
85 enum AtomicOp
86 {
87   AtomicAdd,
88   AtomicAnd,
89   AtomicCmpXchg,
90   AtomicDec,
91   AtomicInc,
92   AtomicMax,
93   AtomicMin,
94   AtomicOr,
95   AtomicSub,
96   AtomicXchg,
97   AtomicXor,
98 };
99 
100 // Enumeration for different log message types
101 enum MessageType
102 {
103   DEBUG,
104   INFO,
105   WARNING,
106   ERROR,
107 };
108 
109 // 3-dimensional size
110 struct Size3
111 {
112   size_t x, y, z;
113   Size3();
114   Size3(size_t x, size_t y, size_t z);
115   Size3(size_t linear, Size3 dimensions);
116   size_t& operator[](unsigned i);
117   const size_t& operator[](unsigned i) const;
118   bool operator==(const Size3& rhs) const;
119   bool operator!=(const Size3& rhs) const;
120   friend std::ostream& operator<<(std::ostream& stream, const Size3& sz);
121 };
122 
123 // Structure for a value with a size/type
124 struct TypedValue
125 {
126   unsigned size;
127   unsigned num;
128   unsigned char* data;
129 
130   bool operator==(const TypedValue& rhs) const;
131   bool operator!=(const TypedValue& rhs) const;
132 
133   friend std::ostream& operator<<(std::ostream& stream, const TypedValue& tv);
134 
135   struct TypedValue clone() const;
136 
137   double getFloat(unsigned index = 0) const;
138   size_t getPointer(unsigned index = 0) const;
139   int64_t getSInt(unsigned index = 0) const;
140   uint64_t getUInt(unsigned index = 0) const;
141   void setFloat(double value, unsigned index = 0);
142   void setPointer(size_t value, unsigned index = 0);
143   void setSInt(int64_t value, unsigned index = 0);
144   void setUInt(uint64_t value, unsigned index = 0);
145 };
146 
147 // Private memory map type
148 typedef std::map<const llvm::Value*, TypedValue> TypedValueMap;
149 
150 // Image object
151 struct Image
152 {
153   size_t address;
154   cl_image_format format;
155   cl_image_desc desc;
156 };
157 
158 // Check if an environment variable is set to 1
159 bool checkEnv(const char* var);
160 
161 // Get an environment variable as an integer
162 unsigned getEnvInt(const char* var, int def = 0, bool allowZero = true);
163 
164 // Output an instruction in human-readable format
165 void dumpInstruction(std::ostream& out, const llvm::Instruction* instruction);
166 
167 // Get the human readable name of an address space
168 const char* getAddressSpaceName(unsigned addrSpace);
169 
170 // Retrieve the raw data for a constant
171 void getConstantData(unsigned char* data, const llvm::Constant* constant);
172 
173 // Creates an instruction from a constant expression
174 llvm::Instruction* getConstExprAsInstruction(const llvm::ConstantExpr* expr);
175 
176 // Get the ConstantInt object for a Metadata node
177 const llvm::ConstantInt* getMDAsConstInt(const llvm::Metadata* md);
178 
179 // Get the byte offset of a struct member
180 unsigned getStructMemberOffset(const llvm::StructType* type, unsigned index);
181 
182 // Returns the size of a type
183 unsigned getTypeSize(const llvm::Type* type);
184 
185 /// Returns the alignment requirements of this type
186 unsigned getTypeAlignment(const llvm::Type* type);
187 
188 // Returns the size of a value
189 std::pair<unsigned, unsigned> getValueSize(const llvm::Value* value);
190 
191 // Returns true if the operand is a constant value
192 bool isConstantOperand(const llvm::Value* operand);
193 
194 // Returns true if the value is a 3-element vector
195 bool isVector3(const llvm::Value* value);
196 
197 // Return the current time in nanoseconds since the epoch
198 double now();
199 
200 // Print data in a human readable format (according to its type)
201 void printTypedData(const llvm::Type* type, const unsigned char* data);
202 
203 // Resolve a constant pointer, using a set of known constant values
204 size_t resolveConstantPointer(const llvm::Value* ptr, TypedValueMap& values);
205 
206 // Resolve a GEP from a base address and list of offsets
207 size_t resolveGEP(size_t base, const llvm::Type* ptrType,
208                   std::vector<int64_t>& offsets);
209 
210 // Exception class for raising fatal errors
211 class FatalError : std::runtime_error
212 {
213 public:
214   FatalError(const std::string& msg, const std::string& file, size_t line);
215   ~FatalError() throw();
216   virtual const std::string& getFile() const;
217   virtual size_t getLine() const;
218   virtual const char* what() const throw();
219 
220 protected:
221   std::string m_file;
222   size_t m_line;
223 };
224 
225 // Utility macro for raising an exception with a sprintf-based message
226 #define FATAL_ERROR(format, ...)                                               \
227   {                                                                            \
228     int sz = snprintf(NULL, 0, format, ##__VA_ARGS__);                         \
229     char* str = new char[sz + 1];                                              \
230     sprintf(str, format, ##__VA_ARGS__);                                       \
231     string msg = str;                                                          \
232     delete[] str;                                                              \
233     throw FatalError(msg, __FILE__, __LINE__);                                 \
234   }
235 
236 class MemoryPool
237 {
238 public:
239   MemoryPool(size_t blockSize = 1024);
240   ~MemoryPool();
241   uint8_t* alloc(size_t size);
242   TypedValue clone(const TypedValue& source);
243 
244 private:
245   size_t m_blockSize;
246   size_t m_offset;
247   std::list<uint8_t*> m_blocks;
248 };
249 
250 // Pool allocator class for STL containers
251 template <class T, size_t BLOCKSIZE> class PoolAllocator
252 {
253   template <typename U, size_t BS> friend class PoolAllocator;
254 
255 public:
256   typedef T value_type;
257   typedef T* pointer;
258   typedef T& reference;
259   typedef const T* const_pointer;
260   typedef const T& const_reference;
261   typedef size_t size_type;
262   typedef ptrdiff_t difference_type;
263 
264   template <typename U> struct rebind
265   {
266     typedef PoolAllocator<U, BLOCKSIZE> other;
267   };
268 
PoolAllocator()269   PoolAllocator()
270   {
271     pool.reset(new MemoryPool(BLOCKSIZE));
272   }
273 
PoolAllocator(const PoolAllocator & p)274   PoolAllocator(const PoolAllocator& p)
275   {
276     this->pool = p.pool;
277   }
278 
PoolAllocator(const PoolAllocator<U,BLOCKSIZE> & p)279   template <typename U> PoolAllocator(const PoolAllocator<U, BLOCKSIZE>& p)
280   {
281     this->pool = p.pool;
282   }
283 
284   pointer allocate(size_type n, const_pointer hint = 0)
285   {
286     return (pointer)(pool->alloc(n * sizeof(value_type)));
287   }
288 
deallocate(pointer p,size_type n)289   void deallocate(pointer p, size_type n) {}
290 
construct(U * p,Args &&...args)291   template <class U, class... Args> void construct(U* p, Args&&... args)
292   {
293     new ((void*)p) U(std::forward<Args>(args)...);
294   }
295 
destroy(U * p)296   template <class U> void destroy(U* p)
297   {
298     p->~U();
299   }
300 
301   bool operator==(const PoolAllocator& p) const
302   {
303     return this->pool == p.pool;
304   }
305 
306   bool operator!=(const PoolAllocator& p) const
307   {
308     return this->pool != p.pool;
309   }
310 
311 private:
312   std::shared_ptr<MemoryPool> pool;
313 };
314 
315 } // namespace oclgrind
316 
317 #endif // __common_h_
318