OpenVDB: Utils.h Source File

OpenVDB 8.1.0

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 {
34 OPENVDB_USE_VERSION_NAMESPACE
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 llvm::Type* strtype = LLVMType<codegen::String>::get(B.getContext());
128 // Create the allocation at the start of the function block
129 llvm::Function* parent = B.GetInsertBlock()->getParent();
130 assert(parent && !parent->empty());
131 auto IP = B.saveIP();
132 llvm::BasicBlock& block = parent->front();
133 if (block.empty()) B.SetInsertPoint(&block);
134 else B.SetInsertPoint(&(block.front()));
135 llvm::Value* result = B.CreateAlloca(type, size);
136
142 if (type == strtype) {
143 llvm::Value* cptr = B.CreateStructGEP(strtype, result, 0); // char**
144 llvm::Value* sso = B.CreateStructGEP(strtype, result, 1); // char[]*
145 llvm::Value* sso_load = B.CreateConstGEP2_64(sso, 0 ,0); // char*
146 llvm::Value* len = B.CreateStructGEP(strtype, result, 2);
147 B.CreateStore(sso_load, cptr); // this->ptr = this->SSO;
148 B.CreateStore(B.getInt64(0), len);
149 }
150 B.restoreIP(IP);
151 return result;
152 }
153
154 inline llvm::Argument*
155 extractArgument(llvm::Function* F, const size_t idx)
156 {
157 if (!F) return nullptr;
158 if (idx >= F->arg_size()) return nullptr;
159 return llvm::cast<llvm::Argument>(F->arg_begin() + idx);
160 }
161
162 inline llvm::Argument*
163 extractArgument(llvm::Function* F, const std::string& name)
164 {
165 if (!F) return nullptr;
166 for (auto iter = F->arg_begin(); iter != F->arg_end(); ++iter) {
167 llvm::Argument* arg = llvm::cast<llvm::Argument>(iter);
168 if (arg->getName() == name) return arg;
169 }
170 return nullptr;
171 }
172
178 inline llvm::Type*
179 typePrecedence(llvm::Type* const typeA,
180 llvm::Type* const typeB)
181 {
182 assert(typeA && (typeA->isIntegerTy() || typeA->isFloatingPointTy()) &&
183 "First Type in typePrecedence is not a scalar type");
184 assert(typeB && (typeB->isIntegerTy() || typeB->isFloatingPointTy()) &&
185 "Second Type in typePrecedence is not a scalar type");
186
187 // handle implicit arithmetic conversion
188 // (http://osr507doc.sco.com/en/tools/clang_conv_implicit.html)
189
190 if (typeA->isDoubleTy()) return typeA;
191 if (typeB->isDoubleTy()) return typeB;
192
193 if (typeA->isFloatTy()) return typeA;
194 if (typeB->isFloatTy()) return typeB;
195
196 if (typeA->isIntegerTy(64)) return typeA;
197 if (typeB->isIntegerTy(64)) return typeB;
198
199 if (typeA->isIntegerTy(32)) return typeA;
200 if (typeB->isIntegerTy(32)) return typeB;
201
202 if (typeA->isIntegerTy(16)) return typeA;
203 if (typeB->isIntegerTy(16)) return typeB;
204
205 if (typeA->isIntegerTy(8)) return typeA;
206 if (typeB->isIntegerTy(8)) return typeB;
207
208 if (typeA->isIntegerTy(1)) return typeA;
209 if (typeB->isIntegerTy(1)) return typeB;
210
211 assert(false && "invalid LLVM type precedence");
212 return nullptr;
213 }
214
224 inline CastFunction
225 llvmArithmeticConversion(const llvm::Type* const sourceType,
226 const llvm::Type* const targetType,
227 const std::string& twine = "")
228 {
229
230 #define BIND_ARITHMETIC_CAST_OP(Function, Twine) \
231 std::bind(&Function, \
232 std::placeholders::_1, \
233 std::placeholders::_2, \
234 std::placeholders::_3, \
235 Twine)
236
237 if (targetType->isDoubleTy()) {
238 if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
239 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
240 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
241 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
242 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
243 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
244 }
245 else if (targetType->isFloatTy()) {
246 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
247 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
248 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
249 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
250 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
251 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
252 }
253 else if (targetType->isIntegerTy(64)) {
254 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
255 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
256 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
257 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
258 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
259 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
260 }
261 else if (targetType->isIntegerTy(32)) {
262 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
263 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
264 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
265 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
266 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
267 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
268 }
269 else if (targetType->isIntegerTy(16)) {
270 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
271 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
272 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
273 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
274 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
275 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
276 }
277 else if (targetType->isIntegerTy(8)) {
278 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
279 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
280 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
281 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
282 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
283 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
284 }
285 else if (targetType->isIntegerTy(1)) {
286 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
287 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
288 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
289 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
290 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
291 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
292 }
293
294 #undef BIND_ARITHMETIC_CAST_OP
295 assert(false && "invalid LLVM type conversion");
296 return CastFunction();
297 }
298
313 inline BinaryFunction
314 llvmBinaryConversion(const llvm::Type* const type,
315 const ast::tokens::OperatorToken& token,
316 const std::string& twine = "")
317 {
318
319 #define BIND_BINARY_OP(Function) \
320 [twine](llvm::IRBuilder<>& B, llvm::Value* L, llvm::Value* R) \
321 -> llvm::Value* { return B.Function(L, R, twine); }
322
323 // NOTE: Binary % and / ops always take sign into account (CreateSDiv vs CreateUDiv, CreateSRem vs CreateURem).
324 // See http://stackoverflow.com/questions/5346160/llvm-irbuildercreateudiv-createsdiv-createexactudiv
325 // a%b in AX is implemented as a floored modulo op and is handled explicitly in binaryExpression
326
327 if (type->isFloatingPointTy()) {
328 assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL ||
329 ast::tokens::operatorType(token) == ast::tokens::BITWISE)
330 && "unable to perform logical or bitwise operation on floating point values");
331
332 if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateFAdd);
333 else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateFSub);
334 else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateFMul);
335 else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateFDiv);
336 else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateFRem); // Note this is NOT a%b in AX.
337 else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateFCmpOEQ);
338 else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateFCmpONE);
339 else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateFCmpOGT);
340 else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateFCmpOLT);
341 else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOGE);
342 else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOLE);
343 assert(false && "unrecognised binary operator");
344 }
345 else if (type->isIntegerTy()) {
346 if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateAdd); // No Unsigned/Signed Wrap
347 else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateSub); // No Unsigned/Signed Wrap
348 else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateMul); // No Unsigned/Signed Wrap
349 else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateSDiv); // IsExact = false - when true, poison value if the reuslt is rounded
350 else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateSRem); // Note this is NOT a%b in AX.
351 else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateICmpEQ);
352 else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateICmpNE);
353 else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateICmpSGT);
354 else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateICmpSLT);
355 else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateICmpSGE);
356 else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateICmpSLE);
357 else if (token == ast::tokens::AND) return BIND_BINARY_OP(CreateAnd);
358 else if (token == ast::tokens::OR) return BIND_BINARY_OP(CreateOr);
359 else if (token == ast::tokens::SHIFTLEFT) return BIND_BINARY_OP(CreateShl); // No Unsigned/Signed Wrap
360 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.
361 else if (token == ast::tokens::BITAND) return BIND_BINARY_OP(CreateAnd);
362 else if (token == ast::tokens::BITOR) return BIND_BINARY_OP(CreateOr);
363 else if (token == ast::tokens::BITXOR) return BIND_BINARY_OP(CreateXor);
364 assert(false && "unrecognised binary operator");
365 }
366
367 #undef BIND_BINARY_OP
368 assert(false && "invalid LLVM type for binary operation");
369 return BinaryFunction();
370 }
371
374 inline bool isValidCast(llvm::Type* from, llvm::Type* to)
375 {
376 assert(from && "llvm Type 'from' is null in isValidCast");
377 assert(to && "llvm Type 'to' is null in isValidCast");
378
379 if ((from->isIntegerTy() || from->isFloatingPointTy()) &&
380 (to->isIntegerTy() || to->isFloatingPointTy())) {
381 return true;
382 }
383 if (from->isArrayTy() && to->isArrayTy()) {
384 llvm::ArrayType* af = llvm::cast<llvm::ArrayType>(from);
385 llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(to);
386 if (af->getArrayNumElements() == at->getArrayNumElements()) {
387 return isValidCast(af->getArrayElementType(),
388 at->getArrayElementType());
389 }
390 }
391 return false;
392 }
393
401 inline llvm::Value*
402 arithmeticConversion(llvm::Value* value,
403 llvm::Type* targetType,
404 llvm::IRBuilder<>& builder)
405 {
406 assert(value && (value->getType()->isIntegerTy() || value->getType()->isFloatingPointTy()) &&
407 "First Value in arithmeticConversion is not a scalar type");
408 assert(targetType && (targetType->isIntegerTy() || targetType->isFloatingPointTy()) &&
409 "Target Type in arithmeticConversion is not a scalar type");
410
411 const llvm::Type* const valueType = value->getType();
412 if (valueType == targetType) return value;
413
414 CastFunction llvmCastFunction = llvmArithmeticConversion(valueType, targetType);
415 return llvmCastFunction(builder, value, targetType);
416 }
417
427 inline llvm::Value*
428 arrayCast(llvm::Value* ptrToArray,
429 llvm::Type* targetElementType,
430 llvm::IRBuilder<>& builder)
431 {
432 assert(targetElementType && (targetElementType->isIntegerTy() ||
433 targetElementType->isFloatingPointTy()) &&
434 "Target element type is not a scalar type");
435 assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
436 "Input to arrayCast is not a pointer type.");
437
438 llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
439 assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
440
441 // getArrayElementType() calls getContainedType(0)
442 llvm::Type* sourceElementType = arrayType->getArrayElementType();
443 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
444 sourceElementType->isFloatingPointTy()) &&
445 "Source element type is not a scalar type");
446
447 if (sourceElementType == targetElementType) return ptrToArray;
448
449 CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
450
451 const size_t elementSize = arrayType->getArrayNumElements();
452 llvm::Value* targetArray =
453 insertStaticAlloca(builder,
454 llvm::ArrayType::get(targetElementType, elementSize));
455
456 for (size_t i = 0; i < elementSize; ++i) {
457 llvm::Value* target = builder.CreateConstGEP2_64(targetArray, 0, i);
458 llvm::Value* source = builder.CreateConstGEP2_64(ptrToArray, 0, i);
459 source = builder.CreateLoad(source);
460 source = llvmCastFunction(builder, source, targetElementType);
461 builder.CreateStore(source, target);
462 }
463
464 return targetArray;
465 }
466
476 inline void
477 arithmeticConversion(std::vector<llvm::Value*>& values,
478 llvm::Type* targetElementType,
479 llvm::IRBuilder<>& builder)
480 {
481 assert(targetElementType && (targetElementType->isIntegerTy() ||
482 targetElementType->isFloatingPointTy()) &&
483 "Target element type is not a scalar type");
484
485 llvm::Type* sourceElementType = values.front()->getType();
486 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
487 sourceElementType->isFloatingPointTy()) &&
488 "Source element type is not a scalar type");
489
490 if (sourceElementType == targetElementType) return;
491
492 CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
493
494 for (llvm::Value*& value : values) {
495 value = llvmCastFunction(builder, value, targetElementType);
496 }
497 }
498
505 inline void
506 arithmeticConversion(std::vector<llvm::Value*>& values,
507 llvm::IRBuilder<>& builder)
508 {
509 llvm::Type* typeCast = LLVMType<bool>::get(builder.getContext());
510 for (llvm::Value*& value : values) {
511 llvm::Type* type = value->getType();
512 if (type->isIntegerTy() || type->isFloatingPointTy()) {
513 typeCast = typePrecedence(typeCast, type);
514 }
515 }
516
517 arithmeticConversion(values, typeCast, builder);
518 }
519
529 inline void
530 arithmeticConversion(llvm::Value*& valueA,
531 llvm::Value*& valueB,
532 llvm::IRBuilder<>& builder)
533 {
534 llvm::Type* type = typePrecedence(valueA->getType(), valueB->getType());
535 valueA = arithmeticConversion(valueA, type, builder);
536 valueB = arithmeticConversion(valueB, type, builder);
537 }
538
544 inline llvm::Value*
545 boolComparison(llvm::Value* value,
546 llvm::IRBuilder<>& builder)
547 {
548 llvm::Type* type = value->getType();
549
550 if (type->isFloatingPointTy()) return builder.CreateFCmpONE(value, llvm::ConstantFP::get(type, 0.0));
551 else if (type->isIntegerTy(1)) return builder.CreateICmpNE(value, llvm::ConstantInt::get(type, 0));
552 else if (type->isIntegerTy()) return builder.CreateICmpNE(value, llvm::ConstantInt::getSigned(type, 0));
553 assert(false && "Invalid type for bool conversion");
554 return nullptr;
555 }
556
565 inline llvm::Value*
566 binaryOperator(llvm::Value* lhs, llvm::Value* rhs,
567 const ast::tokens::OperatorToken& token,
568 llvm::IRBuilder<>& builder)
569 {
570 llvm::Type* lhsType = lhs->getType();
571 assert(lhsType == rhs->getType() ||
572 (token == ast::tokens::SHIFTLEFT ||
573 token == ast::tokens::SHIFTRIGHT));
574
575 const ast::tokens::OperatorType opType = ast::tokens::operatorType(token);
576
577 if (opType == ast::tokens::LOGICAL) {
578 lhs = boolComparison(lhs, builder);
579 rhs = boolComparison(rhs, builder);
580 lhsType = lhs->getType(); // now bool type
581 }
582
583 const BinaryFunction llvmBinaryFunction = llvmBinaryConversion(lhsType, token);
584 return llvmBinaryFunction(builder, lhs, rhs);
585 }
586
594 inline llvm::Value*
595 arrayIndexUnpack(llvm::Value* ptrToArray,
596 const int16_t index,
597 llvm::IRBuilder<>& builder)
598 {
599 return builder.CreateConstGEP2_64(ptrToArray, 0, index);
600 }
601
612 inline void
613 arrayUnpack(llvm::Value* ptrToArray,
614 std::vector<llvm::Value*>& values,
615 llvm::IRBuilder<>& builder,
616 const bool loadElements = false)
617 {
618 const size_t elements =
619 ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
620
621 values.reserve(elements);
622 for (size_t i = 0; i < elements; ++i) {
623 llvm::Value* value = builder.CreateConstGEP2_64(ptrToArray, 0, i);
624 if (loadElements) value = builder.CreateLoad(value);
625 values.push_back(value);
626 }
627 }
628
639 inline void
640 array3Unpack(llvm::Value* ptrToArray,
641 llvm::Value*& value1,
642 llvm::Value*& value2,
643 llvm::Value*& value3,
644 llvm::IRBuilder<>& builder)
645 {
646 assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
647 "Input to array3Unpack is not a pointer type.");
648
649 value1 = builder.CreateConstGEP2_64(ptrToArray, 0, 0);
650 value2 = builder.CreateConstGEP2_64(ptrToArray, 0, 1);
651 value3 = builder.CreateConstGEP2_64(ptrToArray, 0, 2);
652 }
653
664 inline llvm::Value*
665 array3Pack(llvm::Value* value1,
666 llvm::Value* value2,
667 llvm::Value* value3,
668 llvm::IRBuilder<>& builder)
669 {
670 llvm::Type* type = typePrecedence(value1->getType(), value2->getType());
671 type = typePrecedence(type, value3->getType());
672
673 value1 = arithmeticConversion(value1, type, builder);
674 value2 = arithmeticConversion(value2, type, builder);
675 value3 = arithmeticConversion(value3, type, builder);
676
677 llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
678 llvm::Value* vector = insertStaticAlloca(builder, vectorType);
679
680 llvm::Value* e1 = builder.CreateConstGEP2_64(vector, 0, 0);
681 llvm::Value* e2 = builder.CreateConstGEP2_64(vector, 0, 1);
682 llvm::Value* e3 = builder.CreateConstGEP2_64(vector, 0, 2);
683
684 builder.CreateStore(value1, e1);
685 builder.CreateStore(value2, e2);
686 builder.CreateStore(value3, e3);
687
688 return vector;
689 }
690
699 inline llvm::Value*
700 arrayPack(llvm::Value* value,
701 llvm::IRBuilder<>& builder,
702 const size_t size = 3)
703 {
704 assert(value && (value->getType()->isIntegerTy() ||
705 value->getType()->isFloatingPointTy()) &&
706 "value type is not a scalar type");
707
708 llvm::Type* type = value->getType();
709 llvm::Value* array =
710 insertStaticAlloca(builder,
711 llvm::ArrayType::get(type, size));
712
713 for (size_t i = 0; i < size; ++i) {
714 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
715 builder.CreateStore(value, element);
716 }
717
718 return array;
719 }
720
727 inline llvm::Value*
728 arrayPack(const std::vector<llvm::Value*>& values,
729 llvm::IRBuilder<>& builder)
730 {
731 llvm::Type* type = values.front()->getType();
732 llvm::Value* array = insertStaticAlloca(builder,
733 llvm::ArrayType::get(type, values.size()));
734
735 size_t idx = 0;
736 for (llvm::Value* const& value : values) {
737 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, idx++);
738 builder.CreateStore(value, element);
739 }
740
741 return array;
742 }
743
753 inline llvm::Value*
754 arrayPackCast(std::vector<llvm::Value*>& values,
755 llvm::IRBuilder<>& builder)
756 {
757 // get the highest order type present
758
759 llvm::Type* type = LLVMType<bool>::get(builder.getContext());
760 for (llvm::Value* const& value : values) {
761 type = typePrecedence(type, value->getType());
762 }
763
764 // convert all to this type
765
766 for (llvm::Value*& value : values) {
767 value = arithmeticConversion(value, type, builder);
768 }
769
770 return arrayPack(values, builder);
771 }
772
773 inline llvm::Value*
774 scalarToMatrix(llvm::Value* scalar,
775 llvm::IRBuilder<>& builder,
776 const size_t dim = 3)
777 {
778 assert(scalar && (scalar->getType()->isIntegerTy() ||
779 scalar->getType()->isFloatingPointTy()) &&
780 "value type is not a scalar type");
781
782 llvm::Type* type = scalar->getType();
783 llvm::Value* array =
784 insertStaticAlloca(builder,
785 llvm::ArrayType::get(type, dim*dim));
786
787 llvm::Value* zero = llvmConstant(0, type);
788 for (size_t i = 0; i < dim*dim; ++i) {
789 llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
790 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
791 builder.CreateStore(m, element);
792 }
793
794 return array;
795 }
796
797 } // namespace codegen
798 } // namespace ax
799 } // namespace OPENVDB_VERSION_NAME
800 } // namespace openvdb
801
802 #endif // OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
803
Types.h
Consolidated llvm types for most supported types.
BITOR
@ BITOR
Definition: axparser.h:128
DIVIDE
@ DIVIDE
Definition: axparser.h:142
LESSTHANOREQUAL
@ LESSTHANOREQUAL
Definition: axparser.h:136
SHIFTRIGHT
@ SHIFTRIGHT
Definition: axparser.h:138
MORETHANOREQUAL
@ MORETHANOREQUAL
Definition: axparser.h:135
EQUALSEQUALS
@ EQUALSEQUALS
Definition: axparser.h:131
BITXOR
@ BITXOR
Definition: axparser.h:129
BITAND
@ BITAND
Definition: axparser.h:130
AND
@ AND
Definition: axparser.h:127
PLUS
@ PLUS
Definition: axparser.h:139
LESSTHAN
@ LESSTHAN
Definition: axparser.h:134
OR
@ OR
Definition: axparser.h:126
MODULO
@ MODULO
Definition: axparser.h:143
MORETHAN
@ MORETHAN
Definition: axparser.h:133
NOTEQUALS
@ NOTEQUALS
Definition: axparser.h:132
MULTIPLY
@ MULTIPLY
Definition: axparser.h:141
SHIFTLEFT
@ SHIFTLEFT
Definition: axparser.h:137
MINUS
@ MINUS
Definition: axparser.h:140
openvdb::v8_1::ax::ast::tokens::OperatorToken
OperatorToken
Definition: Tokens.h:151
openvdb::v8_1::ax::ast::tokens::operatorType
OperatorType operatorType(const OperatorToken token)
Definition: Tokens.h:210
openvdb::v8_1::ax::ast::tokens::OperatorType
OperatorType
Definition: Tokens.h:201
openvdb::v8_1::ax::ast::tokens::LOGICAL
@ LOGICAL
Definition: Tokens.h:203
openvdb::v8_1::ax::ast::tokens::BITWISE
@ BITWISE
Definition: Tokens.h:205
openvdb::v8_1::ax::codegen::extractArgument
llvm::Argument * extractArgument(llvm::Function *F, const std::string &name)
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:163
openvdb::v8_1::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:774
openvdb::v8_1::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::v8_1::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:530
openvdb::v8_1::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:545
openvdb::v8_1::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:728
openvdb::v8_1::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:595
openvdb::v8_1::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::v8_1::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:428
openvdb::v8_1::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:374
openvdb::v8_1::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:225
openvdb::v8_1::ax::codegen::CastFunction
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Type *)> CastFunction
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:44
openvdb::v8_1::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::v8_1::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:566
openvdb::v8_1::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::v8_1::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:179
openvdb::v8_1::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:640
openvdb::v8_1::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:613
openvdb::v8_1::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:665
openvdb::v8_1::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:754
openvdb::v8_1::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
openvdb::v8_1::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:314
openvdb::v8_1::ax::codegen::BinaryFunction
std::function< llvm::Value *(llvm::IRBuilder<> &, llvm::Value *, llvm::Value *)> BinaryFunction
Definition: openvdb_ax/openvdb_ax/codegen/Utils.h:47
openvdb::v8_1::ax::codegen::llvmConstant
llvm::Constant * llvmConstant(const T t, llvm::Type *type)
Returns an llvm Constant holding a scalar value.
Definition: ax/openvdb_ax/codegen/Types.h:297
openvdb
Definition: openvdb/Exceptions.h:13
BIND_ARITHMETIC_CAST_OP
#define BIND_ARITHMETIC_CAST_OP(Function, Twine)
BIND_BINARY_OP
#define BIND_BINARY_OP(Function)
openvdb::v8_1::ax::codegen::LLVMType
LLVM type mapping from pod types.
Definition: ax/openvdb_ax/codegen/Types.h:55
OPENVDB_VERSION_NAME
#define OPENVDB_VERSION_NAME
The version namespace name for this library version.
Definition: version.h.in:116
OPENVDB_USE_VERSION_NAMESPACE
#define OPENVDB_USE_VERSION_NAMESPACE
Definition: version.h.in:178