GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/codegen/Utils.h
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 217 245 88.6%
Functions: 30 30 100.0%
Branches: 343 680 50.4%

Line Branch Exec Source
1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3
4 /// @file codegen/Utils.h
5 ///
6 /// @authors Nick Avramoussis
7 ///
8 /// @brief Utility code generation methods for performing various llvm
9 /// operations
10 ///
11
12 #ifndef OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
13 #define OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
14
15 #include "Types.h"
16
17 #include "../ast/Tokens.h"
18 #include "../Exceptions.h"
19
20 #include <openvdb/version.h>
21
22 #include <llvm/IR/IRBuilder.h>
23 #include <llvm/IR/LLVMContext.h>
24
25 // Note: As of LLVM 5.0, the llvm::Type::dump() method isn't being
26 // picked up correctly by the linker. dump() is internally implemented
27 // using Type::print(llvm::errs()) which is being used in place. See:
28 //
29 // https://stackoverflow.com/questions/43723127/llvm-5-0-makefile-undefined-reference-fail
30 //
31 #include <llvm/Support/raw_ostream.h> // llvm::errs()
32
33 namespace openvdb {
34 OPENVDB_USE_VERSION_NAMESPACE
35 namespace OPENVDB_VERSION_NAME {
36
37 namespace ax {
38 namespace codegen {
39
40 /// @note Function definitions for some types returned from automatic token to
41 /// llvm IR operations. See llvmArithmeticConversion and llvmBianryConversion
42
43 using CastFunction = std::function<llvm::Value*
44 (llvm::IRBuilder<>&, llvm::Value*, llvm::Type*)>;
45
46 using BinaryFunction = std::function<llvm::Value*
47 (llvm::IRBuilder<>&, llvm::Value*, llvm::Value*)>;
48
49 /// @brief Populate a vector of llvm Types from a vector of llvm values
50 ///
51 /// @param values A vector of llvm values to retrieve types from
52 /// @param types A vector of llvm types to populate
53 ///
54 inline void
55 43751 valuesToTypes(const std::vector<llvm::Value*>& values,
56 std::vector<llvm::Type*>& types)
57 {
58 43751 types.reserve(values.size());
59
2/2
✓ Branch 0 taken 136905 times.
✓ Branch 1 taken 43751 times.
180656 for (const auto& v : values) {
60 136905 types.emplace_back(v->getType());
61 }
62 43751 }
63
64 /// @brief Prints an llvm type to a std string
65 ///
66 /// @param type The llvm type to convert
67 /// @param str The string to store the type info to
68 ///
69 inline void
70
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 llvmTypeToString(const llvm::Type* const type, std::string& str)
71 {
72 2 llvm::raw_string_ostream os(str);
73
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 type->print(os);
74 os.flush();
75 2 }
76
77 /// @brief Return the base llvm value which is being pointed to through
78 /// any number of layered pointers.
79 /// @note This function does not check for cyclical pointer dependencies
80 ///
81 /// @param type A llvm pointer type to traverse
82 ///
83 inline llvm::Type*
84 7571 getBaseContainedType(llvm::Type* const type)
85 {
86 llvm::Type* elementType = type;
87
2/2
✓ Branch 0 taken 7571 times.
✓ Branch 1 taken 7571 times.
15142 while (elementType->isPointerTy()) {
88 elementType = elementType->getContainedType(0);
89 }
90 7571 return elementType;
91 }
92
93 /// @brief Return an llvm value representing a pointer to the provided ptr builtin
94 /// ValueT.
95 /// @note This is probably not a suitable solution for anything other than POD
96 /// types and should be used with caution.
97 ///
98 /// @param ptr A pointer to a type of ValueT whose address will be computed and
99 /// returned
100 /// @param builder The current llvm IRBuilder
101 ///
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
113 /// @brief Insert a stack allocation at the beginning of the current function
114 /// of the provided type and size. The IRBuilder's insertion point must
115 /// be set to a BasicBlock with a valid Function parent.
116 /// @note If a size is provided, the size must not depend on any other
117 /// instructions. If it does, invalid LLVM IR will bb generated.
118 ///
119 /// @param B The IRBuilder
120 /// @param type The type to allocate
121 /// @param size Optional count of allocations. If nullptr, runs a single allocation
122 inline llvm::Value*
123 35450 insertStaticAlloca(llvm::IRBuilder<>& B,
124 llvm::Type* type,
125 llvm::Value* size = nullptr)
126 {
127 35450 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
2/4
✓ Branch 0 taken 35450 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 35450 times.
35450 assert(parent && !parent->empty());
131
1/2
✓ Branch 0 taken 35450 times.
✗ Branch 1 not taken.
35450 auto IP = B.saveIP();
132 llvm::BasicBlock& block = parent->front();
133
2/2
✓ Branch 0 taken 3570 times.
✓ Branch 1 taken 31880 times.
35450 if (block.empty()) B.SetInsertPoint(&block);
134
1/2
✓ Branch 0 taken 31880 times.
✗ Branch 1 not taken.
63760 else B.SetInsertPoint(&(block.front()));
135 35450 llvm::Value* result = B.CreateAlloca(type, size);
136
137 /// @note Strings need to be initialised correctly when they are
138 /// created. We alloc them at the start of the function but
139 /// strings in branches may not ever be set to anything. If
140 /// we don't init these correctly, the clearup frees will
141 /// try and free uninitialised memory
142
2/2
✓ Branch 0 taken 1114 times.
✓ Branch 1 taken 34336 times.
35450 if (type == strtype) {
143 1114 llvm::Value* cptr = B.CreateStructGEP(strtype, result, 0); // char**
144 1114 llvm::Value* sso = B.CreateStructGEP(strtype, result, 1); // char[]*
145 1114 llvm::Value* sso_load = B.CreateConstGEP2_64(sso, 0 ,0); // char*
146 1114 llvm::Value* len = B.CreateStructGEP(strtype, result, 2);
147 1114 B.CreateStore(sso_load, cptr); // this->ptr = this->SSO;
148 1114 B.CreateStore(B.getInt64(0), len);
149 }
150 35450 B.restoreIP(IP);
151 35450 return result;
152 }
153
154 inline llvm::Argument*
155 28 extractArgument(llvm::Function* F, const size_t idx)
156 {
157
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (!F) return nullptr;
158
1/2
✓ Branch 0 taken 28 times.
✗ Branch 1 not taken.
28 if (idx >= F->arg_size()) return nullptr;
159
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 28 times.
28 return llvm::cast<llvm::Argument>(F->arg_begin() + idx);
160 }
161
162 inline llvm::Argument*
163 54919 extractArgument(llvm::Function* F, const std::string& name)
164 {
165
1/2
✓ Branch 0 taken 54919 times.
✗ Branch 1 not taken.
54919 if (!F) return nullptr;
166
1/2
✓ Branch 0 taken 317218 times.
✗ Branch 1 not taken.
579517 for (auto iter = F->arg_begin(); iter != F->arg_end(); ++iter) {
167 llvm::Argument* arg = llvm::cast<llvm::Argument>(iter);
168
2/2
✓ Branch 1 taken 262299 times.
✓ Branch 2 taken 54919 times.
317218 if (arg->getName() == name) return arg;
169 }
170 return nullptr;
171 }
172
173 /// @brief Returns the highest order type from two LLVM Scalar types
174 ///
175 /// @param typeA The first scalar llvm type
176 /// @param typeB The second scalar llvm type
177 ///
178 inline llvm::Type*
179 28037 typePrecedence(llvm::Type* const typeA,
180 llvm::Type* const typeB)
181 {
182
3/4
✓ Branch 0 taken 28037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 18361 times.
✓ Branch 3 taken 9676 times.
28037 assert(typeA && (typeA->isIntegerTy() || typeA->isFloatingPointTy()) &&
183 "First Type in typePrecedence is not a scalar type");
184
3/4
✓ Branch 0 taken 28037 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 21134 times.
✓ Branch 3 taken 6903 times.
28037 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
2/2
✓ Branch 0 taken 19089 times.
✓ Branch 1 taken 8948 times.
28037 if (typeA->isDoubleTy()) return typeA;
191
2/2
✓ Branch 0 taken 17236 times.
✓ Branch 1 taken 1853 times.
19089 if (typeB->isDoubleTy()) return typeB;
192
193
2/2
✓ Branch 0 taken 8020 times.
✓ Branch 1 taken 9216 times.
17236 if (typeA->isFloatTy()) return typeA;
194
2/2
✓ Branch 0 taken 6462 times.
✓ Branch 1 taken 1558 times.
8020 if (typeB->isFloatTy()) return typeB;
195
196
2/2
✓ Branch 1 taken 6230 times.
✓ Branch 2 taken 232 times.
6462 if (typeA->isIntegerTy(64)) return typeA;
197
2/2
✓ Branch 1 taken 6206 times.
✓ Branch 2 taken 24 times.
6230 if (typeB->isIntegerTy(64)) return typeB;
198
199
2/2
✓ Branch 1 taken 1355 times.
✓ Branch 2 taken 4851 times.
6206 if (typeA->isIntegerTy(32)) return typeA;
200
2/2
✓ Branch 1 taken 224 times.
✓ Branch 2 taken 1131 times.
1355 if (typeB->isIntegerTy(32)) return typeB;
201
202
2/2
✓ Branch 1 taken 216 times.
✓ Branch 2 taken 8 times.
224 if (typeA->isIntegerTy(16)) return typeA;
203
1/2
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
216 if (typeB->isIntegerTy(16)) return typeB;
204
205
1/2
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
216 if (typeA->isIntegerTy(8)) return typeA;
206
1/2
✓ Branch 1 taken 216 times.
✗ Branch 2 not taken.
216 if (typeB->isIntegerTy(8)) return typeB;
207
208
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 216 times.
216 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
215 /// @brief Returns a CastFunction which represents the corresponding instruction
216 /// to convert a source llvm Type to a target llvm Type. If the conversion
217 /// is unsupported, throws an error.
218 /// @warning This assumes any integer types are signed.
219 /// @param sourceType The source type to cast
220 /// @param targetType The target type to cast to
221 /// @param twine An optional string description of the cast function. This can
222 /// be used for for more verbose llvm information on IR compilation
223 /// failure
224 inline CastFunction
225
2/2
✓ Branch 0 taken 3413 times.
✓ Branch 1 taken 10673 times.
14086 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
2/2
✓ Branch 0 taken 3413 times.
✓ Branch 1 taken 10673 times.
14086 if (targetType->isDoubleTy()) {
238
3/4
✓ Branch 0 taken 2592 times.
✓ Branch 1 taken 821 times.
✓ Branch 4 taken 2592 times.
✗ Branch 5 not taken.
6005 if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
239
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 821 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
821 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
240
3/4
✓ Branch 1 taken 52 times.
✓ Branch 2 taken 769 times.
✓ Branch 5 taken 52 times.
✗ Branch 6 not taken.
873 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
241
3/4
✓ Branch 1 taken 709 times.
✓ Branch 2 taken 60 times.
✓ Branch 5 taken 709 times.
✗ Branch 6 not taken.
1478 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
242
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
60 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
243
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 60 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
60 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
244
2/4
✓ Branch 1 taken 60 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 60 times.
✗ Branch 6 not taken.
120 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
245 }
246
2/2
✓ Branch 0 taken 1699 times.
✓ Branch 1 taken 8974 times.
10673 else if (targetType->isFloatTy()) {
247
3/4
✓ Branch 0 taken 609 times.
✓ Branch 1 taken 1090 times.
✓ Branch 4 taken 609 times.
✗ Branch 5 not taken.
2308 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
248
3/4
✓ Branch 0 taken 349 times.
✓ Branch 1 taken 741 times.
✓ Branch 4 taken 349 times.
✗ Branch 5 not taken.
1439 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPExt, twine);
249
3/4
✓ Branch 1 taken 53 times.
✓ Branch 2 taken 688 times.
✓ Branch 5 taken 53 times.
✗ Branch 6 not taken.
794 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
250
3/4
✓ Branch 1 taken 627 times.
✓ Branch 2 taken 61 times.
✓ Branch 5 taken 627 times.
✗ Branch 6 not taken.
1315 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
251
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
61 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
252
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 61 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
61 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
253
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
122 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
254 }
255
2/2
✓ Branch 0 taken 340 times.
✓ Branch 1 taken 8634 times.
8974 else if (targetType->isHalfTy()) {
256
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 340 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
340 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
257
2/4
✓ Branch 0 taken 340 times.
✗ Branch 1 not taken.
✓ Branch 4 taken 340 times.
✗ Branch 5 not taken.
680 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPTrunc, twine);
258 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
259 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
260 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
261 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSIToFP, twine);
262 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateUIToFP, twine);
263 }
264
2/2
✓ Branch 1 taken 886 times.
✓ Branch 2 taken 7748 times.
8634 else if (targetType->isIntegerTy(64)) {
265
3/4
✓ Branch 0 taken 20 times.
✓ Branch 1 taken 866 times.
✓ Branch 4 taken 20 times.
✗ Branch 5 not taken.
906 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
266
3/4
✓ Branch 0 taken 9 times.
✓ Branch 1 taken 857 times.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
875 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
267
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 857 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
857 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
268
3/4
✓ Branch 1 taken 840 times.
✓ Branch 2 taken 17 times.
✓ Branch 5 taken 840 times.
✗ Branch 6 not taken.
1697 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
269
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
17 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
270
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 17 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
17 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
271
2/4
✓ Branch 1 taken 17 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 17 times.
✗ Branch 6 not taken.
34 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
272 }
273
2/2
✓ Branch 1 taken 7608 times.
✓ Branch 2 taken 140 times.
7748 else if (targetType->isIntegerTy(32)) {
274
3/4
✓ Branch 0 taken 97 times.
✓ Branch 1 taken 7511 times.
✓ Branch 4 taken 97 times.
✗ Branch 5 not taken.
7705 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
275
3/4
✓ Branch 0 taken 139 times.
✓ Branch 1 taken 7372 times.
✓ Branch 4 taken 139 times.
✗ Branch 5 not taken.
7650 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
276
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 7372 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
7372 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
277
3/4
✓ Branch 1 taken 5121 times.
✓ Branch 2 taken 2251 times.
✓ Branch 5 taken 5121 times.
✗ Branch 6 not taken.
12493 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
278
3/4
✓ Branch 1 taken 4 times.
✓ Branch 2 taken 2247 times.
✓ Branch 5 taken 4 times.
✗ Branch 6 not taken.
2255 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
279
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 2247 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
2247 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
280
2/4
✓ Branch 1 taken 2247 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2247 times.
✗ Branch 6 not taken.
4494 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
281 }
282
1/2
✓ Branch 1 taken 140 times.
✗ Branch 2 not taken.
140 else if (targetType->isIntegerTy(16)) {
283
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
140 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
284
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
140 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
285
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 140 times.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
140 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
286
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 140 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
140 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
287
3/4
✓ Branch 1 taken 132 times.
✓ Branch 2 taken 8 times.
✓ Branch 5 taken 132 times.
✗ Branch 6 not taken.
272 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
288
1/4
✗ Branch 1 not taken.
✓ Branch 2 taken 8 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
8 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateSExt, twine);
289
2/4
✓ Branch 1 taken 8 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 8 times.
✗ Branch 6 not taken.
16 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
290 }
291 else if (targetType->isIntegerTy(8)) {
292 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
293 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
294 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToSI, twine);
295 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
296 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
297 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
298 else if (sourceType->isIntegerTy(1)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateZExt, twine);
299 }
300 else if (targetType->isIntegerTy(1)) {
301 if (sourceType->isDoubleTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
302 else if (sourceType->isFloatTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
303 else if (sourceType->isHalfTy()) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateFPToUI, twine);
304 else if (sourceType->isIntegerTy(64)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
305 else if (sourceType->isIntegerTy(32)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
306 else if (sourceType->isIntegerTy(16)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
307 else if (sourceType->isIntegerTy(8)) return BIND_ARITHMETIC_CAST_OP(llvm::IRBuilder<>::CreateTrunc, twine);
308 }
309
310 #undef BIND_ARITHMETIC_CAST_OP
311 assert(false && "invalid LLVM type conversion");
312 return CastFunction();
313 }
314
315 /// @brief Returns a BinaryFunction representing the corresponding instruction to
316 /// perform on two scalar values, relative to a provided operator token. Note that
317 /// not all operations are supported on floating point types! If the token is not
318 /// supported, or the llvm type is not a scalar type, throws an error.
319 /// @note Various default arguments are bound to provide a simple function call
320 /// signature. For floating point operations, this includes a null pointer to
321 /// the optional metadata node. For integer operations, this includes disabling
322 /// all overflow/rounding optimisations
323 ///
324 /// @param type The type defining the precision of the binary operation
325 /// @param token The token used to create the relative binary operation
326 /// @param twine An optional string description of the binary function. This can
327 /// be used for for more verbose llvm information on IR compilation
328 /// failure
329 inline BinaryFunction
330
1/2
✓ Branch 0 taken 32850 times.
✗ Branch 1 not taken.
32850 llvmBinaryConversion(const llvm::Type* const type,
331 const ast::tokens::OperatorToken& token,
332 const std::string& twine = "")
333 {
334
335 #define BIND_BINARY_OP(Function) \
336 [twine](llvm::IRBuilder<>& B, llvm::Value* L, llvm::Value* R) \
337 -> llvm::Value* { return B.Function(L, R, twine); }
338
339 // NOTE: Binary % and / ops always take sign into account (CreateSDiv vs CreateUDiv, CreateSRem vs CreateURem).
340 // See http://stackoverflow.com/questions/5346160/llvm-irbuildercreateudiv-createsdiv-createexactudiv
341 // a%b in AX is implemented as a floored modulo op and is handled explicitly in binaryExpression
342
343 if (type->isFloatingPointTy()) {
344
2/2
✓ Branch 0 taken 4158 times.
✓ Branch 1 taken 11953 times.
16111 assert(!(ast::tokens::operatorType(token) == ast::tokens::LOGICAL ||
345 ast::tokens::operatorType(token) == ast::tokens::BITWISE)
346 && "unable to perform logical or bitwise operation on floating point values");
347
348
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 4786 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 4786 times.
✓ Branch 10 taken 11325 times.
✓ Branch 13 taken 4786 times.
✗ Branch 14 not taken.
35255 if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateFAdd);
349
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1349 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1349 times.
✓ Branch 10 taken 9976 times.
✓ Branch 13 taken 1349 times.
✗ Branch 14 not taken.
16721 else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateFSub);
350
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 5114 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 5114 times.
✓ Branch 10 taken 4862 times.
✓ Branch 13 taken 5114 times.
✗ Branch 14 not taken.
30432 else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateFMul);
351
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 588 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 588 times.
✓ Branch 10 taken 4274 times.
✓ Branch 13 taken 588 times.
✗ Branch 14 not taken.
7214 else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateFDiv);
352
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 116 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 116 times.
✓ Branch 10 taken 4158 times.
✓ Branch 13 taken 116 times.
✗ Branch 14 not taken.
4738 else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateFRem); // Note this is NOT a%b in AX.
353
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 884 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 884 times.
✓ Branch 8 taken 3274 times.
✓ Branch 11 taken 884 times.
✗ Branch 12 not taken.
7694 else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateFCmpOEQ);
354
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 904 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 904 times.
✓ Branch 8 taken 2370 times.
✓ Branch 11 taken 904 times.
✗ Branch 12 not taken.
6890 else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateFCmpONE);
355
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1136 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1136 times.
✓ Branch 8 taken 1234 times.
✓ Branch 11 taken 1136 times.
✗ Branch 12 not taken.
6914 else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateFCmpOGT);
356
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 300 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 300 times.
✓ Branch 8 taken 934 times.
✓ Branch 11 taken 300 times.
✗ Branch 12 not taken.
2434 else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateFCmpOLT);
357
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 40 times.
✓ Branch 8 taken 894 times.
✓ Branch 11 taken 40 times.
✗ Branch 12 not taken.
1094 else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOGE);
358
3/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 894 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 894 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 894 times.
✗ Branch 12 not taken.
4470 else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateFCmpOLE);
359 assert(false && "unrecognised binary operator");
360 }
361
1/2
✓ Branch 0 taken 16739 times.
✗ Branch 1 not taken.
16739 else if (type->isIntegerTy()) {
362
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1158 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1158 times.
✓ Branch 8 taken 15581 times.
✓ Branch 11 taken 1158 times.
✗ Branch 12 not taken.
21371 if (token == ast::tokens::PLUS) return BIND_BINARY_OP(CreateAdd); // No Unsigned/Signed Wrap
363
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 960 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 960 times.
✓ Branch 8 taken 14621 times.
✓ Branch 11 taken 960 times.
✗ Branch 12 not taken.
19421 else if (token == ast::tokens::MINUS) return BIND_BINARY_OP(CreateSub); // No Unsigned/Signed Wrap
364
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 684 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 684 times.
✓ Branch 8 taken 13937 times.
✓ Branch 11 taken 684 times.
✗ Branch 12 not taken.
17357 else if (token == ast::tokens::MULTIPLY) return BIND_BINARY_OP(CreateMul); // No Unsigned/Signed Wrap
365
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 148 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 148 times.
✓ Branch 10 taken 13789 times.
✓ Branch 13 taken 148 times.
✗ Branch 14 not taken.
14529 else if (token == ast::tokens::DIVIDE) return BIND_BINARY_OP(CreateSDiv); // IsExact = false - when true, poison value if the reuslt is rounded
366
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 76 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 76 times.
✓ Branch 10 taken 13713 times.
✓ Branch 13 taken 76 times.
✗ Branch 14 not taken.
14093 else if (token == ast::tokens::MODULO) return BIND_BINARY_OP(CreateSRem); // Note this is NOT a%b in AX.
367
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1023 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1023 times.
✓ Branch 9 taken 12690 times.
✓ Branch 12 taken 1023 times.
✗ Branch 13 not taken.
17805 else if (token == ast::tokens::EQUALSEQUALS) return BIND_BINARY_OP(CreateICmpEQ);
368
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1959 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 1959 times.
✓ Branch 9 taken 10731 times.
✓ Branch 12 taken 1959 times.
✗ Branch 13 not taken.
20526 else if (token == ast::tokens::NOTEQUALS) return BIND_BINARY_OP(CreateICmpNE);
369
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 192 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 192 times.
✓ Branch 9 taken 10539 times.
✓ Branch 12 taken 192 times.
✗ Branch 13 not taken.
11499 else if (token == ast::tokens::MORETHAN) return BIND_BINARY_OP(CreateICmpSGT);
370
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 324 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 324 times.
✓ Branch 9 taken 10215 times.
✓ Branch 12 taken 324 times.
✗ Branch 13 not taken.
11835 else if (token == ast::tokens::LESSTHAN) return BIND_BINARY_OP(CreateICmpSLT);
371
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 10167 times.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
10407 else if (token == ast::tokens::MORETHANOREQUAL) return BIND_BINARY_OP(CreateICmpSGE);
372
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 48 times.
✓ Branch 9 taken 10119 times.
✓ Branch 12 taken 48 times.
✗ Branch 13 not taken.
10359 else if (token == ast::tokens::LESSTHANOREQUAL) return BIND_BINARY_OP(CreateICmpSLE);
373
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1088 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1088 times.
✓ Branch 10 taken 9031 times.
✓ Branch 13 taken 1088 times.
✗ Branch 14 not taken.
14471 else if (token == ast::tokens::AND) return BIND_BINARY_OP(CreateAnd);
374
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 2715 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 2715 times.
✓ Branch 10 taken 6316 times.
✓ Branch 13 taken 2715 times.
✗ Branch 14 not taken.
19891 else if (token == ast::tokens::OR) return BIND_BINARY_OP(CreateOr);
375
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1563 times.
✗ Branch 6 not taken.
✓ Branch 7 taken 1563 times.
✓ Branch 8 taken 4753 times.
✓ Branch 11 taken 1563 times.
✗ Branch 12 not taken.
12568 else if (token == ast::tokens::SHIFTLEFT) return BIND_BINARY_OP(CreateShl); // No Unsigned/Signed Wrap
376
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1587 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 1587 times.
✓ Branch 10 taken 3166 times.
✓ Branch 13 taken 1587 times.
✗ Branch 14 not taken.
11101 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.
377
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 3078 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 3078 times.
✓ Branch 10 taken 88 times.
✓ Branch 13 taken 3078 times.
✗ Branch 14 not taken.
15478 else if (token == ast::tokens::BITAND) return BIND_BINARY_OP(CreateAnd);
378
4/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 40 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 40 times.
✓ Branch 10 taken 48 times.
✓ Branch 13 taken 40 times.
✗ Branch 14 not taken.
248 else if (token == ast::tokens::BITOR) return BIND_BINARY_OP(CreateOr);
379
3/8
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 48 times.
✗ Branch 6 not taken.
✓ Branch 9 taken 48 times.
✗ Branch 10 not taken.
✓ Branch 13 taken 48 times.
✗ Branch 14 not taken.
240 else if (token == ast::tokens::BITXOR) return BIND_BINARY_OP(CreateXor);
380 assert(false && "unrecognised binary operator");
381 }
382
383 #undef BIND_BINARY_OP
384 assert(false && "invalid LLVM type for binary operation");
385 return BinaryFunction();
386 }
387
388 /// @brief Returns true if the llvm Type 'from' can be safely cast to the llvm
389 /// Type 'to'.
390 179852 inline bool isValidCast(llvm::Type* from, llvm::Type* to)
391 {
392
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179852 times.
179852 assert(from && "llvm Type 'from' is null in isValidCast");
393
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 179852 times.
179852 assert(to && "llvm Type 'to' is null in isValidCast");
394
395
4/4
✓ Branch 0 taken 59708 times.
✓ Branch 1 taken 120144 times.
✓ Branch 2 taken 18072 times.
✓ Branch 3 taken 109525 times.
187305 if ((from->isIntegerTy() || from->isFloatingPointTy()) &&
396 (to->isIntegerTy() || to->isFloatingPointTy())) {
397 return true;
398 }
399
4/4
✓ Branch 0 taken 28871 times.
✓ Branch 1 taken 24828 times.
✓ Branch 2 taken 28864 times.
✓ Branch 3 taken 7 times.
53699 if (from->isArrayTy() && to->isArrayTy()) {
400 28864 llvm::ArrayType* af = llvm::cast<llvm::ArrayType>(from);
401 28864 llvm::ArrayType* at = llvm::cast<llvm::ArrayType>(to);
402
2/2
✓ Branch 2 taken 4684 times.
✓ Branch 3 taken 24180 times.
28864 if (af->getArrayNumElements() == at->getArrayNumElements()) {
403 4684 return isValidCast(af->getArrayElementType(),
404 4684 at->getArrayElementType());
405 }
406 }
407 return false;
408 }
409
410 /// @brief Casts a scalar llvm Value to a target scalar llvm Type. Returns
411 /// the cast scalar value of type targetType.
412 /// @warning This assumes any integer types are signed.
413 /// @param value A llvm scalar value to convert
414 /// @param targetType The target llvm scalar type to convert to
415 /// @param builder The current llvm IRBuilder
416 inline llvm::Value*
417 92306 arithmeticConversion(llvm::Value* value,
418 llvm::Type* targetType,
419 llvm::IRBuilder<>& builder)
420 {
421
3/4
✓ Branch 0 taken 92306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 66848 times.
✓ Branch 3 taken 25458 times.
92306 assert(value && (value->getType()->isIntegerTy() || value->getType()->isFloatingPointTy()) &&
422 "First Value in arithmeticConversion is not a scalar type");
423
3/4
✓ Branch 0 taken 92306 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 67951 times.
✓ Branch 3 taken 24355 times.
92306 assert(targetType && (targetType->isIntegerTy() || targetType->isFloatingPointTy()) &&
424 "Target Type in arithmeticConversion is not a scalar type");
425
426 const llvm::Type* const valueType = value->getType();
427
2/2
✓ Branch 0 taken 13551 times.
✓ Branch 1 taken 78755 times.
92306 if (valueType == targetType) return value;
428
429
2/4
✓ Branch 1 taken 13551 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 13551 times.
✗ Branch 5 not taken.
13551 CastFunction llvmCastFunction = llvmArithmeticConversion(valueType, targetType);
430
1/2
✓ Branch 1 taken 13551 times.
✗ Branch 2 not taken.
13551 return llvmCastFunction(builder, value, targetType);
431 }
432
433 /// @brief Casts an array to another array of equal size but of a different element
434 /// type. Both source and target array element types must be scalar types.
435 /// The source array llvm Value should be a pointer to the array to cast.
436 ///
437 /// @param ptrToArray A llvm value which is a pointer to a llvm array
438 /// @param targetElementType The target llvm scalar type to convert each element
439 /// of the input array
440 /// @param builder The current llvm IRBuilder
441 ///
442 inline llvm::Value*
443 7615 arrayCast(llvm::Value* ptrToArray,
444 llvm::Type* targetElementType,
445 llvm::IRBuilder<>& builder)
446 {
447
3/4
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 2142 times.
✓ Branch 3 taken 5473 times.
7615 assert(targetElementType && (targetElementType->isIntegerTy() ||
448 targetElementType->isFloatingPointTy()) &&
449 "Target element type is not a scalar type");
450
2/4
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7615 times.
7615 assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
451 "Input to arrayCast is not a pointer type.");
452
453 llvm::Type* arrayType = ptrToArray->getType()->getContainedType(0);
454
2/4
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✗ Branch 2 not taken.
✓ Branch 3 taken 7615 times.
7615 assert(arrayType && llvm::isa<llvm::ArrayType>(arrayType));
455
456 // getArrayElementType() calls getContainedType(0)
457 llvm::Type* sourceElementType = arrayType->getArrayElementType();
458
3/4
✓ Branch 0 taken 7615 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 1956 times.
✓ Branch 3 taken 5659 times.
7615 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
459 sourceElementType->isFloatingPointTy()) &&
460 "Source element type is not a scalar type");
461
462
2/2
✓ Branch 0 taken 290 times.
✓ Branch 1 taken 7325 times.
7615 if (sourceElementType == targetElementType) return ptrToArray;
463
464
2/4
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 290 times.
✗ Branch 5 not taken.
580 CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
465
466 const size_t elementSize = arrayType->getArrayNumElements();
467 llvm::Value* targetArray =
468
1/2
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
290 insertStaticAlloca(builder,
469
1/2
✓ Branch 1 taken 290 times.
✗ Branch 2 not taken.
290 llvm::ArrayType::get(targetElementType, elementSize));
470
471
2/2
✓ Branch 0 taken 1050 times.
✓ Branch 1 taken 290 times.
1340 for (size_t i = 0; i < elementSize; ++i) {
472 1050 llvm::Value* target = builder.CreateConstGEP2_64(targetArray, 0, i);
473 1050 llvm::Value* source = builder.CreateConstGEP2_64(ptrToArray, 0, i);
474
1/4
✓ Branch 2 taken 1050 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✗ Branch 5 not taken.
1050 source = builder.CreateLoad(source);
475
1/2
✓ Branch 1 taken 1050 times.
✗ Branch 2 not taken.
1050 source = llvmCastFunction(builder, source, targetElementType);
476
1/2
✓ Branch 1 taken 1050 times.
✗ Branch 2 not taken.
1050 builder.CreateStore(source, target);
477 }
478
479 return targetArray;
480 }
481
482 /// @brief Converts a vector of loaded llvm scalar values of the same type to a
483 /// target scalar type. Each value is converted individually and the loaded
484 /// result stored in the same location within values.
485 /// @warning This assumes any integer types are signed.
486 /// @param values A vector of llvm scalar values to convert
487 /// @param targetElementType The target llvm scalar type to convert each value
488 /// of the input vector
489 /// @param builder The current llvm IRBuilder
490 inline void
491 245 arithmeticConversion(std::vector<llvm::Value*>& values,
492 llvm::Type* targetElementType,
493 llvm::IRBuilder<>& builder)
494 {
495
3/4
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 239 times.
✓ Branch 3 taken 6 times.
245 assert(targetElementType && (targetElementType->isIntegerTy() ||
496 targetElementType->isFloatingPointTy()) &&
497 "Target element type is not a scalar type");
498
499
1/2
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
245 llvm::Type* sourceElementType = values.front()->getType();
500
3/4
✓ Branch 0 taken 245 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 231 times.
✓ Branch 3 taken 14 times.
245 assert(sourceElementType && (sourceElementType->isIntegerTy() ||
501 sourceElementType->isFloatingPointTy()) &&
502 "Source element type is not a scalar type");
503
504
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 245 times.
245 if (sourceElementType == targetElementType) return;
505
506
2/4
✓ Branch 1 taken 245 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 245 times.
✗ Branch 5 not taken.
490 CastFunction llvmCastFunction = llvmArithmeticConversion(sourceElementType, targetElementType);
507
508
2/2
✓ Branch 0 taken 739 times.
✓ Branch 1 taken 245 times.
984 for (llvm::Value*& value : values) {
509
1/2
✓ Branch 1 taken 739 times.
✗ Branch 2 not taken.
739 value = llvmCastFunction(builder, value, targetElementType);
510 }
511 }
512
513 /// @brief Converts a vector of loaded llvm scalar values to the highest precision
514 /// type stored amongst them. Any values which are not scalar types are ignored
515 /// @warning This assumes any integer types are signed.
516 /// @param values A vector of llvm scalar values to convert
517 /// @param builder The current llvm IRBuilder
518 inline void
519 arithmeticConversion(std::vector<llvm::Value*>& values,
520 llvm::IRBuilder<>& builder)
521 {
522 llvm::Type* typeCast = LLVMType<bool>::get(builder.getContext());
523 for (llvm::Value*& value : values) {
524 llvm::Type* type = value->getType();
525 if (type->isIntegerTy() || type->isFloatingPointTy()) {
526 typeCast = typePrecedence(typeCast, type);
527 }
528 }
529
530 arithmeticConversion(values, typeCast, builder);
531 }
532
533 /// @brief Chooses the highest order llvm Type as defined by typePrecedence
534 /// from either of the two incoming values and casts the other value to
535 /// the choosen type if it is not already. The types of valueA and valueB
536 /// are guaranteed to match. Both values must be scalar LLVM types
537 /// @warning This assumes any integer types are signed.
538 /// @param valueA The first llvm value
539 /// @param valueB The second llvm value
540 /// @param builder The current llvm IRBuilder
541 inline void
542 arithmeticConversion(llvm::Value*& valueA,
543 llvm::Value*& valueB,
544 llvm::IRBuilder<>& builder)
545 {
546 llvm::Type* type = typePrecedence(valueA->getType(), valueB->getType());
547 valueA = arithmeticConversion(valueA, type, builder);
548 valueB = arithmeticConversion(valueB, type, builder);
549 }
550
551 /// @brief Performs a C style boolean comparison from a given scalar LLVM value
552 ///
553 /// @param value The scalar llvm value to convert to a boolean
554 /// @param builder The current llvm IRBuilder
555 ///
556 inline llvm::Value*
557
1/2
✓ Branch 0 taken 27164 times.
✗ Branch 1 not taken.
27164 boolComparison(llvm::Value* value,
558 llvm::IRBuilder<>& builder)
559 {
560 llvm::Type* type = value->getType();
561
562 80 if (type->isFloatingPointTy()) return builder.CreateFCmpONE(value, llvm::ConstantFP::get(type, 0.0));
563
2/2
✓ Branch 1 taken 13128 times.
✓ Branch 2 taken 13996 times.
40252 else if (type->isIntegerTy(1)) return builder.CreateICmpNE(value, llvm::ConstantInt::get(type, 0));
564
1/2
✓ Branch 0 taken 13996 times.
✗ Branch 1 not taken.
27992 else if (type->isIntegerTy()) return builder.CreateICmpNE(value, llvm::ConstantInt::getSigned(type, 0));
565 assert(false && "Invalid type for bool conversion");
566 return nullptr;
567 }
568
569 /// @ brief Performs a binary operation on two loaded llvm scalar values of the same type.
570 /// The type of operation performed is defined by the token (see the list of supported
571 /// tokens in ast/Tokens.h. Returns a loaded llvm scalar result
572 ///
573 /// @param lhs The left hand side value of the binary operation
574 /// @param rhs The right hand side value of the binary operation
575 /// @param token The token representing the binary operation to perform
576 /// @param builder The current llvm IRBuilder
577 inline llvm::Value*
578
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32850 times.
32850 binaryOperator(llvm::Value* lhs, llvm::Value* rhs,
579 const ast::tokens::OperatorToken& token,
580 llvm::IRBuilder<>& builder)
581 {
582 llvm::Type* lhsType = lhs->getType();
583
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
32850 assert(lhsType == rhs->getType() ||
584 (token == ast::tokens::SHIFTLEFT ||
585 token == ast::tokens::SHIFTRIGHT));
586
587
2/2
✓ Branch 0 taken 17871 times.
✓ Branch 1 taken 14979 times.
32850 const ast::tokens::OperatorType opType = ast::tokens::operatorType(token);
588
589 if (opType == ast::tokens::LOGICAL) {
590 3803 lhs = boolComparison(lhs, builder);
591 3803 rhs = boolComparison(rhs, builder);
592 lhsType = lhs->getType(); // now bool type
593 }
594
595
2/4
✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 32850 times.
✗ Branch 5 not taken.
32850 const BinaryFunction llvmBinaryFunction = llvmBinaryConversion(lhsType, token);
596
1/2
✓ Branch 1 taken 32850 times.
✗ Branch 2 not taken.
65700 return llvmBinaryFunction(builder, lhs, rhs);
597 }
598
599 /// @brief Unpack a particular element of an array and return a pointer to that element
600 /// The provided llvm Value is expected to be a pointer to an array
601 ///
602 /// @param ptrToArray A llvm value which is a pointer to a llvm array
603 /// @param index The index at which to access the array
604 /// @param builder The current llvm IRBuilder
605 ///
606 inline llvm::Value*
607 arrayIndexUnpack(llvm::Value* ptrToArray,
608 const int16_t index,
609 llvm::IRBuilder<>& builder)
610 {
611 return builder.CreateConstGEP2_64(ptrToArray, 0, index);
612 }
613
614 /// @brief Unpack an array type into llvm Values which represent all its elements
615 /// The provided llvm Value is expected to be a pointer to an array
616 /// If loadElements is true, values will store loaded llvm values instead
617 /// of pointers to the array elements
618 ///
619 /// @param ptrToArray A llvm value which is a pointer to a llvm array
620 /// @param values A vector of llvm values where to store the array elements
621 /// @param builder The current llvm IRBuilder
622 /// @param loadElements Whether or not to load each array element into a register
623 ///
624 inline void
625
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3344 times.
3344 arrayUnpack(llvm::Value* ptrToArray,
626 std::vector<llvm::Value*>& values,
627 llvm::IRBuilder<>& builder,
628 const bool loadElements = false)
629 {
630 const size_t elements =
631 ptrToArray->getType()->getContainedType(0)->getArrayNumElements();
632
633 3344 values.reserve(elements);
634
2/2
✓ Branch 0 taken 15324 times.
✓ Branch 1 taken 3344 times.
18668 for (size_t i = 0; i < elements; ++i) {
635 15324 llvm::Value* value = builder.CreateConstGEP2_64(ptrToArray, 0, i);
636
2/2
✓ Branch 0 taken 7380 times.
✓ Branch 1 taken 7944 times.
15324 if (loadElements) value = builder.CreateLoad(value);
637 15324 values.push_back(value);
638 }
639 3344 }
640
641 /// @brief Unpack the first three elements of an array.
642 /// The provided llvm Value is expected to be a pointer to an array
643 /// @note The elements are note loaded
644 ///
645 /// @param ptrToArray A llvm value which is a pointer to a llvm array
646 /// @param value1 The first array value
647 /// @param value2 The second array value
648 /// @param value3 The third array value
649 /// @param builder The current llvm IRBuilder
650 ///
651 inline void
652 array3Unpack(llvm::Value* ptrToArray,
653 llvm::Value*& value1,
654 llvm::Value*& value2,
655 llvm::Value*& value3,
656 llvm::IRBuilder<>& builder)
657 {
658 assert(ptrToArray && ptrToArray->getType()->isPointerTy() &&
659 "Input to array3Unpack is not a pointer type.");
660
661 value1 = builder.CreateConstGEP2_64(ptrToArray, 0, 0);
662 value2 = builder.CreateConstGEP2_64(ptrToArray, 0, 1);
663 value3 = builder.CreateConstGEP2_64(ptrToArray, 0, 2);
664 }
665
666 /// @brief Pack three values into a new array and return a pointer to the
667 /// newly allocated array. If the values are of a mismatching type,
668 /// the highets order type is uses, as defined by typePrecedence. All
669 /// llvm values are expected to a be a loaded scalar type
670 ///
671 /// @param value1 The first array value
672 /// @param value2 The second array value
673 /// @param value3 The third array value
674 /// @param builder The current llvm IRBuilder
675 ///
676 inline llvm::Value*
677 array3Pack(llvm::Value* value1,
678 llvm::Value* value2,
679 llvm::Value* value3,
680 llvm::IRBuilder<>& builder)
681 {
682 llvm::Type* type = typePrecedence(value1->getType(), value2->getType());
683 type = typePrecedence(type, value3->getType());
684
685 value1 = arithmeticConversion(value1, type, builder);
686 value2 = arithmeticConversion(value2, type, builder);
687 value3 = arithmeticConversion(value3, type, builder);
688
689 llvm::Type* vectorType = llvm::ArrayType::get(type, 3);
690 llvm::Value* vector = insertStaticAlloca(builder, vectorType);
691
692 llvm::Value* e1 = builder.CreateConstGEP2_64(vector, 0, 0);
693 llvm::Value* e2 = builder.CreateConstGEP2_64(vector, 0, 1);
694 llvm::Value* e3 = builder.CreateConstGEP2_64(vector, 0, 2);
695
696 builder.CreateStore(value1, e1);
697 builder.CreateStore(value2, e2);
698 builder.CreateStore(value3, e3);
699
700 return vector;
701 }
702
703 /// @brief Pack a loaded llvm scalar value into a new array of a specified
704 /// size and return a pointer to the newly allocated array. Each element
705 /// of the new array will have the value of the given scalar
706 ///
707 /// @param value The uniform scalar llvm value to pack into the array
708 /// @param builder The current llvm IRBuilder
709 /// @param size The size of the newly allocated array
710 ///
711 inline llvm::Value*
712 32 arrayPack(llvm::Value* value,
713 llvm::IRBuilder<>& builder,
714 const size_t size = 3)
715 {
716
2/4
✓ Branch 0 taken 32 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 32 times.
✗ Branch 3 not taken.
32 assert(value && (value->getType()->isIntegerTy() ||
717 value->getType()->isFloatingPointTy()) &&
718 "value type is not a scalar type");
719
720 llvm::Type* type = value->getType();
721 llvm::Value* array =
722 32 insertStaticAlloca(builder,
723 32 llvm::ArrayType::get(type, size));
724
725
2/2
✓ Branch 0 taken 96 times.
✓ Branch 1 taken 32 times.
128 for (size_t i = 0; i < size; ++i) {
726 96 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
727 96 builder.CreateStore(value, element);
728 }
729
730 32 return array;
731 }
732
733 /// @brief Pack a vector of loaded llvm scalar values into a new array of
734 /// equal size and return a pointer to the newly allocated array.
735 ///
736 /// @param values A vector of loaded llvm scalar values to pack
737 /// @param builder The current llvm IRBuilder
738 ///
739 inline llvm::Value*
740 4028 arrayPack(const std::vector<llvm::Value*>& values,
741 llvm::IRBuilder<>& builder)
742 {
743 4028 llvm::Type* type = values.front()->getType();
744 4028 llvm::Value* array = insertStaticAlloca(builder,
745 4028 llvm::ArrayType::get(type, values.size()));
746
747 size_t idx = 0;
748
2/2
✓ Branch 0 taken 22719 times.
✓ Branch 1 taken 4028 times.
26747 for (llvm::Value* const& value : values) {
749 22719 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, idx++);
750 22719 builder.CreateStore(value, element);
751 }
752
753 4028 return array;
754 }
755
756 /// @brief Pack a vector of loaded llvm scalar values into a new array of
757 /// equal size and return a pointer to the newly allocated array.
758 /// arrayPackCast first checks all the contained types in values
759 /// and casts all types to the highest order type present. All llvm
760 /// values in values are expected to be loaded scalar types
761 ///
762 /// @param values A vector of loaded llvm scalar values to pack
763 /// @param builder The current llvm IRBuilder
764 ///
765 inline llvm::Value*
766 3931 arrayPackCast(std::vector<llvm::Value*>& values,
767 llvm::IRBuilder<>& builder)
768 {
769 // get the highest order type present
770
771 llvm::Type* type = LLVMType<bool>::get(builder.getContext());
772
2/2
✓ Branch 0 taken 21943 times.
✓ Branch 1 taken 3931 times.
25874 for (llvm::Value* const& value : values) {
773 21943 type = typePrecedence(type, value->getType());
774 }
775
776 // convert all to this type
777
778
2/2
✓ Branch 0 taken 21943 times.
✓ Branch 1 taken 3931 times.
25874 for (llvm::Value*& value : values) {
779 21943 value = arithmeticConversion(value, type, builder);
780 }
781
782 3931 return arrayPack(values, builder);
783 }
784
785 inline llvm::Value*
786 118 scalarToMatrix(llvm::Value* scalar,
787 llvm::IRBuilder<>& builder,
788 const size_t dim = 3)
789 {
790
3/4
✓ Branch 0 taken 118 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 116 times.
✓ Branch 3 taken 2 times.
118 assert(scalar && (scalar->getType()->isIntegerTy() ||
791 scalar->getType()->isFloatingPointTy()) &&
792 "value type is not a scalar type");
793
794 llvm::Type* type = scalar->getType();
795 llvm::Value* array =
796 118 insertStaticAlloca(builder,
797 118 llvm::ArrayType::get(type, dim*dim));
798
799 118 llvm::Value* zero = llvmConstant(0, type);
800
2/2
✓ Branch 0 taken 1426 times.
✓ Branch 1 taken 118 times.
1544 for (size_t i = 0; i < dim*dim; ++i) {
801
2/2
✓ Branch 0 taken 1020 times.
✓ Branch 1 taken 406 times.
1426 llvm::Value* m = ((i % (dim+1) == 0) ? scalar : zero);
802 1426 llvm::Value* element = builder.CreateConstGEP2_64(array, 0, i);
803 1426 builder.CreateStore(m, element);
804 }
805
806 118 return array;
807 }
808
809 } // namespace codegen
810 } // namespace ax
811 } // namespace OPENVDB_VERSION_NAME
812 } // namespace openvdb
813
814 #endif // OPENVDB_AX_CODEGEN_UTILS_HAS_BEEN_INCLUDED
815
816