12#ifndef OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
13#define OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
17#include "../ast/Tokens.h"
18#include "../Exceptions.h"
20#include <openvdb/version.h>
22#include <llvm/IR/IRBuilder.h>
23#include <llvm/IR/LLVMContext.h>
31#include <llvm/Support/raw_ostream.h>
44 (llvm::IRBuilder<>&, llvm::Value*, llvm::Type*)>;
47 (llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>;
54inline auto ir_load(llvm::IRBuilder<>& B, llvm::Value* ptr,
const char*
Name =
"")
57 assert(ptr->getType()->isPointerTy());
58#if LLVM_VERSION_MAJOR <= 7
59 return B.CreateLoad(ptr,
Name);
61 return B.CreateLoad(ptr->getType()->getPointerElementType(), ptr,
Name);
66inline auto ir_gep(llvm::IRBuilder<>& B,
67 llvm::Value* ptr, llvm::ArrayRef<llvm::Value*> IdxList,
const char*
Name =
"")
70 assert(ptr->getType()->getScalarType());
71 assert(ptr->getType()->getScalarType()->isPointerTy());
72#if LLVM_VERSION_MAJOR <= 7
73 return B.CreateGEP(ptr, IdxList,
Name);
75 return B.CreateGEP(ptr->getType()->getScalarType()->getPointerElementType(),
82 llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1,
const char*
Name =
"")
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);
90 return B.CreateConstGEP2_64(
91 ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
98 llvm::Value* ptr, uint64_t Idx0, uint64_t Idx1,
const char*
Name =
"")
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);
106 return B.CreateConstInBoundsGEP2_64(
107 ptr->getType()->getScalarType()->getPointerElementType(), ptr, Idx0,
119 std::vector<llvm::Type*>& types)
121 types.reserve(values.size());
122 for (
const auto& v : values) {
123 types.emplace_back(v->getType());
135 llvm::raw_string_ostream os(str);
149 llvm::Type* elementType = type;
150 while (elementType->isPointerTy()) {
151 elementType = elementType->getContainedType(0);
165template <
typename ValueT>
168 llvm::IRBuilder<>& builder)
170 llvm::Value* address =
171 llvm::ConstantInt::get(llvm::Type::getIntNTy(builder.getContext(),
sizeof(uintptr_t)*8),
172 reinterpret_cast<uintptr_t
>(ptr));
188 llvm::Value* size =
nullptr)
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);
205 if (type == strtype) {
206 llvm::Value* cptr = B.CreateStructGEP(strtype, result, 0);
207 llvm::Value* sso = B.CreateStructGEP(strtype, result, 1);
209 llvm::Value* len = B.CreateStructGEP(strtype, result, 2);
210 B.CreateStore(sso_load, cptr);
211 B.CreateStore(B.getInt64(0), len);
217inline llvm::Argument*
220 if (!F)
return nullptr;
221 if (idx >= F->arg_size())
return nullptr;
222 return llvm::cast<llvm::Argument>(F->arg_begin() + idx);
225inline llvm::Argument*
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;
243 llvm::Type*
const typeB)
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");
253 if (typeA->isDoubleTy())
return typeA;
254 if (typeB->isDoubleTy())
return typeB;
256 if (typeA->isFloatTy())
return typeA;
257 if (typeB->isFloatTy())
return typeB;
259 if (typeA->isIntegerTy(64))
return typeA;
260 if (typeB->isIntegerTy(64))
return typeB;
262 if (typeA->isIntegerTy(32))
return typeA;
263 if (typeB->isIntegerTy(32))
return typeB;
265 if (typeA->isIntegerTy(16))
return typeA;
266 if (typeB->isIntegerTy(16))
return typeB;
268 if (typeA->isIntegerTy(8))
return typeA;
269 if (typeB->isIntegerTy(8))
return typeB;
271 if (typeA->isIntegerTy(1))
return typeA;
272 if (typeB->isIntegerTy(1))
return typeB;
274 assert(
false &&
"invalid LLVM type precedence");
289 const llvm::Type*
const targetType,
290 const std::string& twine =
"")
293#define BIND_ARITHMETIC_CAST_OP(Function, Twine) \
294 std::bind(&Function, \
295 std::placeholders::_1, \
296 std::placeholders::_2, \
297 std::placeholders::_3, \
300 if (targetType->isDoubleTy()) {
309 else if (targetType->isFloatTy()) {
318 else if (targetType->isHalfTy()) {
327 else if (targetType->isIntegerTy(64)) {
336 else if (targetType->isIntegerTy(32)) {
345 else if (targetType->isIntegerTy(16)) {
354 else if (targetType->isIntegerTy(8)) {
363 else if (targetType->isIntegerTy(1)) {
373#undef BIND_ARITHMETIC_CAST_OP
374 assert(
false &&
"invalid LLVM type conversion");
395 const std::string& twine =
"")
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); }
406 if (type->isFloatingPointTy()) {
407 assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL ||
408 ast::tokens::operatorType(token) == ast::tokens::BITWISE)
409 &&
"unable to perform logical or bitwise operation on floating point values");
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);
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");
424 else if (type->isIntegerTy()) {
426 else if (token == ast::tokens::MINUS)
return BIND_BINARY_OP(CreateSub);
427 else if (token == ast::tokens::MULTIPLY)
return BIND_BINARY_OP(CreateMul);
428 else if (token == ast::tokens::DIVIDE)
return BIND_BINARY_OP(CreateSDiv);
429 else if (token == ast::tokens::MODULO)
return BIND_BINARY_OP(CreateSRem);
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);
439 else if (token == ast::tokens::SHIFTRIGHT)
return BIND_BINARY_OP(CreateAShr);
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");
447 assert(
false &&
"invalid LLVM type for binary operation");
455 assert(from &&
"llvm Type 'from' is null in isValidCast");
456 assert(to &&
"llvm Type 'to' is null in isValidCast");
458 if ((from->isIntegerTy() || from->isFloatingPointTy()) &&
459 (to->isIntegerTy() || to->isFloatingPointTy())) {
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()) {
467 at->getArrayElementType());
481 llvm::Type* targetType,
482 llvm::IRBuilder<>& builder)
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");
489 const llvm::Type*
const valueType =
value->getType();
490 if (valueType == targetType)
return value;
493 return llvmCastFunction(builder,
value, targetType);
507 llvm::Type* targetElementType,
508 llvm::IRBuilder<>& builder)
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.");
516 llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
517 assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
520 llvm::Type* sourceElementType = arrayType->getArrayElementType();
521 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
522 sourceElementType->isFloatingPointTy()) &&
523 "Source element type is not a scalar type");
525 if (sourceElementType == targetElementType)
return ptrToArray;
529 const size_t elementSize = arrayType->getArrayNumElements();
530 llvm::Value* targetArray =
532 llvm::ArrayType::get(targetElementType, elementSize));
534 for (
size_t i = 0; i < elementSize; ++i) {
537 source =
ir_load(builder, source);
538 source = llvmCastFunction(builder, source, targetElementType);
539 builder.CreateStore(source, target);
555 llvm::Type* targetElementType,
556 llvm::IRBuilder<>& builder)
558 assert(targetElementType && (targetElementType->isIntegerTy() ||
559 targetElementType->isFloatingPointTy()) &&
560 "Target element type is not a scalar type");
562 llvm::Type* sourceElementType = values.front()->getType();
563 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
564 sourceElementType->isFloatingPointTy()) &&
565 "Source element type is not a scalar type");
567 if (sourceElementType == targetElementType)
return;
571 for (llvm::Value*&
value : values) {
572 value = llvmCastFunction(builder,
value, targetElementType);
583 llvm::IRBuilder<>& builder)
586 for (llvm::Value*&
value : values) {
587 llvm::Type* type =
value->getType();
588 if (type->isIntegerTy() || type->isFloatingPointTy()) {
606 llvm::Value*& valueB,
607 llvm::IRBuilder<>& builder)
609 llvm::Type* type =
typePrecedence(valueA->getType(), valueB->getType());
621 llvm::IRBuilder<>& builder)
623 llvm::Type* type =
value->getType();
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");
643 llvm::IRBuilder<>& builder)
645 llvm::Type* lhsType = lhs->getType();
646 assert(lhsType == rhs->getType() ||
647 (token == ast::tokens::SHIFTLEFT ||
648 token == ast::tokens::SHIFTRIGHT));
652 if (opType == ast::tokens::LOGICAL) {
655 lhsType = lhs->getType();
659 return llvmBinaryFunction(builder, lhs, rhs);
672 llvm::IRBuilder<>& builder)
689 std::vector<llvm::Value*>& values,
690 llvm::IRBuilder<>& builder,
691 const bool loadElements =
false)
693 const size_t elements =
694 ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
696 values.reserve(elements);
697 for (
size_t i = 0; i < elements; ++i) {
700 values.push_back(
value);
716 llvm::Value*& value1,
717 llvm::Value*& value2,
718 llvm::Value*& value3,
719 llvm::IRBuilder<>& builder)
721 assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
722 "Input to array3Unpack is not a pointer type.");
743 llvm::IRBuilder<>& builder)
745 llvm::Type* type =
typePrecedence(value1->getType(), value2->getType());
752 llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
759 builder.CreateStore(value1, e1);
760 builder.CreateStore(value2, e2);
761 builder.CreateStore(value3, e3);
776 llvm::IRBuilder<>& builder,
777 const size_t size = 3)
779 assert(
value && (
value->getType()->isIntegerTy() ||
780 value->getType()->isFloatingPointTy()) &&
781 "value type is not a scalar type");
783 llvm::Type* type =
value->getType();
786 llvm::ArrayType::get(type, size));
788 for (
size_t i = 0; i < size; ++i) {
790 builder.CreateStore(
value, element);
804 llvm::IRBuilder<>& builder)
806 llvm::Type* type = values.front()->getType();
808 llvm::ArrayType::get(type, values.size()));
811 for (llvm::Value*
const&
value : values) {
813 builder.CreateStore(
value, element);
830 llvm::IRBuilder<>& builder)
835 for (llvm::Value*
const&
value : values) {
841 for (llvm::Value*&
value : values) {
850 llvm::IRBuilder<>& builder,
851 const size_t dim = 3)
853 assert(scalar && (scalar->getType()->isIntegerTy() ||
854 scalar->getType()->isFloatingPointTy()) &&
855 "value type is not a scalar type");
857 llvm::Type* type = scalar->getType();
860 llvm::ArrayType::get(type, dim*dim));
863 for (
size_t i = 0; i < dim*dim; ++i) {
864 llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
866 builder.CreateStore(m, element);
ValueT value
Definition: GridBuilder.h:1290
Consolidated llvm types for most supported types.
OperatorToken
Definition: Tokens.h:151
OperatorType
Definition: Tokens.h:201
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
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
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
llvm::Value * arithmeticConversion(llvm::Value *value, llvm::Type *targetType, llvm::IRBuilder<> &builder)
Casts a scalar llvm Value to a target scalar llvm Type. Returns the cast scalar value of type targetT...
Definition: Utils.h:480
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
void llvmTypeToString(const llvm::Type *const type, std::string &str)
Prints an llvm type to a std string.
Definition: Utils.h:133
llvm::Value * binaryOperator(llvm::Value *lhs, llvm::Value *rhs, const ast::tokens::OperatorToken &token, llvm::IRBuilder<> &builder)
Definition: Utils.h:641
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
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: Utils.h:453
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
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: Utils.h:740
auto ir_load(llvm::IRBuilder<> &B, llvm::Value *ptr, const char *Name="")
Alias around IR load inst.
Definition: Utils.h:54
llvm::Value * scalarToMatrix(llvm::Value *scalar, llvm::IRBuilder<> &builder, const size_t dim=3)
Definition: Utils.h:849
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
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Type *)> CastFunction
Definition: Utils.h:44
llvm::Argument * extractArgument(llvm::Function *F, const size_t idx)
Definition: Utils.h:218
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 * 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
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::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: Types.h:328
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
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
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::Value * boolComparison(llvm::Value *value, llvm::IRBuilder<> &builder)
Performs a C style boolean comparison from a given scalar LLVM value.
Definition: Utils.h:620
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Value *)> BinaryFunction
Definition: Utils.h:47
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
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 * arrayPack(llvm::Value *value, llvm::IRBuilder<> &builder, const size_t size=3)
Pack a loaded llvm scalar value into a new array of a specified size and return a pointer to the newl...
Definition: Utils.h:775
std::string Name
Definition: Name.h:17
Definition: Exceptions.h:13
#define BIND_ARITHMETIC_CAST_OP(Function, Twine)
#define BIND_BINARY_OP(Function)
LLVM type mapping from pod types.
Definition: Types.h:55
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:121
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:212