OpenVDB 10.0.1
Loading...
Searching...
No Matches
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
33namespace openvdb {
35namespace OPENVDB_VERSION_NAME {
36
37namespace ax {
38namespace codegen {
39
40/// @note Function definitions for some types returned from automatic token to
41/// llvm IR operations. See llvmArithmeticConversion and llvmBianryConversion
42
43using CastFunction = std::function<llvm::Value*
44 (llvm::IRBuilder<>&, llvm::Value*, llvm::Type*)>;
45
46using 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.
54inline 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.
66inline 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.
81inline 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.
97inline 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///
117inline void
118valuesToTypes(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///
132inline void
133llvmTypeToString(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///
146inline llvm::Type*
147getBaseContainedType(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///
165template <typename ValueT>
166inline llvm::Value*
167llvmPointerFromAddress(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
185inline llvm::Value*
186insertStaticAlloca(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
217inline llvm::Argument*
218extractArgument(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
225inline llvm::Argument*
226extractArgument(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///
241inline llvm::Type*
242typePrecedence(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
287inline CastFunction
288llvmArithmeticConversion(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
392inline BinaryFunction
393llvmBinaryConversion(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 ||
408 ast::tokens::operatorType(token) == ast::tokens::BITWISE)
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'.
453inline 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
479inline llvm::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///
505inline llvm::Value*
506arrayCast(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
553inline void
554arithmeticConversion(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
581inline void
582arithmeticConversion(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
604inline void
605arithmeticConversion(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///
619inline llvm::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
640inline llvm::Value*
641binaryOperator(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
650 const ast::tokens::OperatorType opType = ast::tokens::operatorType(token);
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///
669inline llvm::Value*
670arrayIndexUnpack(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///
687inline void
688arrayUnpack(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///
714inline void
715array3Unpack(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///
739inline llvm::Value*
740array3Pack(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///
774inline llvm::Value*
775arrayPack(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///
802inline llvm::Value*
803arrayPack(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///
828inline llvm::Value*
829arrayPackCast(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
848inline llvm::Value*
849scalarToMatrix(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
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