OpenVDB  7.2.1
openvdb_ax/openvdb_ax/codegen/Utils.h
Go to the documentation of this file.
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
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 
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 
54 inline void
55 valuesToTypes(const std::vector<llvm::Value*>& values,
56  std::vector<llvm::Type*>& types)
57 {
58  types.reserve(values.size());
59  for (const auto& v : values) {
60  types.emplace_back(v->getType());
61  }
62 }
63 
69 inline void
70 llvmTypeToString(const llvm::Type* const type, std::string& str)
71 {
72  llvm::raw_string_ostream os(str);
73  type->print(os);
74  os.flush();
75 }
76 
83 inline llvm::Type*
84 getBaseContainedType(llvm::Type* const type)
85 {
86  llvm::Type* elementType = type;
87  while (elementType->isPointerTy()) {
88  elementType = elementType->getContainedType(0);
89  }
90  return elementType;
91 }
92 
102 template <typename ValueT>
103 inline llvm::Value*
104 llvmPointerFromAddress(const ValueT* const& ptr,
105  llvm::IRBuilder<>& builder)
106 {
107  llvm::Value* address =
108  llvm::ConstantInt::get(llvm::Type::getIntNTy(builder.getContext(), sizeof(uintptr_t)*8),
109  reinterpret_cast<uintptr_t>(ptr));
110  return builder.CreateIntToPtr(address, LLVMType<ValueT*>::get(builder.getContext()));
111 }
112 
122 inline llvm::Value*
123 insertStaticAlloca(llvm::IRBuilder<>& B,
124  llvm::Type* type,
125  llvm::Value* size = nullptr)
126 {
127  // Create the allocation at the start of the function block
128  llvm::Function* parent = B.GetInsertBlock()->getParent();
129  assert(parent && !parent->empty());
130  auto IP = B.saveIP();
131  llvm::BasicBlock& block = parent->front();
132  if (block.empty()) B.SetInsertPoint(&block);
133  else B.SetInsertPoint(&(block.front()));
134  llvm::Value* result = B.CreateAlloca(type, size);
135  B.restoreIP(IP);
136  return result;
137 }
138 
139 inline llvm::Argument*
140 extractArgument(llvm::Function* F, const size_t idx)
141 {
142  if (!F) return nullptr;
143  if (idx >= F->arg_size()) return nullptr;
144  return llvm::cast<llvm::Argument>(F->arg_begin() + idx);
145 }
146 
147 inline llvm::Argument*
148 extractArgument(llvm::Function* F, const std::string& name)
149 {
150  if (!F) return nullptr;
151  for (auto iter = F->arg_begin(); iter != F->arg_end(); ++iter) {
152  llvm::Argument* arg = llvm::cast<llvm::Argument>(iter);
153  if (arg->getName() == name) return arg;
154  }
155  return nullptr;
156 }
157 
163 inline llvm::Type*
164 typePrecedence(llvm::Type* const typeA,
165  llvm::Type* const typeB)
166 {
167  assert(typeA && (typeA->isIntegerTy() || typeA->isFloatingPointTy()) &&
168  "First Type in typePrecedence is not a scalar type");
169  assert(typeB && (typeB->isIntegerTy() || typeB->isFloatingPointTy()) &&
170  "Second Type in typePrecedence is not a scalar type");
171 
172  // handle implicit arithmetic conversion
173  // (http://osr507doc.sco.com/en/tools/clang_conv_implicit.html)
174 
175  if (typeA->isDoubleTy()) return typeA;
176  if (typeB->isDoubleTy()) return typeB;
177 
178  if (typeA->isFloatTy()) return typeA;
179  if (typeB->isFloatTy()) return typeB;
180 
181  if (typeA->isIntegerTy(64)) return typeA;
182  if (typeB->isIntegerTy(64)) return typeB;
183 
184  if (typeA->isIntegerTy(32)) return typeA;
185  if (typeB->isIntegerTy(32)) return typeB;
186 
187  if (typeA->isIntegerTy(16)) return typeA;
188  if (typeB->isIntegerTy(16)) return typeB;
189 
190  if (typeA->isIntegerTy(8)) return typeA;
191  if (typeB->isIntegerTy(8)) return typeB;
192 
193  if (typeA->isIntegerTy(1)) return typeA;
194  if (typeB->isIntegerTy(1)) return typeB;
195 
196  assert(false && "invalid LLVM type precedence");
197  return nullptr;
198 }
199 
209 inline CastFunction
210 llvmArithmeticConversion(const llvm::Type* const sourceType,
211  const llvm::Type* const targetType,
212  const std::string& twine = "")
213 {
214 
215 #define BIND_ARITHMETIC_CAST_OP(Function, Twine) \
216  std::bind(&Function, \
217  std::placeholders::_1, \
218  std::placeholders::_2, \
219  std::placeholders::_3, \
220  Twine)
221 
222  if (targetType->isDoubleTy()) {
223  if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
224  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
225  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
226  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
227  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
228  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
229  }
230  else if (targetType->isFloatTy()) {
231  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
232  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
233  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
234  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
235  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
236  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
237  }
238  else if (targetType->isIntegerTy(64)) {
239  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
240  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
241  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
242  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
243  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
244  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
245  }
246  else if (targetType->isIntegerTy(32)) {
247  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
248  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
249  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
250  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
251  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
252  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
253  }
254  else if (targetType->isIntegerTy(16)) {
255  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
256  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
257  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
258  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
259  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
260  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
261  }
262  else if (targetType->isIntegerTy(8)) {
263  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
264  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
265  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
266  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
267  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
268  else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
269  }
270  else if (targetType->isIntegerTy(1)) {
271  if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
272  else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
273  else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
274  else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
275  else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
276  else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
277  }
278 
279 #undef BIND_ARITHMETIC_CAST_OP
280  assert(false && "invalid LLVM type conversion");
281  return CastFunction();
282 }
283 
298 inline BinaryFunction
299 llvmBinaryConversion(const llvm::Type* const type,
300  const ast::tokens::OperatorToken& token,
301  const std::string& twine = "")
302 {
303 
304 #define BIND_BINARY_OP(Function) \
305  [twine](llvm::IRBuilder<>& B, llvm::Value* L, llvm::Value* R) \
306  -> llvm::Value* { return B.Function(L, R, twine); }
307 
308  // NOTE: Binary % and / ops always take sign into account (CreateSDiv vs CreateUDiv, CreateSRem vs CreateURem).
309  // See http://stackoverflow.com/questions/5346160/llvm-irbuildercreateudiv-createsdiv-createexactudiv
310  // a%b in AX is implemented as a floored modulo op and is handled explicitly in binaryExpression
311 
312  if (type->isFloatingPointTy()) {
313  assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL ||
315  && "unable to perform logical or bitwise operation on floating point values");
316 
317  if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateFAdd);
318  else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateFSub);
319  else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateFMul);
320  else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateFDiv);
321  else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateFRem); // Note this is NOT a%b in AX.
322  else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateFCmpOEQ);
323  else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateFCmpONE);
324  else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateFCmpOGT);
325  else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateFCmpOLT);
326  else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOGE);
327  else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOLE);
328  assert(false && "unrecognised binary operator");
329  }
330  else if (type->isIntegerTy()) {
331  if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateAdd); // No Unsigned/Signed Wrap
332  else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateSub); // No Unsigned/Signed Wrap
333  else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateMul); // No Unsigned/Signed Wrap
334  else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateSDiv); // IsExact = false - when true, poison value if the reuslt is rounded
335  else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateSRem); // Note this is NOT a%b in AX.
336  else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateICmpEQ);
337  else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateICmpNE);
338  else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateICmpSGT);
339  else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateICmpSLT);
340  else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateICmpSGE);
341  else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateICmpSLE);
342  else if (token == ast::tokens::AND) return BIND_BINARY_OP(CreateAnd);
343  else if (token == ast::tokens::OR) return BIND_BINARY_OP(CreateOr);
344  else if (token == ast::tokens::SHIFTLEFT) return BIND_BINARY_OP(CreateShl); // No Unsigned/Signed Wrap
345  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.
346  else if (token == ast::tokens::BITAND) return BIND_BINARY_OP(CreateAnd);
347  else if (token == ast::tokens::BITOR) return BIND_BINARY_OP(CreateOr);
348  else if (token == ast::tokens::BITXOR) return BIND_BINARY_OP(CreateXor);
349  assert(false && "unrecognised binary operator");
350  }
351 
352 #undef BIND_BINARY_OP
353  assert(false && "invalid LLVM type for binary operation");
354  return BinaryFunction();
355 }
356 
359 inline bool isValidCast(llvm::Type* from, llvm::Type* to)
360 {
361  assert(from && "llvm Type 'from' is null in isValidCast");
362  assert(to && "llvm Type 'to' is null in isValidCast");
363 
364  if ((from->isIntegerTy() || from->isFloatingPointTy()) &&
365  (to->isIntegerTy() || to->isFloatingPointTy())) {
366  return true;
367  }
368  if (from->isArrayTy() && to->isArrayTy()) {
369  llvm::ArrayType* af = llvm::cast<llvm::ArrayType>(from);
370  llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(to);
371  if (af->getArrayNumElements() == at->getArrayNumElements()) {
372  return isValidCast(af->getArrayElementType(),
373  at->getArrayElementType());
374  }
375  }
376  return false;
377 }
378 
386 inline llvm::Value*
387 arithmeticConversion(llvm::Value* value,
388  llvm::Type* targetType,
389  llvm::IRBuilder<>& builder)
390 {
391  assert(value && (value->getType()->isIntegerTy() || value->getType()->isFloatingPointTy()) &&
392  "First Value in arithmeticConversion is not a scalar type");
393  assert(targetType && (targetType->isIntegerTy() || targetType->isFloatingPointTy()) &&
394  "Target Type in arithmeticConversion is not a scalar type");
395 
396  const llvm::Type* const valueType = value->getType();
397  if (valueType == targetType) return value;
398 
399  CastFunction llvmCastFunction = llvmArithmeticConversion(valueType, targetType);
400  return llvmCastFunction(builder, value, targetType);
401 }
402 
412 inline llvm::Value*
413 arrayCast(llvm::Value* ptrToArray,
414  llvm::Type* targetElementType,
415  llvm::IRBuilder<>& builder)
416 {
417  assert(targetElementType && (targetElementType->isIntegerTy() ||
418  targetElementType->isFloatingPointTy()) &&
419  "Target element type is not a scalar type");
420  assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
421  "Input to arrayCast is not a pointer type.");
422 
423  llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
424  assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
425 
426  // getArrayElementType() calls getContainedType(0)
427  llvm::Type* sourceElementType = arrayType->getArrayElementType();
428  assert(sourceElementType && (sourceElementType->isIntegerTy() ||
429  sourceElementType->isFloatingPointTy()) &&
430  "Source element type is not a scalar type");
431 
432  if (sourceElementType == targetElementType) return ptrToArray;
433 
434  CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
435 
436  const size_t elementSize = arrayType->getArrayNumElements();
437  llvm::Value* targetArray =
438  insertStaticAlloca(builder,
439  llvm::ArrayType::get(targetElementType, elementSize));
440 
441  for (size_t i = 0; i < elementSize; ++i) {
442  llvm::Value* target = builder.CreateConstGEP2_64(targetArray, 0, i);
443  llvm::Value* source = builder.CreateConstGEP2_64(ptrToArray, 0, i);
444  source = builder.CreateLoad(source);
445  source = llvmCastFunction(builder, source, targetElementType);
446  builder.CreateStore(source, target);
447  }
448 
449  return targetArray;
450 }
451 
461 inline void
462 arithmeticConversion(std::vector<llvm::Value*>& values,
463  llvm::Type* targetElementType,
464  llvm::IRBuilder<>& builder)
465 {
466  assert(targetElementType && (targetElementType->isIntegerTy() ||
467  targetElementType->isFloatingPointTy()) &&
468  "Target element type is not a scalar type");
469 
470  llvm::Type* sourceElementType = values.front()->getType();
471  assert(sourceElementType && (sourceElementType->isIntegerTy() ||
472  sourceElementType->isFloatingPointTy()) &&
473  "Source element type is not a scalar type");
474 
475  if (sourceElementType == targetElementType) return;
476 
477  CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
478 
479  for (llvm::Value*& value : values) {
480  value = llvmCastFunction(builder, value, targetElementType);
481  }
482 }
483 
490 inline void
491 arithmeticConversion(std::vector<llvm::Value*>& values,
492  llvm::IRBuilder<>& builder)
493 {
494  llvm::Type* typeCast = LLVMType<bool>::get(builder.getContext());
495  for (llvm::Value*& value : values) {
496  llvm::Type* type = value->getType();
497  if (type->isIntegerTy() || type->isFloatingPointTy()) {
498  typeCast = typePrecedence(typeCast, type);
499  }
500  }
501 
502  arithmeticConversion(values, typeCast, builder);
503 }
504 
514 inline void
515 arithmeticConversion(llvm::Value*& valueA,
516  llvm::Value*& valueB,
517  llvm::IRBuilder<>& builder)
518 {
519  llvm::Type* type = typePrecedence(valueA->getType(), valueB->getType());
520  valueA = arithmeticConversion(valueA, type, builder);
521  valueB = arithmeticConversion(valueB, type, builder);
522 }
523 
529 inline llvm::Value*
530 boolComparison(llvm::Value* value,
531  llvm::IRBuilder<>& builder)
532 {
533  llvm::Type* type = value->getType();
534 
535  if (type->isFloatingPointTy()) return builder.CreateFCmpONE(value, llvm::ConstantFP::get(type, 0.0));
536  else if (type->isIntegerTy(1)) return builder.CreateICmpNE(value, llvm::ConstantInt::get(type, 0));
537  else if (type->isIntegerTy()) return builder.CreateICmpNE(value, llvm::ConstantInt::getSigned(type, 0));
538  assert(false && "Invalid type for bool conversion");
539  return nullptr;
540 }
541 
550 inline llvm::Value*
551 binaryOperator(llvm::Value* lhs, llvm::Value* rhs,
552  const ast::tokens::OperatorToken& token,
553  llvm::IRBuilder<>& builder)
554 {
555  llvm::Type* lhsType = lhs->getType();
556  assert(lhsType == rhs->getType());
557 
559 
560  if (opType == ast::tokens::LOGICAL) {
561  lhs = boolComparison(lhs, builder);
562  rhs = boolComparison(rhs, builder);
563  lhsType = lhs->getType(); // now bool type
564  }
565 
566  const BinaryFunction llvmBinaryFunction = llvmBinaryConversion(lhsType, token);
567  return llvmBinaryFunction(builder, lhs, rhs);
568 }
569 
577 inline llvm::Value*
578 arrayIndexUnpack(llvm::Value* ptrToArray,
579  const int16_t index,
580  llvm::IRBuilder<>& builder)
581 {
582  return builder.CreateConstGEP2_64(ptrToArray, 0, index);
583 }
584 
595 inline void
596 arrayUnpack(llvm::Value* ptrToArray,
597  std::vector<llvm::Value*>& values,
598  llvm::IRBuilder<>& builder,
599  const bool loadElements = false)
600 {
601  const size_t elements =
602  ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
603 
604  values.reserve(elements);
605  for (size_t i = 0; i < elements; ++i) {
606  llvm::Value* value = builder.CreateConstGEP2_64(ptrToArray, 0, i);
607  if (loadElements) value = builder.CreateLoad(value);
608  values.push_back(value);
609  }
610 }
611 
622 inline void
623 array3Unpack(llvm::Value* ptrToArray,
624  llvm::Value*& value1,
625  llvm::Value*& value2,
626  llvm::Value*& value3,
627  llvm::IRBuilder<>& builder)
628 {
629  assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
630  "Input to array3Unpack is not a pointer type.");
631 
632  value1 = builder.CreateConstGEP2_64(ptrToArray, 0, 0);
633  value2 = builder.CreateConstGEP2_64(ptrToArray, 0, 1);
634  value3 = builder.CreateConstGEP2_64(ptrToArray, 0, 2);
635 }
636 
647 inline llvm::Value*
648 array3Pack(llvm::Value* value1,
649  llvm::Value* value2,
650  llvm::Value* value3,
651  llvm::IRBuilder<>& builder)
652 {
653  llvm::Type* type = typePrecedence(value1->getType(), value2->getType());
654  type = typePrecedence(type, value3->getType());
655 
656  value1 = arithmeticConversion(value1, type, builder);
657  value2 = arithmeticConversion(value2, type, builder);
658  value3 = arithmeticConversion(value3, type, builder);
659 
660  llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
661  llvm::Value* vector = insertStaticAlloca(builder, vectorType);
662 
663  llvm::Value* e1 = builder.CreateConstGEP2_64(vector, 0, 0);
664  llvm::Value* e2 = builder.CreateConstGEP2_64(vector, 0, 1);
665  llvm::Value* e3 = builder.CreateConstGEP2_64(vector, 0, 2);
666 
667  builder.CreateStore(value1, e1);
668  builder.CreateStore(value2, e2);
669  builder.CreateStore(value3, e3);
670 
671  return vector;
672 }
673 
682 inline llvm::Value*
683 arrayPack(llvm::Value* value,
684  llvm::IRBuilder<>& builder,
685  const size_t size = 3)
686 {
687  assert(value && (value->getType()->isIntegerTy() ||
688  value->getType()->isFloatingPointTy()) &&
689  "value type is not a scalar type");
690 
691  llvm::Type* type = value->getType();
692  llvm::Value* array =
693  insertStaticAlloca(builder,
694  llvm::ArrayType::get(type, size));
695 
696  for (size_t i = 0; i < size; ++i) {
697  llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
698  builder.CreateStore(value, element);
699  }
700 
701  return array;
702 }
703 
710 inline llvm::Value*
711 arrayPack(const std::vector<llvm::Value*>& values,
712  llvm::IRBuilder<>& builder)
713 {
714  llvm::Type* type = values.front()->getType();
715  llvm::Value* array = insertStaticAlloca(builder,
716  llvm::ArrayType::get(type, values.size()));
717 
718  size_t idx = 0;
719  for (llvm::Value* const& value : values) {
720  llvm::Value* element = builder.CreateConstGEP2_64(array, 0, idx++);
721  builder.CreateStore(value, element);
722  }
723 
724  return array;
725 }
726 
736 inline llvm::Value*
737 arrayPackCast(std::vector<llvm::Value*>& values,
738  llvm::IRBuilder<>& builder)
739 {
740  // get the highest order type present
741 
742  llvm::Type* type = LLVMType<bool>::get(builder.getContext());
743  for (llvm::Value* const& value : values) {
744  type = typePrecedence(type, value->getType());
745  }
746 
747  // convert all to this type
748 
749  for (llvm::Value*& value : values) {
750  value = arithmeticConversion(value, type, builder);
751  }
752 
753  return arrayPack(values, builder);
754 }
755 
756 inline llvm::Value*
757 scalarToMatrix(llvm::Value* scalar,
758  llvm::IRBuilder<>& builder,
759  const size_t dim = 3)
760 {
761  assert(scalar && (scalar->getType()->isIntegerTy() ||
762  scalar->getType()->isFloatingPointTy()) &&
763  "value type is not a scalar type");
764 
765  llvm::Type* type = scalar->getType();
766  llvm::Value* array =
767  insertStaticAlloca(builder,
768  llvm::ArrayType::get(type, dim*dim));
769 
770  llvm::Value* zero = llvm::ConstantFP::get(type, 0.0);
771 
772  for (size_t i = 0; i < dim*dim; ++i) {
773  llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
774  llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
775  builder.CreateStore(m, element);
776  }
777 
778  return array;
779 }
780 
781 } // namespace codegen
782 } // namespace ax
783 } // namespace OPENVDB_VERSION_NAME
784 } // namespace openvdb
785 
786 #endif // OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
787 
BIND_BINARY_OP
#define BIND_BINARY_OP(Function)
SHIFTRIGHT
@ SHIFTRIGHT
Definition: axparser.h:138
Types.h
Consolidated llvm types for most supported types.
openvdb::v7_2::ax::codegen::arrayCast
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: openvdb_ax/openvdb_ax/codegen/Utils.h:413
BITXOR
@ BITXOR
Definition: axparser.h:129
openvdb::v7_2::ax::codegen::getBaseContainedType
llvm::Type * getBaseContainedType(llvm::Type *const type)
Return the base llvm value which is being pointed to through any number of layered pointers.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:84
openvdb::v7_2::ax::codegen::boolComparison
llvm::Value * boolComparison(llvm::Value *value, llvm::IRBuilder<> &builder)
Performs a C style boolean comparison from a given scalar LLVM value.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:530
LESSTHANOREQUAL
@ LESSTHANOREQUAL
Definition: axparser.h:136
openvdb::v7_2::ax::codegen::arithmeticConversion
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: openvdb_ax/openvdb_ax/codegen/Utils.h:515
openvdb::v7_2::ax::codegen::llvmArithmeticConversion
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: openvdb_ax/openvdb_ax/codegen/Utils.h:210
PLUS
@ PLUS
Definition: axparser.h:139
LESSTHAN
@ LESSTHAN
Definition: axparser.h:134
openvdb::v7_2::ax::codegen::typePrecedence
llvm::Type * typePrecedence(llvm::Type *const typeA, llvm::Type *const typeB)
Returns the highest order type from two LLVM Scalar types.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:164
openvdb::v7_2::ax::codegen::valuesToTypes
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: openvdb_ax/openvdb_ax/codegen/Utils.h:55
openvdb::v7_2::ax::codegen::isValidCast
bool isValidCast(llvm::Type *from, llvm::Type *to)
Returns true if the llvm Type 'from' can be safely cast to the llvm Type 'to'.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:359
openvdb::v7_2::ax::codegen::BinaryFunction
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Value *)> BinaryFunction
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:47
version.h
Library and file format version numbers.
openvdb::v7_2::ax::codegen::arrayIndexUnpack
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: openvdb_ax/openvdb_ax/codegen/Utils.h:578
BITOR
@ BITOR
Definition: axparser.h:128
openvdb::v7_2::ax::codegen::insertStaticAlloca
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: openvdb_ax/openvdb_ax/codegen/Utils.h:123
openvdb::v7_2::ax::codegen::arrayUnpack
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: openvdb_ax/openvdb_ax/codegen/Utils.h:596
MODULO
@ MODULO
Definition: axparser.h:143
openvdb::v7_2::ax::codegen::arrayPack
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: openvdb_ax/openvdb_ax/codegen/Utils.h:711
MULTIPLY
@ MULTIPLY
Definition: axparser.h:141
openvdb::v7_2::ax::codegen::array3Pack
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....
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:648
openvdb::v7_2::ax::ast::tokens::LOGICAL
@ LOGICAL
Definition: Tokens.h:203
OR
@ OR
Definition: axparser.h:126
openvdb::v7_2::ax::codegen::array3Unpack
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: openvdb_ax/openvdb_ax/codegen/Utils.h:623
NOTEQUALS
@ NOTEQUALS
Definition: axparser.h:132
SHIFTLEFT
@ SHIFTLEFT
Definition: axparser.h:137
BITAND
@ BITAND
Definition: axparser.h:130
MORETHANOREQUAL
@ MORETHANOREQUAL
Definition: axparser.h:135
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h:147
openvdb::v7_2::ax::ast::tokens::OperatorToken
OperatorToken
Definition: Tokens.h:151
openvdb::v7_2::ax::codegen::llvmTypeToString
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:70
openvdb::v7_2::ax::ast::tokens::operatorType
OperatorType operatorType(const OperatorToken token)
Definition: Tokens.h:210
MORETHAN
@ MORETHAN
Definition: axparser.h:133
openvdb::v7_2::ax::codegen::arrayPackCast
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: openvdb_ax/openvdb_ax/codegen/Utils.h:737
BIND_ARITHMETIC_CAST_OP
#define BIND_ARITHMETIC_CAST_OP(Function, Twine)
MINUS
@ MINUS
Definition: axparser.h:140
openvdb::v7_2::ax::codegen::llvmBinaryConversion
BinaryFunction llvmBinaryConversion(const llvm::Type *const type, const ast::tokens::OperatorToken &token, const std::string &twine="")
Returns a BinaryFunction representing the corresponding instruction to peform on two scalar values,...
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:299
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h:95
openvdb::v7_2::ax::codegen::extractArgument
llvm::Argument * extractArgument(llvm::Function *F, const std::string &name)
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:148
openvdb::v7_2::ax::codegen::scalarToMatrix
llvm::Value * scalarToMatrix(llvm::Value *scalar, llvm::IRBuilder<> &builder, const size_t dim=3)
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:757
AND
@ AND
Definition: axparser.h:127
openvdb::v7_2::ax::codegen::CastFunction
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Type *)> CastFunction
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:44
EQUALSEQUALS
@ EQUALSEQUALS
Definition: axparser.h:131
openvdb::v7_2::ax::codegen::binaryOperator
llvm::Value * binaryOperator(llvm::Value *lhs, llvm::Value *rhs, const ast::tokens::OperatorToken &token, llvm::IRBuilder<> &builder)
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:551
openvdb
Definition: openvdb/Exceptions.h:13
openvdb::v7_2::ax::ast::tokens::BITWISE
@ BITWISE
Definition: Tokens.h:205
openvdb::v7_2::ax::codegen::LLVMType
LLVM type mapping from pod types.
Definition: ax/openvdb_ax/codegen/Types.h:55
openvdb::v7_2::ax::codegen::llvmPointerFromAddress
llvm::Value * llvmPointerFromAddress(const ValueT *const &ptr, llvm::IRBuilder<> &builder)
Return an llvm value representing a pointer to the provided ptr builtin ValueT.
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:104
DIVIDE
@ DIVIDE
Definition: axparser.h:142
openvdb::v7_2::ax::ast::tokens::OperatorType
OperatorType
Definition: Tokens.h:201