OpenVDB  11.0.0
Utils.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file codegen/Utils.h
5 ///
6 /// @authors Nick Avramoussis
7 ///
8 /// @brief Utility code generation methods for performing various llvm
9 /// operations
10 ///
11 
12 #ifndef OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
13 #define OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
14 
15 #include "Types.h"
16 
17 #include "../ast/Tokens.h"
18 #include "../Exceptions.h"
19 
20 #include <openvdb/version.h>
21 
22 #include <llvm/IR/IRBuilder.h>
23 #include <llvm/IR/LLVMContext.h>
24 
25 // Note: As of LLVM 5.0, the llvm::Type::dump() method isn't being
26 // picked up correctly by the linker. dump() is internally implemented
27 // using Type::print(llvm::errs()) which is being used in place. See:
28 //
29 // https://stackoverflow.com/questions/43723127/llvm-5-0-makefile-undefined-reference-fail
30 //
31 #include <llvm/Support/raw_ostream.h> // llvm::errs()
32 
33 namespace openvdb {
35 namespace OPENVDB_VERSION_NAME {
36 
37 namespace ax {
38 namespace codegen {
39 
40 /// @note Function definitions for some types returned from automatic token to
41 /// llvm IR operations. See llvmArithmeticConversion and llvmBianryConversion
42 
43 using CastFunction = std::function<llvm::Value*
44  (llvm::IRBuilder<>&, llvm::Value*, llvm::Type*)>;
45 
46 using BinaryFunction = std::function<llvm::Value*
47  (llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>;
48 
49 
50 /// @todo Should really provide a standard interface for all these and avoid
51 /// using the IR builder directly.
52 
53 /// @brief Alias around IR load inst.
54 inline auto ir_load(llvm::IRBuilder<>& B, llvm::Value* ptr, const char* Name = "")
55 {
56  assert(ptr);
57  assert(ptr->getType()->isPointerTy());
58 #if LLVM_VERSION_MAJOR <= 7
59  return B.CreateLoad(ptr, Name);
60 #else
61  return B.CreateLoad(ptr->getType()->getPointerElementType(), ptr, Name);
62 #endif
63 }
64 
65 /// @brief Alias around IR gep inst.
66 inline auto ir_gep(llvm::IRBuilder<>& B,
67  llvm::Value* ptr, llvm::ArrayRef<llvm::Value*> IdxList, const char* Name = "")
68 {
69  assert(ptr);
70  assert(ptr->getType()->getScalarType());
71  assert(ptr->getType()->getScalarType()->isPointerTy());
72 #if LLVM_VERSION_MAJOR <= 7
73  return B.CreateGEP(ptr, IdxList, Name);
74 #else
75  return B.CreateGEP(ptr->getType()->getScalarType()->getPointerElementType(),
76  ptr, IdxList, Name);
77 #endif
78 }
79 
80 /// @brief Alias around IR gep2_64 inst.
81 inline auto ir_constgep2_64(llvm::IRBuilder<>& B,
82  llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1, const char* Name = "")
83 {
84  assert(ptr);
85  assert(ptr->getType()->getScalarType());
86  assert(ptr->getType()->getScalarType()->isPointerTy());
87 #if LLVM_VERSION_MAJOR <= 7
88  return B.CreateConstGEP2_64(ptr, Idx0, Idx1, Name);
89 #else
90  return B.CreateConstGEP2_64(
91  ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
92  Idx1, Name);
93 #endif
94 }
95 
96 /// @brief Alias around IR in bounds gep2_64 inst.
97 inline auto ir_constinboundsgep2_64(llvm::IRBuilder<>& B,
98  llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1, const char* Name = "")
99 {
100  assert(ptr);
101  assert(ptr->getType()->getScalarType());
102  assert(ptr->getType()->getScalarType()->isPointerTy());
103 #if LLVM_VERSION_MAJOR <= 7
104  return B.CreateConstInBoundsGEP2_64(ptr, Idx0, Idx1, Name);
105 #else
106  return B.CreateConstInBoundsGEP2_64(
107  ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
108  Idx1, Name);
109 #endif
110 }
111 
112 /// @brief Populate a vector of llvm Types from a vector of llvm values
113 ///
114 /// @param values A vector of llvm values to retrieve types from
115 /// @param types A vector of llvm types to populate
116 ///
117 inline void
118 valuesToTypes(const std::vector<llvm::Value*>& values,
119  std::vector<llvm::Type*>& types)
120 {
121  types.reserve(values.size());
122  for (const auto& v : values) {
123  types.emplace_back(v->getType());
124  }
125 }
126 
127 /// @brief Prints an llvm type to a std string
128 ///
129 /// @param type The llvm type to convert
130 /// @param str The string to store the type info to
131 ///
132 inline void
133 llvmTypeToString(const llvm::Type* const type, std::string& str)
134 {
135  llvm::raw_string_ostream os(str);
136  type->print(os);
137  os.flush();
138 }
139 
140 /// @brief Return the base llvm value which is being pointed to through
141 /// any number of layered pointers.
142 /// @note This function does not check for cyclical pointer dependencies
143 ///
144 /// @param type A llvm pointer type to traverse
145 ///
146 inline llvm::Type*
147 getBaseContainedType(llvm::Type* const type)
148 {
149  llvm::Type* elementType = type;
150  while (elementType->isPointerTy()) {
151  elementType = elementType->getContainedType(0);
152  }
153  return elementType;
154 }
155 
156 /// @brief Return an llvm value representing a pointer to the provided ptr builtin
157 /// ValueT.
158 /// @note This is probably not a suitable solution for anything other than POD
159 /// types and should be used with caution.
160 ///
161 /// @param ptr A pointer to a type of ValueT whose address will be computed and
162 /// returned
163 /// @param builder The current llvm IRBuilder
164 ///
165 template <typename ValueT>
166 inline llvm::Value*
167 llvmPointerFromAddress(const ValueT* const& ptr,
168  llvm::IRBuilder<>& builder)
169 {
170  llvm::Value* address =
171  llvm::ConstantInt::get(llvm::Type::getIntNTy(builder.getContext(), sizeof(uintptr_t)*8),
172  reinterpret_cast<uintptr_t>(ptr));
173  return builder.CreateIntToPtr(address, LLVMType<ValueT*>::get(builder.getContext()));
174 }
175 
176 /// @brief Insert a stack allocation at the beginning of the current function
177 /// of the provided type and size. The IRBuilder's insertion point must
178 /// be set to a BasicBlock with a valid Function parent.
179 /// @note If a size is provided, the size must not depend on any other
180 /// instructions. If it does, invalid LLVM IR will bb generated.
181 ///
182 /// @param B The IRBuilder
183 /// @param type The type to allocate
184 /// @param size Optional count of allocations. If nullptr, runs a single allocation
185 inline llvm::Value*
186 insertStaticAlloca(llvm::IRBuilder<>& B,
187  llvm::Type* type,
188  llvm::Value* size = nullptr)
189 {
190  llvm::Type* strtype = LLVMType<codegen::String>::get(B.getContext());
191  // Create the allocation at the start of the function block
192  llvm::Function* parent = B.GetInsertBlock()->getParent();
193  assert(parent && !parent->empty());
194  auto IP = B.saveIP();
195  llvm::BasicBlock& block = parent->front();
196  if (block.empty()) B.SetInsertPoint(&block);
197  else B.SetInsertPoint(&(block.front()));
198  llvm::Value* result = B.CreateAlloca(type, size);
199 
200  /// @note Strings need to be initialised correctly when they are
201  /// created. We alloc them at the start of the function but
202  /// strings in branches may not ever be set to anything. If
203  /// we don't init these correctly, the clearup frees will
204  /// try and free uninitialised memory
205  if (type == strtype) {
206  llvm::Value* cptr = B.CreateStructGEP(strtype, result, 0); // char**
207  llvm::Value* sso = B.CreateStructGEP(strtype, result, 1); // char[]*
208  llvm::Value* sso_load = ir_constgep2_64(B, sso, 0 ,0); // char*
209  llvm::Value* len = B.CreateStructGEP(strtype, result, 2);
210  B.CreateStore(sso_load, cptr); // this->ptr = this->SSO;
211  B.CreateStore(B.getInt64(0), len);
212  }
213  B.restoreIP(IP);
214  return result;
215 }
216 
217 inline llvm::Argument*
218 extractArgument(llvm::Function* F, const size_t idx)
219 {
220  if (!F) return nullptr;
221  if (idx >= F->arg_size()) return nullptr;
222  return llvm::cast<llvm::Argument>(F->arg_begin() + idx);
223 }
224 
225 inline llvm::Argument*
226 extractArgument(llvm::Function* F, const std::string& name)
227 {
228  if (!F) return nullptr;
229  for (auto iter = F->arg_begin(); iter != F->arg_end(); ++iter) {
230  llvm::Argument* arg = llvm::cast<llvm::Argument>(iter);
231  if (arg->getName() == name) return arg;
232  }
233  return nullptr;
234 }
235 
236 /// @brief Returns the highest order type from two LLVM Scalar types
237 ///
238 /// @param typeA The first scalar llvm type
239 /// @param typeB The second scalar llvm type
240 ///
241 inline llvm::Type*
242 typePrecedence(llvm::Type* const typeA,
243  llvm::Type* const typeB)
244 {
245  assert(typeA && (typeA->isIntegerTy() || typeA->isFloatingPointTy()) &&
246  "First Type in typePrecedence is not a scalar type");
247  assert(typeB && (typeB->isIntegerTy() || typeB->isFloatingPointTy()) &&
248  "Second Type in typePrecedence is not a scalar type");
249 
250  // handle implicit arithmetic conversion
251  // (http://osr507doc.sco.com/en/tools/clang_conv_implicit.html)
252 
253  if (typeA->isDoubleTy()) return typeA;
254  if (typeB->isDoubleTy()) return typeB;
255 
256  if (typeA->isFloatTy()) return typeA;
257  if (typeB->isFloatTy()) return typeB;
258 
259  if (typeA->isIntegerTy(64)) return typeA;
260  if (typeB->isIntegerTy(64)) return typeB;
261 
262  if (typeA->isIntegerTy(32)) return typeA;
263  if (typeB->isIntegerTy(32)) return typeB;
264 
265  if (typeA->isIntegerTy(16)) return typeA;
266  if (typeB->isIntegerTy(16)) return typeB;
267 
268  if (typeA->isIntegerTy(8)) return typeA;
269  if (typeB->isIntegerTy(8)) return typeB;
270 
271  if (typeA->isIntegerTy(1)) return typeA;
272  if (typeB->isIntegerTy(1)) return typeB;
273 
274  assert(false && "invalid LLVM type precedence");
275  return nullptr;
276 }
277 
278 /// @brief Returns a CastFunction which represents the corresponding instruction
279 /// to convert a source llvm Type to a target llvm Type. If the conversion
280 /// is unsupported, throws an error.
281 /// @warning This assumes any integer types are signed.
282 /// @param sourceType The source type to cast
283 /// @param targetType The target type to cast to
284 /// @param twine An optional string description of the cast function. This can
285 /// be used for for more verbose llvm information on IR compilation
286 /// failure
287 inline CastFunction
288 llvmArithmeticConversion(const llvm::Type* const sourceType,
289  const llvm::Type* const targetType,
290  const std::string& twine = "")
291 {
292 
293 #define BIND_ARITHMETIC_CAST_OP(Function, Twine) \
294  std::bind(&Function, \
295  std::placeholders::_1, \
296  std::placeholders::_2, \
297  std::placeholders::_3, \
298  Twine)
299 
300  if (targetType->isDoubleTy()) {
301  if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
302  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
303  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
304  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
305  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
306  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
307  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
308  }
309  else if (targetType->isFloatTy()) {
310  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
311  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
312  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
313  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
314  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
315  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
316  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
317  }
318  else if (targetType->isHalfTy()) {
319  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
320  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
321  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
322  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
323  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
324  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
325  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
326  }
327  else if (targetType->isIntegerTy(64)) {
328  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
329  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
330  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
331  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
332  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
333  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
334  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
335  }
336  else if (targetType->isIntegerTy(32)) {
337  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
338  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
339  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
340  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
341  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
342  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
343  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
344  }
345  else if (targetType->isIntegerTy(16)) {
346  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
347  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
348  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
349  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
350  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
351  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
352  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
353  }
354  else if (targetType->isIntegerTy(8)) {
355  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
356  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
357  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
358  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
359  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
360  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
361  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
362  }
363  else if (targetType->isIntegerTy(1)) {
364  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
365  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
366  else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
367  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
368  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
369  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
370  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
371  }
372 
373 #undef BIND_ARITHMETIC_CAST_OP
374  assert(false && "invalid LLVM type conversion");
375  return CastFunction();
376 }
377 
378 /// @brief Returns a BinaryFunction representing the corresponding instruction to
379 /// perform on two scalar values, relative to a provided operator token. Note that
380 /// not all operations are supported on floating point types! If the token is not
381 /// supported, or the llvm type is not a scalar type, throws an error.
382 /// @note Various default arguments are bound to provide a simple function call
383 /// signature. For floating point operations, this includes a null pointer to
384 /// the optional metadata node. For integer operations, this includes disabling
385 /// all overflow/rounding optimisations
386 ///
387 /// @param type The type defining the precision of the binary operation
388 /// @param token The token used to create the relative binary operation
389 /// @param twine An optional string description of the binary function. This can
390 /// be used for for more verbose llvm information on IR compilation
391 /// failure
392 inline BinaryFunction
393 llvmBinaryConversion(const llvm::Type* const type,
394  const ast::tokens::OperatorToken& token,
395  const std::string& twine = "")
396 {
397 
398 #define BIND_BINARY_OP(Function) \
399  [twine](llvm::IRBuilder<>& B, llvm::Value* L, llvm::Value* R) \
400  -> llvm::Value* { return B.Function(L, R, twine); }
401 
402  // NOTE: Binary % and / ops always take sign into account (CreateSDiv vs CreateUDiv, CreateSRem vs CreateURem).
403  // See http://stackoverflow.com/questions/5346160/llvm-irbuildercreateudiv-createsdiv-createexactudiv
404  // a%b in AX is implemented as a floored modulo op and is handled explicitly in binaryExpression
405 
406  if (type->isFloatingPointTy()) {
407  assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL ||
409  && "unable to perform logical or bitwise operation on floating point values");
410 
411  if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateFAdd);
412  else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateFSub);
413  else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateFMul);
414  else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateFDiv);
415  else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateFRem); // Note this is NOT a%b in AX.
416  else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateFCmpOEQ);
417  else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateFCmpONE);
418  else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateFCmpOGT);
419  else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateFCmpOLT);
420  else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOGE);
421  else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOLE);
422  assert(false && "unrecognised binary operator");
423  }
424  else if (type->isIntegerTy()) {
425  if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateAdd); // No Unsigned/Signed Wrap
426  else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateSub); // No Unsigned/Signed Wrap
427  else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateMul); // No Unsigned/Signed Wrap
428  else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateSDiv); // IsExact = false - when true, poison value if the reuslt is rounded
429  else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateSRem); // Note this is NOT a%b in AX.
430  else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateICmpEQ);
431  else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateICmpNE);
432  else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateICmpSGT);
433  else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateICmpSLT);
434  else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateICmpSGE);
435  else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateICmpSLE);
436  else if (token == ast::tokens::AND) return BIND_BINARY_OP(CreateAnd);
437  else if (token == ast::tokens::OR) return BIND_BINARY_OP(CreateOr);
438  else if (token == ast::tokens::SHIFTLEFT) return BIND_BINARY_OP(CreateShl); // No Unsigned/Signed Wrap
439  else if (token == ast::tokens::SHIFTRIGHT) return BIND_BINARY_OP(CreateAShr); // IsExact = false - poison value if any of the bits shifted out are non-zero.
440  else if (token == ast::tokens::BITAND) return BIND_BINARY_OP(CreateAnd);
441  else if (token == ast::tokens::BITOR) return BIND_BINARY_OP(CreateOr);
442  else if (token == ast::tokens::BITXOR) return BIND_BINARY_OP(CreateXor);
443  assert(false && "unrecognised binary operator");
444  }
445 
446 #undef BIND_BINARY_OP
447  assert(false && "invalid LLVM type for binary operation");
448  return BinaryFunction();
449 }
450 
451 /// @brief Returns true if the llvm Type 'from' can be safely cast to the llvm
452 /// Type 'to'.
453 inline bool isValidCast(llvm::Type* from, llvm::Type* to)
454 {
455  assert(from && "llvm Type 'from' is null in isValidCast");
456  assert(to && "llvm Type 'to' is null in isValidCast");
457 
458  if ((from->isIntegerTy() || from->isFloatingPointTy()) &&
459  (to->isIntegerTy() || to->isFloatingPointTy())) {
460  return true;
461  }
462  if (from->isArrayTy() && to->isArrayTy()) {
463  llvm::ArrayType* af = llvm::cast<llvm::ArrayType>(from);
464  llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(to);
465  if (af->getArrayNumElements() == at->getArrayNumElements()) {
466  return isValidCast(af->getArrayElementType(),
467  at->getArrayElementType());
468  }
469  }
470  return false;
471 }
472 
473 /// @brief Casts a scalar llvm Value to a target scalar llvm Type. Returns
474 /// the cast scalar value of type targetType.
475 /// @warning This assumes any integer types are signed.
476 /// @param value A llvm scalar value to convert
477 /// @param targetType The target llvm scalar type to convert to
478 /// @param builder The current llvm IRBuilder
479 inline llvm::Value*
480 arithmeticConversion(llvm::Value* value,
481  llvm::Type* targetType,
482  llvm::IRBuilder<>& builder)
483 {
484  assert(value && (value->getType()->isIntegerTy() || value->getType()->isFloatingPointTy()) &&
485  "First Value in arithmeticConversion is not a scalar type");
486  assert(targetType && (targetType->isIntegerTy() || targetType->isFloatingPointTy()) &&
487  "Target Type in arithmeticConversion is not a scalar type");
488 
489  const llvm::Type* const valueType = value->getType();
490  if (valueType == targetType) return value;
491 
492  CastFunction llvmCastFunction = llvmArithmeticConversion(valueType, targetType);
493  return llvmCastFunction(builder, value, targetType);
494 }
495 
496 /// @brief Casts an array to another array of equal size but of a different element
497 /// type. Both source and target array element types must be scalar types.
498 /// The source array llvm Value should be a pointer to the array to cast.
499 ///
500 /// @param ptrToArray A llvm value which is a pointer to a llvm array
501 /// @param targetElementType The target llvm scalar type to convert each element
502 /// of the input array
503 /// @param builder The current llvm IRBuilder
504 ///
505 inline llvm::Value*
506 arrayCast(llvm::Value* ptrToArray,
507  llvm::Type* targetElementType,
508  llvm::IRBuilder<>& builder)
509 {
510  assert(targetElementType && (targetElementType->isIntegerTy() ||
511  targetElementType->isFloatingPointTy()) &&
512  "Target element type is not a scalar type");
513  assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
514  "Input to arrayCast is not a pointer type.");
515 
516  llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
517  assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
518 
519  // getArrayElementType() calls getContainedType(0)
520  llvm::Type* sourceElementType = arrayType->getArrayElementType();
521  assert(sourceElementType && (sourceElementType->isIntegerTy() ||
522  sourceElementType->isFloatingPointTy()) &&
523  "Source element type is not a scalar type");
524 
525  if (sourceElementType == targetElementType) return ptrToArray;
526 
527  CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
528 
529  const size_t elementSize = arrayType->getArrayNumElements();
530  llvm::Value* targetArray =
531  insertStaticAlloca(builder,
532  llvm::ArrayType::get(targetElementType, elementSize));
533 
534  for (size_t i = 0; i < elementSize; ++i) {
535  llvm::Value* target = ir_constgep2_64(builder, targetArray, 0, i);
536  llvm::Value* source = ir_constgep2_64(builder, ptrToArray, 0, i);
537  source = ir_load(builder, source);
538  source = llvmCastFunction(builder, source, targetElementType);
539  builder.CreateStore(source, target);
540  }
541 
542  return targetArray;
543 }
544 
545 /// @brief Converts a vector of loaded llvm scalar values of the same type to a
546 /// target scalar type. Each value is converted individually and the loaded
547 /// result stored in the same location within values.
548 /// @warning This assumes any integer types are signed.
549 /// @param values A vector of llvm scalar values to convert
550 /// @param targetElementType The target llvm scalar type to convert each value
551 /// of the input vector
552 /// @param builder The current llvm IRBuilder
553 inline void
554 arithmeticConversion(std::vector<llvm::Value*>& values,
555  llvm::Type* targetElementType,
556  llvm::IRBuilder<>& builder)
557 {
558  assert(targetElementType && (targetElementType->isIntegerTy() ||
559  targetElementType->isFloatingPointTy()) &&
560  "Target element type is not a scalar type");
561 
562  llvm::Type* sourceElementType = values.front()->getType();
563  assert(sourceElementType && (sourceElementType->isIntegerTy() ||
564  sourceElementType->isFloatingPointTy()) &&
565  "Source element type is not a scalar type");
566 
567  if (sourceElementType == targetElementType) return;
568 
569  CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
570 
571  for (llvm::Value*& value : values) {
572  value = llvmCastFunction(builder, value, targetElementType);
573  }
574 }
575 
576 /// @brief Converts a vector of loaded llvm scalar values to the highest precision
577 /// type stored amongst them. Any values which are not scalar types are ignored
578 /// @warning This assumes any integer types are signed.
579 /// @param values A vector of llvm scalar values to convert
580 /// @param builder The current llvm IRBuilder
581 inline void
582 arithmeticConversion(std::vector<llvm::Value*>& values,
583  llvm::IRBuilder<>& builder)
584 {
585  llvm::Type* typeCast = LLVMType<bool>::get(builder.getContext());
586  for (llvm::Value*& value : values) {
587  llvm::Type* type = value->getType();
588  if (type->isIntegerTy() || type->isFloatingPointTy()) {
589  typeCast = typePrecedence(typeCast, type);
590  }
591  }
592 
593  arithmeticConversion(values, typeCast, builder);
594 }
595 
596 /// @brief Chooses the highest order llvm Type as defined by typePrecedence
597 /// from either of the two incoming values and casts the other value to
598 /// the choosen type if it is not already. The types of valueA and valueB
599 /// are guaranteed to match. Both values must be scalar LLVM types
600 /// @warning This assumes any integer types are signed.
601 /// @param valueA The first llvm value
602 /// @param valueB The second llvm value
603 /// @param builder The current llvm IRBuilder
604 inline void
605 arithmeticConversion(llvm::Value*& valueA,
606  llvm::Value*& valueB,
607  llvm::IRBuilder<>& builder)
608 {
609  llvm::Type* type = typePrecedence(valueA->getType(), valueB->getType());
610  valueA = arithmeticConversion(valueA, type, builder);
611  valueB = arithmeticConversion(valueB, type, builder);
612 }
613 
614 /// @brief Performs a C style boolean comparison from a given scalar LLVM value
615 ///
616 /// @param value The scalar llvm value to convert to a boolean
617 /// @param builder The current llvm IRBuilder
618 ///
619 inline llvm::Value*
620 boolComparison(llvm::Value* value,
621  llvm::IRBuilder<>& builder)
622 {
623  llvm::Type* type = value->getType();
624 
625  if (type->isFloatingPointTy()) return builder.CreateFCmpONE(value, llvm::ConstantFP::get(type, 0.0));
626  else if (type->isIntegerTy(1)) return builder.CreateICmpNE(value, llvm::ConstantInt::get(type, 0));
627  else if (type->isIntegerTy()) return builder.CreateICmpNE(value, llvm::ConstantInt::getSigned(type, 0));
628  assert(false && "Invalid type for bool conversion");
629  return nullptr;
630 }
631 
632 /// @ brief Performs a binary operation on two loaded llvm scalar values of the same type.
633 /// The type of operation performed is defined by the token (see the list of supported
634 /// tokens in ast/Tokens.h. Returns a loaded llvm scalar result
635 ///
636 /// @param lhs The left hand side value of the binary operation
637 /// @param rhs The right hand side value of the binary operation
638 /// @param token The token representing the binary operation to perform
639 /// @param builder The current llvm IRBuilder
640 inline llvm::Value*
641 binaryOperator(llvm::Value* lhs, llvm::Value* rhs,
642  const ast::tokens::OperatorToken& token,
643  llvm::IRBuilder<>& builder)
644 {
645  llvm::Type* lhsType = lhs->getType();
646  assert(lhsType == rhs->getType() ||
647  (token == ast::tokens::SHIFTLEFT ||
648  token == ast::tokens::SHIFTRIGHT));
649 
651 
652  if (opType == ast::tokens::LOGICAL) {
653  lhs = boolComparison(lhs, builder);
654  rhs = boolComparison(rhs, builder);
655  lhsType = lhs->getType(); // now bool type
656  }
657 
658  const BinaryFunction llvmBinaryFunction = llvmBinaryConversion(lhsType, token);
659  return llvmBinaryFunction(builder, lhs, rhs);
660 }
661 
662 /// @brief Unpack a particular element of an array and return a pointer to that element
663 /// The provided llvm Value is expected to be a pointer to an array
664 ///
665 /// @param ptrToArray A llvm value which is a pointer to a llvm array
666 /// @param index The index at which to access the array
667 /// @param builder The current llvm IRBuilder
668 ///
669 inline llvm::Value*
670 arrayIndexUnpack(llvm::Value* ptrToArray,
671  const int16_t index,
672  llvm::IRBuilder<>& builder)
673 {
674  return ir_constgep2_64(builder, ptrToArray, 0, index);
675 }
676 
677 /// @brief Unpack an array type into llvm Values which represent all its elements
678 /// The provided llvm Value is expected to be a pointer to an array
679 /// If loadElements is true, values will store loaded llvm values instead
680 /// of pointers to the array elements
681 ///
682 /// @param ptrToArray A llvm value which is a pointer to a llvm array
683 /// @param values A vector of llvm values where to store the array elements
684 /// @param builder The current llvm IRBuilder
685 /// @param loadElements Whether or not to load each array element into a register
686 ///
687 inline void
688 arrayUnpack(llvm::Value* ptrToArray,
689  std::vector<llvm::Value*>& values,
690  llvm::IRBuilder<>& builder,
691  const bool loadElements = false)
692 {
693  const size_t elements =
694  ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
695 
696  values.reserve(elements);
697  for (size_t i = 0; i < elements; ++i) {
698  llvm::Value* value = ir_constgep2_64(builder, ptrToArray, 0, i);
699  if (loadElements) value = ir_load(builder, value);
700  values.push_back(value);
701  }
702 }
703 
704 /// @brief Unpack the first three elements of an array.
705 /// The provided llvm Value is expected to be a pointer to an array
706 /// @note The elements are note loaded
707 ///
708 /// @param ptrToArray A llvm value which is a pointer to a llvm array
709 /// @param value1 The first array value
710 /// @param value2 The second array value
711 /// @param value3 The third array value
712 /// @param builder The current llvm IRBuilder
713 ///
714 inline void
715 array3Unpack(llvm::Value* ptrToArray,
716  llvm::Value*& value1,
717  llvm::Value*& value2,
718  llvm::Value*& value3,
719  llvm::IRBuilder<>& builder)
720 {
721  assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
722  "Input to array3Unpack is not a pointer type.");
723 
724  value1 = ir_constgep2_64(builder, ptrToArray, 0, 0);
725  value2 = ir_constgep2_64(builder, ptrToArray, 0, 1);
726  value3 = ir_constgep2_64(builder, ptrToArray, 0, 2);
727 }
728 
729 /// @brief Pack three values into a new array and return a pointer to the
730 /// newly allocated array. If the values are of a mismatching type,
731 /// the highets order type is uses, as defined by typePrecedence. All
732 /// llvm values are expected to a be a loaded scalar type
733 ///
734 /// @param value1 The first array value
735 /// @param value2 The second array value
736 /// @param value3 The third array value
737 /// @param builder The current llvm IRBuilder
738 ///
739 inline llvm::Value*
740 array3Pack(llvm::Value* value1,
741  llvm::Value* value2,
742  llvm::Value* value3,
743  llvm::IRBuilder<>& builder)
744 {
745  llvm::Type* type = typePrecedence(value1->getType(), value2->getType());
746  type = typePrecedence(type, value3->getType());
747 
748  value1 = arithmeticConversion(value1, type, builder);
749  value2 = arithmeticConversion(value2, type, builder);
750  value3 = arithmeticConversion(value3, type, builder);
751 
752  llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
753  llvm::Value* vector = insertStaticAlloca(builder, vectorType);
754 
755  llvm::Value* e1 = ir_constgep2_64(builder, vector, 0, 0);
756  llvm::Value* e2 = ir_constgep2_64(builder, vector, 0, 1);
757  llvm::Value* e3 = ir_constgep2_64(builder, vector, 0, 2);
758 
759  builder.CreateStore(value1, e1);
760  builder.CreateStore(value2, e2);
761  builder.CreateStore(value3, e3);
762 
763  return vector;
764 }
765 
766 /// @brief Pack a loaded llvm scalar value into a new array of a specified
767 /// size and return a pointer to the newly allocated array. Each element
768 /// of the new array will have the value of the given scalar
769 ///
770 /// @param value The uniform scalar llvm value to pack into the array
771 /// @param builder The current llvm IRBuilder
772 /// @param size The size of the newly allocated array
773 ///
774 inline llvm::Value*
775 arrayPack(llvm::Value* value,
776  llvm::IRBuilder<>& builder,
777  const size_t size = 3)
778 {
779  assert(value && (value->getType()->isIntegerTy() ||
780  value->getType()->isFloatingPointTy()) &&
781  "value type is not a scalar type");
782 
783  llvm::Type* type = value->getType();
784  llvm::Value* array =
785  insertStaticAlloca(builder,
786  llvm::ArrayType::get(type, size));
787 
788  for (size_t i = 0; i < size; ++i) {
789  llvm::Value* element = ir_constgep2_64(builder, array, 0, i);
790  builder.CreateStore(value, element);
791  }
792 
793  return array;
794 }
795 
796 /// @brief Pack a vector of loaded llvm scalar values into a new array of
797 /// equal size and return a pointer to the newly allocated array.
798 ///
799 /// @param values A vector of loaded llvm scalar values to pack
800 /// @param builder The current llvm IRBuilder
801 ///
802 inline llvm::Value*
803 arrayPack(const std::vector<llvm::Value*>& values,
804  llvm::IRBuilder<>& builder)
805 {
806  llvm::Type* type = values.front()->getType();
807  llvm::Value* array = insertStaticAlloca(builder,
808  llvm::ArrayType::get(type, values.size()));
809 
810  size_t idx = 0;
811  for (llvm::Value* const& value : values) {
812  llvm::Value* element = ir_constgep2_64(builder, array, 0, idx++);
813  builder.CreateStore(value, element);
814  }
815 
816  return array;
817 }
818 
819 /// @brief Pack a vector of loaded llvm scalar values into a new array of
820 /// equal size and return a pointer to the newly allocated array.
821 /// arrayPackCast first checks all the contained types in values
822 /// and casts all types to the highest order type present. All llvm
823 /// values in values are expected to be loaded scalar types
824 ///
825 /// @param values A vector of loaded llvm scalar values to pack
826 /// @param builder The current llvm IRBuilder
827 ///
828 inline llvm::Value*
829 arrayPackCast(std::vector<llvm::Value*>& values,
830  llvm::IRBuilder<>& builder)
831 {
832  // get the highest order type present
833 
834  llvm::Type* type = LLVMType<bool>::get(builder.getContext());
835  for (llvm::Value* const& value : values) {
836  type = typePrecedence(type, value->getType());
837  }
838 
839  // convert all to this type
840 
841  for (llvm::Value*& value : values) {
842  value = arithmeticConversion(value, type, builder);
843  }
844 
845  return arrayPack(values, builder);
846 }
847 
848 inline llvm::Value*
849 scalarToMatrix(llvm::Value* scalar,
850  llvm::IRBuilder<>& builder,
851  const size_t dim = 3)
852 {
853  assert(scalar && (scalar->getType()->isIntegerTy() ||
854  scalar->getType()->isFloatingPointTy()) &&
855  "value type is not a scalar type");
856 
857  llvm::Type* type = scalar->getType();
858  llvm::Value* array =
859  insertStaticAlloca(builder,
860  llvm::ArrayType::get(type, dim*dim));
861 
862  llvm::Value* zero = llvmConstant(0, type);
863  for (size_t i = 0; i < dim*dim; ++i) {
864  llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
865  llvm::Value* element = ir_constgep2_64(builder, array, 0, i);
866  builder.CreateStore(m, element);
867  }
868 
869  return array;
870 }
871 
872 } // namespace codegen
873 } // namespace ax
874 } // namespace OPENVDB_VERSION_NAME
875 } // namespace openvdb
876 
877 #endif // OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
878 
llvm::Type * getBaseContainedType(llvm::Type *const type)
Return the base llvm value which is being pointed to through any number of layered pointers...
Definition: Utils.h:147
Definition: axparser.h:140
#define BIND_ARITHMETIC_CAST_OP(Function, Twine)
LLVM type mapping from pod types.
Definition: Types.h:54
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Type *)> CastFunction
Definition: Utils.h:44
#define BIND_BINARY_OP(Function)
Definition: axparser.h:141
Definition: axparser.h:147
llvm::Value * scalarToMatrix(llvm::Value *scalar, llvm::IRBuilder<> &builder, const size_t dim=3)
Definition: Utils.h:849
llvm::Value * arrayCast(llvm::Value *ptrToArray, llvm::Type *targetElementType, llvm::IRBuilder<> &builder)
Casts an array to another array of equal size but of a different element type. Both source and target...
Definition: Utils.h:506
Definition: axparser.h:144
llvm::Value * arrayPack(const std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder)
Pack a vector of loaded llvm scalar values into a new array of equal size and return a pointer to the...
Definition: Utils.h:803
llvm::Value * boolComparison(llvm::Value *value, llvm::IRBuilder<> &builder)
Performs a C style boolean comparison from a given scalar LLVM value.
Definition: Utils.h:620
auto ir_gep(llvm::IRBuilder<> &B, llvm::Value *ptr, llvm::ArrayRef< llvm::Value * > IdxList, const char *Name="")
Alias around IR gep inst.
Definition: Utils.h:66
Definition: axparser.h:136
Definition: axparser.h:145
Consolidated llvm types for most supported types.
Definition: axparser.h:143
auto ir_load(llvm::IRBuilder<> &B, llvm::Value *ptr, const char *Name="")
Alias around IR load inst.
Definition: Utils.h:54
llvm::Value * array3Pack(llvm::Value *value1, llvm::Value *value2, llvm::Value *value3, llvm::IRBuilder<> &builder)
Pack three values into a new array and return a pointer to the newly allocated array. If the values are of a mismatching type, the highets order type is uses, as defined by typePrecedence. All llvm values are expected to a be a loaded scalar type.
Definition: Utils.h:740
void arrayUnpack(llvm::Value *ptrToArray, std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder, const bool loadElements=false)
Unpack an array type into llvm Values which represent all its elements The provided llvm Value is exp...
Definition: Utils.h:688
Definition: axparser.h:151
Definition: axparser.h:137
Definition: axparser.h:146
auto ir_constgep2_64(llvm::IRBuilder<> &B, llvm::Value *ptr, uint64_t Idx0, uint64_t Idx1, const char *Name="")
Alias around IR gep2_64 inst.
Definition: Utils.h:81
llvm::Type * typePrecedence(llvm::Type *const typeA, llvm::Type *const typeB)
Returns the highest order type from two LLVM Scalar types.
Definition: Utils.h:242
llvm::Value * arrayPackCast(std::vector< llvm::Value * > &values, llvm::IRBuilder<> &builder)
Pack a vector of loaded llvm scalar values into a new array of equal size and return a pointer to the...
Definition: Utils.h:829
llvm::Value * insertStaticAlloca(llvm::IRBuilder<> &B, llvm::Type *type, llvm::Value *size=nullptr)
Insert a stack allocation at the beginning of the current function of the provided type and size...
Definition: Utils.h:186
Definition: Exceptions.h:13
Definition: axparser.h:135
std::string Name
Definition: Name.h:19
Definition: axparser.h:150
Definition: axparser.h:142
Definition: axparser.h:149
OperatorType
Definition: Tokens.h:200
llvm::Argument * extractArgument(llvm::Function *F, const std::string &name)
Definition: Utils.h:226
Definition: axparser.h:148
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition: Utils.h:133
Definition: axparser.h:139
llvm::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: Types.h:328
void array3Unpack(llvm::Value *ptrToArray, llvm::Value *&value1, llvm::Value *&value2, llvm::Value *&value3, llvm::IRBuilder<> &builder)
Unpack the first three elements of an array. The provided llvm Value is expected to be a pointer to a...
Definition: Utils.h:715
Definition: axparser.h:152
Definition: axparser.h:138
OperatorType operatorType(const OperatorToken token)
Definition: Tokens.h:210
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Value *)> BinaryFunction
Definition: Utils.h:47
llvm::Value * arrayIndexUnpack(llvm::Value *ptrToArray, const int16_t index, llvm::IRBuilder<> &builder)
Unpack a particular element of an array and return a pointer to that element The provided llvm Value ...
Definition: Utils.h:670
void arithmeticConversion(llvm::Value *&valueA, llvm::Value *&valueB, llvm::IRBuilder<> &builder)
Chooses the highest order llvm Type as defined by typePrecedence from either of the two incoming valu...
Definition: Utils.h:605
OperatorToken
Definition: Tokens.h:150
BinaryFunction llvmBinaryConversion(const llvm::Type *const type, const ast::tokens::OperatorToken &token, const std::string &twine="")
Returns a BinaryFunction representing the corresponding instruction to perform on two scalar values...
Definition: Utils.h:393
llvm::Value * binaryOperator(llvm::Value *lhs, llvm::Value *rhs, const ast::tokens::OperatorToken &token, llvm::IRBuilder<> &builder)
Definition: Utils.h:641
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
bool isValidCast(llvm::Type *from, llvm::Type *to)
Returns true if the llvm Type &#39;from&#39; can be safely cast to the llvm Type &#39;to&#39;.
Definition: Utils.h:453
auto ir_constinboundsgep2_64(llvm::IRBuilder<> &B, llvm::Value *ptr, uint64_t Idx0, uint64_t Idx1, const char *Name="")
Alias around IR in bounds gep2_64 inst.
Definition: Utils.h:97
void valuesToTypes(const std::vector< llvm::Value * > &values, std::vector< llvm::Type * > &types)
Populate a vector of llvm Types from a vector of llvm values.
Definition: Utils.h:118
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212
CastFunction llvmArithmeticConversion(const llvm::Type *const sourceType, const llvm::Type *const targetType, const std::string &twine="")
Returns a CastFunction which represents the corresponding instruction to convert a source llvm Type t...
Definition: Utils.h:288
llvm::Value * llvmPointerFromAddress(const ValueT *const &ptr, llvm::IRBuilder<> &builder)
Return an llvm value representing a pointer to the provided ptr builtin ValueT.
Definition: Utils.h:167