Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file codegen/PointComputeGenerator.cc | ||
5 | |||
6 | #include "PointComputeGenerator.h" | ||
7 | |||
8 | #include "FunctionRegistry.h" | ||
9 | #include "FunctionTypes.h" | ||
10 | #include "Types.h" | ||
11 | #include "Utils.h" | ||
12 | #include "Codecs.h" | ||
13 | |||
14 | #include "openvdb_ax/Exceptions.h" | ||
15 | #include "openvdb_ax/ast/Scanners.h" | ||
16 | |||
17 | #include <llvm/ADT/SmallVector.h> | ||
18 | #include <llvm/IR/BasicBlock.h> | ||
19 | #include <llvm/IR/CallingConv.h> | ||
20 | #include <llvm/IR/Constants.h> | ||
21 | #include <llvm/IR/DerivedTypes.h> | ||
22 | #include <llvm/IR/Function.h> | ||
23 | #include <llvm/IR/GlobalVariable.h> | ||
24 | #include <llvm/IR/InlineAsm.h> | ||
25 | #include <llvm/IR/Instructions.h> | ||
26 | #include <llvm/IR/Intrinsics.h> | ||
27 | #include <llvm/IR/IRBuilder.h> | ||
28 | #include <llvm/IR/LLVMContext.h> | ||
29 | #include <llvm/Pass.h> | ||
30 | #include <llvm/Support/MathExtras.h> | ||
31 | |||
32 | namespace openvdb { | ||
33 | OPENVDB_USE_VERSION_NAMESPACE | ||
34 | namespace OPENVDB_VERSION_NAME { | ||
35 | |||
36 | namespace ax { | ||
37 | namespace codegen { | ||
38 | |||
39 | const std::array<const char*, PointKernelValue::N_ARGS>& | ||
40 | 772 | PointKernelValue::argumentKeys() | |
41 | { | ||
42 | static const std::array<const char*, PointKernelValue::N_ARGS> arguments = {{ | ||
43 | "custom_data", | ||
44 | "origin", | ||
45 | "value_buffer", | ||
46 | "isactive", | ||
47 | "point_index", | ||
48 | "transforms", | ||
49 | "values", | ||
50 | "flags", | ||
51 | "attribute_set", | ||
52 | "group_handles", | ||
53 | "leaf_data" | ||
54 | }}; | ||
55 | |||
56 | 772 | return arguments; | |
57 | } | ||
58 | |||
59 | 2284 | const char* PointKernelValue::getDefaultName() { return "ax.compute.point.PKV"; } | |
60 | |||
61 | // | ||
62 | |||
63 | const std::array<const char*, PointKernelBufferRange::N_ARGS>& | ||
64 | ✗ | PointKernelBufferRange::argumentKeys() | |
65 | { | ||
66 | static const std::array<const char*, PointKernelBufferRange::N_ARGS> arguments = {{ | ||
67 | "custom_data", | ||
68 | "origin", | ||
69 | "value_buffer", | ||
70 | "active_buffer", | ||
71 | "buffer_size", | ||
72 | "mode", | ||
73 | "transforms", | ||
74 | "buffers", | ||
75 | "flags", | ||
76 | "attribute_set", | ||
77 | "group_handles", | ||
78 | "leaf_data" | ||
79 | }}; | ||
80 | |||
81 | ✗ | return arguments; | |
82 | } | ||
83 | |||
84 | 3037 | const char* PointKernelBufferRange::getDefaultName() { return "ax.compute.point.PKBR"; } | |
85 | |||
86 | // | ||
87 | |||
88 | const std::array<const char*, PointKernelBuffer::N_ARGS>& | ||
89 | 756 | PointKernelBuffer::argumentKeys() | |
90 | { | ||
91 | static const std::array<const char*, PointKernelBuffer::N_ARGS> arguments = {{ | ||
92 | "custom_data", | ||
93 | "origin", | ||
94 | "value_buffer", | ||
95 | "isactive", | ||
96 | "point_index", | ||
97 | "transforms", | ||
98 | "buffers", | ||
99 | "flags", | ||
100 | "attribute_set", | ||
101 | "group_handles", | ||
102 | "leaf_data" | ||
103 | }}; | ||
104 | |||
105 | 756 | return arguments; | |
106 | } | ||
107 | |||
108 | 2268 | const char* PointKernelBuffer::getDefaultName() { return "ax.compute.point.PKB"; } | |
109 | |||
110 | // | ||
111 | |||
112 | const std::array<const char*, PointKernelAttributeArray::N_ARGS>& | ||
113 | 756 | PointKernelAttributeArray::argumentKeys() | |
114 | { | ||
115 | static const std::array<const char*, PointKernelAttributeArray::N_ARGS> arguments = {{ | ||
116 | "custom_data", | ||
117 | "origin", | ||
118 | "value_buffer", | ||
119 | "isactive", | ||
120 | "point_index", | ||
121 | "transforms", | ||
122 | "attribute_arrays", | ||
123 | "flags", | ||
124 | "attribute_set", | ||
125 | "group_handles", | ||
126 | "leaf_data" | ||
127 | }}; | ||
128 | |||
129 | 756 | return arguments; | |
130 | } | ||
131 | |||
132 | 3037 | const char* PointKernelAttributeArray::getDefaultName() { return "ax.compute.point.PKAA"; } | |
133 | |||
134 | /////////////////////////////////////////////////////////////////////////// | ||
135 | /////////////////////////////////////////////////////////////////////////// | ||
136 | |||
137 | namespace codegen_internal { | ||
138 | |||
139 | 756 | inline void PointComputeGenerator::computePKBR(const AttributeRegistry&) | |
140 | { | ||
141 | 1512 | llvm::Function* compute = mModule.getFunction(PointKernelBuffer::getDefaultName()); | |
142 | |||
143 | auto generate = | ||
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | [&](const std::vector<llvm::Value*>& args, |
145 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
146 | { | ||
147 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(args.size() == 12); |
148 | 756 | llvm::Value* vbuff = args[2]; //extractArgument(rangeFunction, "value_buffer"); | |
149 | 756 | llvm::Value* abuff = args[3]; //extractArgument(rangeFunction, "active_buffer"); | |
150 | 756 | llvm::Value* buffSize = args[4]; //extractArgument(rangeFunction, "buffer_size"); | |
151 | 756 | llvm::Value* mode = args[5]; //extractArgument(rangeFunction, "mode"); | |
152 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(buffSize); |
153 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(vbuff); |
154 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(abuff); |
155 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(mode); |
156 | |||
157 | llvm::Function* base = B.GetInsertBlock()->getParent(); | ||
158 | llvm::LLVMContext& C = B.getContext(); | ||
159 | |||
160 | 756 | llvm::BasicBlock* conditionBlock = llvm::BasicBlock::Create(C, "k2.condition", base); | |
161 | 756 | llvm::BasicBlock* bodyBlock = llvm::BasicBlock::Create(C, "k2.body", base); | |
162 | 756 | llvm::BasicBlock* iterBlock = llvm::BasicBlock::Create(C, "k2.buffiter", base); | |
163 | |||
164 | // init var - loops from 0 -> buffSize | ||
165 | 756 | llvm::Value* incr = insertStaticAlloca(B, LLVMType<int64_t>::get(C)); | |
166 | 756 | B.CreateStore(B.getInt64(0), incr); | |
167 | 756 | B.CreateBr(conditionBlock); | |
168 | |||
169 | // increment | ||
170 | B.SetInsertPoint(iterBlock); | ||
171 | { | ||
172 | 756 | llvm::Value* new_incr = B.CreateAdd(B.CreateLoad(incr), B.getInt64(1)); | |
173 | 756 | B.CreateStore(new_incr, incr); | |
174 | 756 | B.CreateBr(conditionBlock); | |
175 | } | ||
176 | |||
177 | // generate loop body | ||
178 | B.SetInsertPoint(bodyBlock); | ||
179 | { | ||
180 | 756 | llvm::Value* lincr = B.CreateLoad(incr); | |
181 | |||
182 | // Extract mask bit from array of words | ||
183 | // NodeMask::isOn() = (0 != (mWords[n >> 6] & (Word(1) << (n & 63)))); | ||
184 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 756 times.
✗ Branch 8 not taken.
|
756 | llvm::Value* mask = binaryOperator(B.getInt64(1), |
185 | 1512 | binaryOperator(lincr, B.getInt64(63), ast::tokens::BITAND, B), | |
186 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | ast::tokens::SHIFTLEFT, B); |
187 | 756 | llvm::Value* word_idx = binaryOperator(lincr, B.getInt64(6), ast::tokens::SHIFTRIGHT, B); | |
188 | 756 | llvm::Value* word = B.CreateGEP(abuff, word_idx); | |
189 | 756 | word = B.CreateLoad(word); | |
190 | 756 | word = binaryOperator(word, mask, ast::tokens::BITAND, B); | |
191 | 756 | llvm::Value* ison = B.CreateICmpNE(word, B.getInt64(0)); | |
192 | |||
193 | // Check if we should run the kernel depending on the mode. | ||
194 | // mode == 0, inactive values | ||
195 | // mode == 1, active values | ||
196 | // mode == 2, all values | ||
197 | 756 | llvm::Value* matches_mode = B.CreateICmpEQ(B.CreateZExt(ison, mode->getType()), mode); | |
198 | 756 | llvm::Value* mode_is_all = B.CreateICmpEQ(mode, B.getInt64(2)); | |
199 | 756 | llvm::Value* process = binaryOperator(matches_mode, mode_is_all, ast::tokens::OR, B); | |
200 | 756 | llvm::BasicBlock* then = llvm::BasicBlock::Create(C, "k2.do_points", base); | |
201 | |||
202 | 756 | B.CreateCondBr(process, then, iterBlock); | |
203 | B.SetInsertPoint(then); | ||
204 | { | ||
205 | // branches for getting the end point index | ||
206 | 756 | llvm::BasicBlock* pthen = llvm::BasicBlock::Create(C, "k2.get_0_end", base); | |
207 | 756 | llvm::BasicBlock* pelse = llvm::BasicBlock::Create(C, "k2.get_p_end", base); | |
208 | |||
209 | // loop branches | ||
210 | 756 | llvm::BasicBlock* pcondition = llvm::BasicBlock::Create(C, "k2.pcond", base); | |
211 | 756 | llvm::BasicBlock* pbody = llvm::BasicBlock::Create(C, "k2.pbody", base); | |
212 | 756 | llvm::BasicBlock* piter = llvm::BasicBlock::Create(C, "k2.piter", base); | |
213 | |||
214 | // loops from pindex->pindexend (point grids have 32bit buffers) | ||
215 | 756 | llvm::Value* pindex = insertStaticAlloca(B, B.getInt32Ty()); | |
216 | 756 | llvm::Value* pindexend = B.CreateGEP(vbuff, lincr); | |
217 | 756 | pindexend = B.CreateLoad(pindexend); | |
218 | |||
219 | 756 | llvm::Value* firstvoxel = binaryOperator(lincr, B.getInt64(0), ast::tokens::EQUALSEQUALS, B); | |
220 | 756 | B.CreateCondBr(firstvoxel, pthen, pelse); | |
221 | B.SetInsertPoint(pthen); | ||
222 | { | ||
223 | 756 | B.CreateStore(B.getInt32(0), pindex); | |
224 | 756 | B.CreateBr(pcondition); | |
225 | } | ||
226 | |||
227 | B.SetInsertPoint(pelse); | ||
228 | { | ||
229 | 756 | llvm::Value* prevv = binaryOperator(lincr, B.getInt64(1), ast::tokens::MINUS, B); | |
230 | 756 | llvm::Value* pindexcount = B.CreateGEP(vbuff, prevv); | |
231 | 756 | B.CreateStore(B.CreateLoad(pindexcount), pindex); | |
232 | 756 | B.CreateBr(pcondition); | |
233 | } | ||
234 | |||
235 | B.SetInsertPoint(pcondition); | ||
236 | { | ||
237 | 756 | llvm::Value* end = B.CreateICmpULT(B.CreateLoad(pindex), pindexend); | |
238 | 756 | B.CreateCondBr(end, pbody, iterBlock); | |
239 | } | ||
240 | |||
241 | B.SetInsertPoint(piter); | ||
242 | { | ||
243 | 756 | llvm::Value* pnext = B.CreateAdd(B.CreateLoad(pindex), B.getInt32(1)); | |
244 | 756 | B.CreateStore(pnext, pindex); | |
245 | 756 | B.CreateBr(pcondition); | |
246 | } | ||
247 | |||
248 | B.SetInsertPoint(pbody); | ||
249 | { | ||
250 | // invoke the point kernel for this value | ||
251 | const std::array<llvm::Value*, 11> input { | ||
252 | args[0], // ax::CustomData | ||
253 | args[1], // index space coordinate | ||
254 | vbuff, // value buffer | ||
255 | ison, // active/inactive | ||
256 | 756 | arithmeticConversion(B.CreateLoad(pindex), B.getInt64Ty(), B), // offset in the point array | |
257 | args[6], // transforms | ||
258 | args[7], // buffers | ||
259 | args[8], // flags | ||
260 | args[9], // attr set | ||
261 | args[10], // groups | ||
262 | args[11] // leafdata | ||
263 | 1512 | }; | |
264 | |||
265 | 756 | B.CreateCall(compute, input); | |
266 | 756 | B.CreateBr(piter); | |
267 | } | ||
268 | } | ||
269 | } | ||
270 | |||
271 | B.SetInsertPoint(conditionBlock); | ||
272 | 756 | llvm::Value* endCondition = B.CreateICmpULT(B.CreateLoad(incr), buffSize); | |
273 | |||
274 | 756 | llvm::BasicBlock* postBlock = llvm::BasicBlock::Create(C, "k2.end", base); | |
275 | 756 | B.CreateCondBr(endCondition, bodyBlock, postBlock); | |
276 | B.SetInsertPoint(postBlock); | ||
277 | 756 | return B.CreateRetVoid(); | |
278 | 756 | }; | |
279 | |||
280 | // Use the function builder to generate the correct prototype and body for K2 | ||
281 |
1/2✓ Branch 3 taken 756 times.
✗ Branch 4 not taken.
|
1512 | auto k = FunctionBuilder(PointKernelBufferRange::getDefaultName()) |
282 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 756 times.
✗ Branch 6 not taken.
|
1512 | .addSignature<PointKernelBufferRange::Signature>(generate, PointKernelBufferRange::getDefaultName()) |
283 | .setConstantFold(false) | ||
284 | .setEmbedIR(false) | ||
285 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::ReadOnly) |
286 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoCapture) |
287 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoAlias) |
288 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::ReadOnly) |
289 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoCapture) |
290 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoAlias) |
291 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoCapture) |
292 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoAlias) |
293 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(3, llvm::Attribute::NoCapture) |
294 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(3, llvm::Attribute::NoAlias) |
295 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoCapture) |
296 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoAlias) |
297 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoCapture) |
298 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoAlias) |
299 | 756 | .addFunctionAttribute(llvm::Attribute::NoRecurse) | |
300 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
1512 | .get(); |
301 | |||
302 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | k->list()[0]->create(mContext, &mModule); |
303 | 756 | } | |
304 | |||
305 | /// @brief Decode the value held by buffer[pid] based on the flag type. | ||
306 | /// @details Certain types either cannot be encoded or can only be encoded with | ||
307 | /// certain encoders, so we use the type information to filter out what | ||
308 | /// encoders we need to loop over in IR. | ||
309 | /// @return Either returns buffer[pid] if no decoding was necessary or a | ||
310 | /// pointer to the newly allocated var of the decoded type which will have | ||
311 | /// been allocated in the function prologue | ||
312 | inline llvm::Value* | ||
313 | 10170 | decode(llvm::Value* buffer, | |
314 | llvm::Value* pid, | ||
315 | llvm::Value* flag, | ||
316 | llvm::Value* store, | ||
317 | ast::tokens::CoreType decodedType, | ||
318 | llvm::IRBuilder<>& B) | ||
319 | { | ||
320 | llvm::LLVMContext& C = B.getContext(); | ||
321 | 10170 | llvm::Type* type = llvmTypeFromToken(decodedType, C); | |
322 | |||
323 | // see if this type might be encoded. If not, just return the original value | ||
324 | 10170 | const auto* codecs = getTypeSupportedCodecs(decodedType); | |
325 |
2/2✓ Branch 0 taken 8530 times.
✓ Branch 1 taken 1640 times.
|
10170 | if (!codecs) { |
326 | // Value can't be encoded so the buffer is guaranteed to be the decoded type | ||
327 | 8530 | buffer = B.CreatePointerCast(buffer, type->getPointerTo()); | |
328 | 17060 | return B.CreateGEP(buffer, pid); | |
329 | } | ||
330 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1640 times.
|
1640 | assert(!codecs->empty()); |
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 1640 times.
|
1640 | assert(store); |
332 | |||
333 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
334 | 1640 | llvm::BasicBlock* post = llvm::BasicBlock::Create(C, "k1.get_buffer.decode", self); | |
335 | |||
336 |
2/2✓ Branch 0 taken 5912 times.
✓ Branch 1 taken 1640 times.
|
7552 | for (const auto& codecNamePair : *codecs) { |
337 | 5912 | const std::string& name = codecNamePair.first; | |
338 | 5912 | const Codec* codec = codecNamePair.second; | |
339 | |||
340 |
1/2✓ Branch 3 taken 5912 times.
✗ Branch 4 not taken.
|
5912 | llvm::BasicBlock* then = llvm::BasicBlock::Create(C, "k1.get_buffer." + name, self); |
341 | 5912 | llvm::BasicBlock* els = llvm::BasicBlock::Create(C, "", self); | |
342 | |||
343 | llvm::Value* usescodec = | ||
344 | 5912 | B.CreateAnd(flag, LLVMType<uint64_t>::get(C, codec->flag())); | |
345 | 5912 | usescodec = boolComparison(usescodec, B); | |
346 | 5912 | B.CreateCondBr(usescodec, then, els); | |
347 | |||
348 | B.SetInsertPoint(then); | ||
349 | { | ||
350 | // If this is the codec in use, get the appropriate function, cast | ||
351 | // the input value and decode the value. | ||
352 | const FunctionGroup* const F = codec->decoder(); | ||
353 | 5912 | llvm::Type* encodedType = codec->decodedToEncoded(decodedType, C); | |
354 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5912 times.
|
5912 | assert(encodedType); |
355 | 5912 | encodedType = encodedType->getPointerTo(); | |
356 | |||
357 | // guranteed to be castable | ||
358 | 5912 | llvm::Value* typedBuffer = B.CreatePointerCast(buffer, encodedType); | |
359 |
1/2✓ Branch 2 taken 5912 times.
✗ Branch 3 not taken.
|
11824 | llvm::Value* encoded = B.CreateGEP(typedBuffer, pid); |
360 |
3/6✓ Branch 1 taken 5912 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5912 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 5912 times.
|
5912 | assert(F->match({store->getType(), encoded->getType()}, C)); |
361 |
2/4✓ Branch 1 taken 5912 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5912 times.
✗ Branch 5 not taken.
|
5912 | F->execute({store, encoded}, B); |
362 | 5912 | B.CreateBr(post); | |
363 | } | ||
364 | |||
365 | B.SetInsertPoint(els); | ||
366 | } | ||
367 | |||
368 | // if we're here (the final else), the value is not encoded | ||
369 | // @todo We could instead register all vaid nullcodecs which would give | ||
370 | // guarantees should a codec not exist | ||
371 | 1640 | llvm::Value* typedBuffer = B.CreatePointerCast(buffer, type->getPointerTo()); | |
372 | 1640 | llvm::Value* value = B.CreateGEP(typedBuffer, pid); | |
373 | 1640 | B.CreateStore(B.CreateLoad(value), store); | |
374 | 1640 | B.CreateBr(post); | |
375 | |||
376 | B.SetInsertPoint(post); | ||
377 | 1640 | return store; | |
378 | } | ||
379 | |||
380 | /// @brief Encode the value held by "in" based on the flag type, to the | ||
381 | /// location pointed to by buffer[pid]. | ||
382 | /// @details Certain types either cannot be encoded or can only be encoded with | ||
383 | /// certain codec, so we use the type information to filter out what | ||
384 | /// codec we need to loop over in IR. | ||
385 | /// @return Either returns immediately if no encoding was necessary or stores | ||
386 | /// the encoded version of "in" at the location pointed to by buffer[pid] | ||
387 | inline void | ||
388 | 4940 | encode(llvm::Value* in, | |
389 | llvm::Value* buffer, | ||
390 | llvm::Value* pid, | ||
391 | llvm::Value* flag, | ||
392 | ast::tokens::CoreType decodedType, | ||
393 | llvm::IRBuilder<>& B) | ||
394 | { | ||
395 | llvm::LLVMContext& C = B.getContext(); | ||
396 | 4940 | llvm::Type* type = llvmTypeFromToken(decodedType, C); | |
397 | |||
398 | // see if this type might be encoded. If not, just store the original value | ||
399 | 4940 | const auto* codecs = getTypeSupportedCodecs(decodedType); | |
400 |
2/2✓ Branch 0 taken 4149 times.
✓ Branch 1 taken 791 times.
|
4940 | if (!codecs) { |
401 | // Value can't be encoded so the buffer is guaranteed to be the decoded type | ||
402 | 4149 | buffer = B.CreatePointerCast(buffer, type->getPointerTo()); | |
403 | 8298 | B.CreateStore(B.CreateLoad(in), B.CreateGEP(buffer, pid)); | |
404 | 4149 | return; | |
405 | } | ||
406 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 791 times.
|
791 | assert(!codecs->empty()); |
407 | |||
408 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
409 | 791 | llvm::BasicBlock* post = llvm::BasicBlock::Create(C, "k1.set_buffer.encode", self); | |
410 | |||
411 |
2/2✓ Branch 0 taken 2847 times.
✓ Branch 1 taken 791 times.
|
3638 | for (const auto& codecNamePair : *codecs) { |
412 | 2847 | const std::string& name = codecNamePair.first; | |
413 | 2847 | const Codec* codec = codecNamePair.second; | |
414 | |||
415 |
1/2✓ Branch 3 taken 2847 times.
✗ Branch 4 not taken.
|
2847 | llvm::BasicBlock* then = llvm::BasicBlock::Create(C, "k1.set_buffer." + name, self); |
416 | 2847 | llvm::BasicBlock* els = llvm::BasicBlock::Create(C, "", self); | |
417 | |||
418 | llvm::Value* usescodec = | ||
419 | 2847 | B.CreateAnd(flag, LLVMType<uint64_t>::get(C, codec->flag())); | |
420 | 2847 | usescodec = boolComparison(usescodec, B); | |
421 | 2847 | B.CreateCondBr(usescodec, then, els); | |
422 | |||
423 | B.SetInsertPoint(then); | ||
424 | { | ||
425 | const FunctionGroup* const F = codec->encoder(); | ||
426 | 2847 | llvm::Type* encodedType = codec->decodedToEncoded(decodedType, C); | |
427 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 2847 times.
|
2847 | assert(encodedType); |
428 | 2847 | encodedType = encodedType->getPointerTo(); | |
429 | 2847 | llvm::Value* typedBuffer = B.CreatePointerCast(buffer, encodedType); | |
430 |
1/2✓ Branch 2 taken 2847 times.
✗ Branch 3 not taken.
|
5694 | llvm::Value* loc = B.CreateGEP(typedBuffer, pid); |
431 |
3/6✓ Branch 1 taken 2847 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2847 times.
✗ Branch 5 not taken.
✗ Branch 6 not taken.
✓ Branch 7 taken 2847 times.
|
2847 | assert(F->match({loc->getType(),in->getType()}, C)); |
432 |
2/4✓ Branch 1 taken 2847 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2847 times.
✗ Branch 5 not taken.
|
2847 | F->execute({loc, in}, B); |
433 | 2847 | B.CreateBr(post); | |
434 | } | ||
435 | |||
436 | B.SetInsertPoint(els); | ||
437 | } | ||
438 | |||
439 | // if we're here (the final else), the value is not encodable | ||
440 | // @todo We could instead register all vaid nullcodecs which would give | ||
441 | // guarantees should a codec not exist | ||
442 | 791 | llvm::Value* typedBuffer = B.CreatePointerCast(buffer, type->getPointerTo()); | |
443 | 791 | llvm::Value* loc = B.CreateGEP(typedBuffer, pid); | |
444 | 791 | B.CreateStore(B.CreateLoad(in), loc); | |
445 | 791 | B.CreateBr(post); | |
446 | |||
447 | B.SetInsertPoint(post); | ||
448 | } | ||
449 | |||
450 | 756 | inline void PointComputeGenerator::computePKB(const AttributeRegistry& registry) | |
451 | { | ||
452 | 1512 | llvm::Function* compute = mModule.getFunction(PointKernelValue::getDefaultName()); | |
453 | |||
454 | auto generate = | ||
455 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | [&](const std::vector<llvm::Value*>& args, |
456 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
457 | { | ||
458 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(args.size() == 11); |
459 | auto& C = B.getContext(); | ||
460 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
461 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
|
756 | llvm::Value* pindex = extractArgument(self, "point_index"); |
462 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
|
756 | llvm::Value* flags = extractArgument(self, "flags"); |
463 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
|
756 | llvm::Value* buffers = extractArgument(self, "buffers"); |
464 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(buffers); |
465 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(pindex); |
466 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(flags); |
467 | |||
468 | // create array of void*. each pointer will encode an address to a stored typed value | ||
469 | 1512 | llvm::Type* locType = llvm::ArrayType::get(LLVMType<void*>::get(C), registry.data().size()); // [SIZE x i8*] | |
470 | 756 | llvm::Value* loc = insertStaticAlloca(B, locType); | |
471 | |||
472 | size_t i = 0; | ||
473 |
2/2✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 756 times.
|
5841 | for (const AttributeRegistry::AccessData& data : registry.data()) |
474 | { | ||
475 | const std::string token = data.tokenname(); | ||
476 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | llvm::Type* type = llvmTypeFromToken(data.type(), C); |
477 | |||
478 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | llvm::Value* decodedPtrs = B.CreateConstInBoundsGEP2_64(loc, 0, i++); // void**, location to hold the typed ptr |
479 |
3/6✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5085 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 5085 times.
✗ Branch 9 not taken.
|
5085 | decodedPtrs = B.CreatePointerCast(decodedPtrs, type->getPointerTo()->getPointerTo()); // ValueType** |
480 | |||
481 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | llvm::Value* index = mModule.getGlobalVariable(token); |
482 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5085 times.
|
5085 | assert(index); |
483 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | index = B.CreateLoad(index); |
484 | 5085 | llvm::Value* buffer = B.CreateGEP(buffers, index); | |
485 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | buffer = B.CreateLoad(buffer); // void** = void* |
486 | |||
487 |
1/2✓ Branch 3 taken 5085 times.
✗ Branch 4 not taken.
|
10170 | llvm::Value* flag = B.CreateLoad(B.CreateGEP(flags, index)); |
488 | |||
489 | // @todo write handles shouldn't need to do this check | ||
490 |
2/4✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5085 times.
✗ Branch 6 not taken.
|
5085 | llvm::Value* isuniform = B.CreateAnd(flag, LLVMType<uint64_t>::get(C, (uint64_t(1) << 63))); |
491 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | isuniform = boolComparison(isuniform, B); |
492 | |||
493 | // If the value type has supported codecs we have to allocate the | ||
494 | // expected decoded type that will be stored. Otherwise, decode() | ||
495 | // will simply extract the value ptr directly from the buffer. | ||
496 | llvm::Value* decodedStore = nullptr; | ||
497 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | const auto* codecs = getTypeSupportedCodecs(data.type()); |
498 |
4/6✓ Branch 0 taken 820 times.
✓ Branch 1 taken 4265 times.
✓ Branch 3 taken 820 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 820 times.
✗ Branch 7 not taken.
|
5085 | if (codecs) decodedStore = insertStaticAlloca(B, llvmTypeFromToken(data.type(), C)); // allocated to prologue |
499 | |||
500 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | llvm::BasicBlock* then = llvm::BasicBlock::Create(C, "k1.get_buffer.uniform", self); |
501 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | llvm::BasicBlock* els = llvm::BasicBlock::Create(C, "k1.get_buffer.nuniform", self); |
502 |
1/2✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
|
5085 | llvm::BasicBlock* cont = llvm::BasicBlock::Create(C, "k1.get_buffer.continue", self); |
503 | |||
504 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateCondBr(isuniform, then, els); |
505 | |||
506 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.SetInsertPoint(then); |
507 | { | ||
508 |
2/4✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5085 times.
✗ Branch 5 not taken.
|
5085 | llvm::Value* ptr = decode(buffer, B.getInt64(0), flag, decodedStore, data.type(), B); |
509 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateStore(ptr, decodedPtrs); |
510 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateBr(cont); |
511 | } | ||
512 | |||
513 | B.SetInsertPoint(els); | ||
514 | { | ||
515 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | llvm::Value* ptr = decode(buffer, pindex, flag, decodedStore, data.type(), B); |
516 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateStore(ptr, decodedPtrs); |
517 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateBr(cont); |
518 | } | ||
519 | |||
520 | B.SetInsertPoint(cont); | ||
521 | } | ||
522 | |||
523 | 756 | llvm::BasicBlock* post = llvm::BasicBlock::Create(C, "k1.run_compute", self); | |
524 | 756 | B.CreateBr(post); | |
525 | B.SetInsertPoint(post); | ||
526 | |||
527 | // invoke the point kernel for this value | ||
528 | std::array<llvm::Value*, 11> input; | ||
529 | 756 | std::copy_n(args.begin(), 11, input.begin()); | |
530 | 756 | input[6] = B.CreateConstInBoundsGEP2_64(loc, 0, 0); // void**, replace the buffers with the extracted values | |
531 | |||
532 | 756 | B.CreateCall(compute, input); | |
533 | |||
534 | // insert writes to any attributes that were potentially compressed | ||
535 | i = 0; | ||
536 |
2/2✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 756 times.
|
5841 | for (const AttributeRegistry::AccessData& data : registry.data()) |
537 | { | ||
538 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 4940 times.
|
5085 | if (!data.writes()) { |
539 | 145 | i++; | |
540 | 145 | continue; | |
541 | } | ||
542 | |||
543 | const std::string token = data.tokenname(); | ||
544 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | llvm::Type* type = llvmTypeFromToken(data.type(), C); |
545 | |||
546 |
1/2✓ Branch 2 taken 4940 times.
✗ Branch 3 not taken.
|
4940 | llvm::Value* store = B.CreateConstInBoundsGEP2_64(loc, 0, i++); // void**, location to hold the typed ptr |
547 |
1/2✓ Branch 2 taken 4940 times.
✗ Branch 3 not taken.
|
4940 | store = B.CreateLoad(store); // void* |
548 |
2/4✓ Branch 2 taken 4940 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4940 times.
✗ Branch 6 not taken.
|
4940 | store = B.CreatePointerCast(store, type->getPointerTo()); // ValueType* |
549 | |||
550 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | llvm::Value* index = mModule.getGlobalVariable(token); |
551 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4940 times.
|
4940 | assert(index); |
552 |
1/2✓ Branch 2 taken 4940 times.
✗ Branch 3 not taken.
|
4940 | index = B.CreateLoad(index); |
553 |
1/2✓ Branch 3 taken 4940 times.
✗ Branch 4 not taken.
|
9880 | llvm::Value* flag = B.CreateLoad(B.CreateGEP(flags, index)); |
554 | |||
555 | 4940 | llvm::Value* buffer = B.CreateGEP(buffers, index); | |
556 |
2/4✓ Branch 2 taken 4940 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 4940 times.
✗ Branch 6 not taken.
|
4940 | buffer = B.CreateLoad(buffer); // void** = void* |
557 | |||
558 | // The buffer should not be uniform if we're writing to it, so no | ||
559 | // need to branch for this case (this should be guaranteed by the | ||
560 | // PointExectuable) | ||
561 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | encode(store, buffer, pindex, flag, data.type(), B); |
562 | } | ||
563 | |||
564 | 756 | return B.CreateRetVoid(); | |
565 | 756 | }; | |
566 | |||
567 | 756 | const auto& keys = PointKernelBuffer::argumentKeys(); | |
568 | |||
569 | // Use the function builder to generate the correct prototype and body for K2 | ||
570 |
1/2✓ Branch 3 taken 756 times.
✗ Branch 4 not taken.
|
1512 | auto k = FunctionBuilder(PointKernelBuffer::getDefaultName()) |
571 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 756 times.
✗ Branch 8 not taken.
|
1512 | .addSignature<PointKernelBuffer::Signature>(generate, PointKernelBuffer::getDefaultName()) |
572 | .setConstantFold(false) | ||
573 | .setEmbedIR(false) | ||
574 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 756 times.
✗ Branch 7 not taken.
|
1512 | .setArgumentNames(std::vector<const char*>(keys.begin(), keys.end())) |
575 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::ReadOnly) |
576 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoCapture) |
577 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoAlias) |
578 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::ReadOnly) |
579 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoCapture) |
580 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoAlias) |
581 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoCapture) |
582 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoAlias) |
583 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(5, llvm::Attribute::NoCapture) |
584 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(5, llvm::Attribute::NoAlias) |
585 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoCapture) |
586 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoAlias) |
587 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoCapture) |
588 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoAlias) |
589 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(8, llvm::Attribute::NoCapture) |
590 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(8, llvm::Attribute::NoAlias) |
591 | 756 | .addFunctionAttribute(llvm::Attribute::NoRecurse) | |
592 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
1512 | .get(); |
593 | |||
594 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | k->list()[0]->create(mContext, &mModule); |
595 | 756 | } | |
596 | |||
597 | 756 | inline void PointComputeGenerator::computePKAA(const AttributeRegistry& registry) | |
598 | { | ||
599 | 1512 | llvm::Function* compute = mModule.getFunction(PointKernelValue::getDefaultName()); | |
600 | |||
601 | /// @brief PKAA function for getting a point value from an attribute array | ||
602 | 5085 | auto getAttributeValue = [this](const std::string& token, | |
603 | llvm::Value* pindex, | ||
604 | llvm::Value* store, | ||
605 | 5085 | llvm::IRBuilder<>& B) | |
606 | { | ||
607 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
608 | llvm::Module* M = self->getParent(); | ||
609 | llvm::LLVMContext& C = B.getContext(); | ||
610 | |||
611 | llvm::Type* type = store->getType(); | ||
612 | |||
613 | // insert the attribute into the map of global variables and get a unique global representing | ||
614 | // the location which will hold the attribute handle offset. | ||
615 | 5085 | llvm::Value* index = M->getGlobalVariable(token); | |
616 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5085 times.
|
5085 | assert(index); |
617 | 5085 | index = B.CreateLoad(index); | |
618 | |||
619 |
2/4✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5085 times.
✗ Branch 5 not taken.
|
5085 | llvm::Value* arrays = extractArgument(self, "attribute_arrays"); |
620 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 5085 times.
|
5085 | assert(arrays); |
621 | 5085 | llvm::Value* array = B.CreateGEP(arrays, index); | |
622 | 5085 | array = B.CreateLoad(array); // void** = void* | |
623 | |||
624 | // invoke C binding | ||
625 | const bool usingString = | ||
626 | type == LLVMType<codegen::String*>::get(C); | ||
627 | |||
628 | std::vector<llvm::Value*> args { | ||
629 | array, | ||
630 | pindex, | ||
631 | store | ||
632 | 5085 | }; | |
633 | |||
634 |
2/2✓ Branch 0 taken 90 times.
✓ Branch 1 taken 4995 times.
|
5085 | if (usingString) { |
635 |
3/6✓ Branch 1 taken 90 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 90 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 90 times.
✗ Branch 8 not taken.
|
90 | args.emplace_back(extractArgument(self, "leaf_data")); |
636 | } | ||
637 | |||
638 |
2/4✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5085 times.
✗ Branch 5 not taken.
|
5085 | const FunctionGroup* const F = this->getFunction("getattribute", true); |
639 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | F->execute(args, B); |
640 | 5085 | }; | |
641 | |||
642 | /// @brief PKAA function for setting a point value on an attribute array | ||
643 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4940 times.
|
4940 | auto setAttributeValue = [this](const std::string& token, |
644 | llvm::Value* pindex, | ||
645 | llvm::Value* load, | ||
646 | 4940 | llvm::IRBuilder<>& B) | |
647 | { | ||
648 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
649 | llvm::Module* M = self->getParent(); | ||
650 | llvm::LLVMContext& C = B.getContext(); | ||
651 | |||
652 | llvm::Type* type = load->getType()->getPointerElementType(); | ||
653 | |||
654 | // insert the attribute into the map of global variables and get a unique global representing | ||
655 | // the location which will hold the attribute handle offset. | ||
656 | 4940 | llvm::Value* index = M->getGlobalVariable(token); | |
657 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4940 times.
|
4940 | assert(index); |
658 | 4940 | index = B.CreateLoad(index); | |
659 | |||
660 |
2/4✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4940 times.
✗ Branch 5 not taken.
|
4940 | llvm::Value* arrays = extractArgument(self, "attribute_arrays"); |
661 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 4940 times.
|
4940 | assert(arrays); |
662 | 4940 | llvm::Value* array = B.CreateGEP(arrays, index); | |
663 |
2/2✓ Branch 2 taken 3239 times.
✓ Branch 3 taken 1701 times.
|
4940 | array = B.CreateLoad(array); // void** = void* |
664 | |||
665 | // load the result (if its a scalar) | ||
666 |
2/2✓ Branch 0 taken 3239 times.
✓ Branch 1 taken 1701 times.
|
4940 | if (type->isIntegerTy() || type->isFloatingPointTy()) { |
667 | 3039 | load = B.CreateLoad(load); | |
668 | } | ||
669 | //llvm::errs() << "storing: " << *(load->getType()) << '\n'; | ||
670 | |||
671 | // construct function arguments | ||
672 | std::vector<llvm::Value*> args { | ||
673 | array, // handle | ||
674 | pindex, // point index | ||
675 | load // set value | ||
676 | 4940 | }; | |
677 | |||
678 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | llvm::Type* strType = LLVMType<codegen::String>::get(C); |
679 | const bool usingString = type == strType; | ||
680 | |||
681 |
2/2✓ Branch 0 taken 84 times.
✓ Branch 1 taken 4856 times.
|
4940 | if (usingString) { |
682 |
2/4✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 84 times.
✗ Branch 5 not taken.
|
84 | llvm::Value* leafdata = extractArgument(self, "leaf_data"); |
683 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 84 times.
|
84 | assert(leafdata); |
684 |
1/2✓ Branch 1 taken 84 times.
✗ Branch 2 not taken.
|
84 | args.emplace_back(leafdata); |
685 | } | ||
686 | |||
687 |
2/4✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4940 times.
✗ Branch 5 not taken.
|
4940 | const FunctionGroup* const function = this->getFunction("setattribute", true); |
688 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | function->execute(args, B); |
689 | 4940 | }; | |
690 | |||
691 | // | ||
692 | |||
693 | auto generate = | ||
694 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | [&](const std::vector<llvm::Value*>& args, |
695 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
696 | { | ||
697 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 756 times.
|
756 | assert(args.size() == 11); |
698 | auto& C = B.getContext(); | ||
699 | llvm::Function* self = B.GetInsertBlock()->getParent(); | ||
700 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 756 times.
✗ Branch 8 not taken.
|
1512 | llvm::Value* pindex = extractArgument(self, "point_index"); |
701 | |||
702 | SymbolTable table; | ||
703 | |||
704 | // create array of void*. each element will hold the attribute values | ||
705 |
2/4✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
|
2268 | llvm::Type* locType = llvm::ArrayType::get(LLVMType<void*>::get(C), registry.data().size()); // [SIZE x i8*] |
706 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | llvm::Value* loc = insertStaticAlloca(B, locType); |
707 | |||
708 | // run allocations | ||
709 | size_t i = 0; | ||
710 |
2/2✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 756 times.
|
5841 | for (const AttributeRegistry::AccessData& access : registry.data()) { |
711 |
2/4✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5085 times.
✗ Branch 5 not taken.
|
5085 | llvm::Value* value = insertStaticAlloca(B, llvmTypeFromToken(access.type(), C)); |
712 |
2/4✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
✓ Branch 5 taken 5085 times.
|
5085 | assert(llvm::cast<llvm::AllocaInst>(value)->isStaticAlloca()); |
713 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | table.insert(access.tokenname(), value); |
714 | |||
715 | // store the allocated ptr in the array of void* | ||
716 | 5085 | llvm::Value* store = B.CreateConstInBoundsGEP2_64(loc, 0, i); // void**, location to hold the typed ptr | |
717 |
2/4✓ Branch 2 taken 5085 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 5085 times.
✗ Branch 6 not taken.
|
5085 | value = B.CreatePointerCast(value, LLVMType<void*>::get(C)); |
718 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | B.CreateStore(value, store); |
719 | |||
720 | 5085 | ++i; | |
721 | } | ||
722 | |||
723 | // get attributes | ||
724 |
2/2✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 756 times.
|
5841 | for (const AttributeRegistry::AccessData& data : registry.data()) { |
725 | const std::string token = data.tokenname(); | ||
726 | 5085 | llvm::Value* store = table.get(token); | |
727 |
1/2✓ Branch 1 taken 5085 times.
✗ Branch 2 not taken.
|
5085 | getAttributeValue(token, pindex, store, B); |
728 | } | ||
729 | |||
730 | // invoke the point kernel for this value | ||
731 | std::array<llvm::Value*, 11> input; | ||
732 | 756 | std::copy_n(args.begin(), 11, input.begin()); | |
733 | 756 | input[6] = B.CreateConstInBoundsGEP2_64(loc, 0, 0); // void**, replace the buffers with the extracted values | |
734 |
1/2✓ Branch 2 taken 756 times.
✗ Branch 3 not taken.
|
756 | B.CreateCall(compute, input); |
735 | |||
736 | // insert set code and deallocations | ||
737 |
2/2✓ Branch 0 taken 5085 times.
✓ Branch 1 taken 756 times.
|
5841 | for (const AttributeRegistry::AccessData& data : registry.data()) { |
738 |
2/2✓ Branch 0 taken 145 times.
✓ Branch 1 taken 4940 times.
|
5085 | if (!data.writes()) continue; |
739 | |||
740 | const std::string token = data.tokenname(); | ||
741 | 4940 | llvm::Value* value = table.get(token); | |
742 | // // Expected to be used more than one (i.e. should never be zero) | ||
743 | // assert(value->hasNUsesOrMore(1)); | ||
744 | // // Check to see if this value is still being used - it may have | ||
745 | // // been cleaned up due to returns. If there's only one use, it's | ||
746 | // // the original get of this attribute. | ||
747 | // if (value->hasOneUse()) { | ||
748 | // // @todo The original get can also be optimized out in this case | ||
749 | // // this->globals().remove(variable.first); | ||
750 | // // mModule.getGlobalVariable(variable.first)->eraseFromParent(); | ||
751 | // continue; | ||
752 | // } | ||
753 |
1/2✓ Branch 1 taken 4940 times.
✗ Branch 2 not taken.
|
4940 | setAttributeValue(token, pindex, value, B); |
754 | } | ||
755 | |||
756 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | llvm::Value* last = B.CreateRetVoid(); |
757 | |||
758 | // insert free calls for any strings | ||
759 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | this->createFreeSymbolStrings(B); |
760 | |||
761 | 756 | return last; | |
762 | 756 | }; | |
763 | |||
764 | 756 | const auto& keys = PointKernelAttributeArray::argumentKeys(); | |
765 | |||
766 | // Use the function builder to generate the correct prototype and body for K2 | ||
767 |
1/2✓ Branch 3 taken 756 times.
✗ Branch 4 not taken.
|
1512 | auto k = FunctionBuilder(PointKernelAttributeArray::getDefaultName()) |
768 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 756 times.
✗ Branch 8 not taken.
|
1512 | .addSignature<PointKernelAttributeArray::Signature>(generate, PointKernelAttributeArray::getDefaultName()) |
769 | .setConstantFold(false) | ||
770 | .setEmbedIR(false) | ||
771 |
3/6✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 756 times.
✗ Branch 5 not taken.
✓ Branch 6 taken 756 times.
✗ Branch 7 not taken.
|
1512 | .setArgumentNames(std::vector<const char*>(keys.begin(), keys.end())) |
772 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::ReadOnly) |
773 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoCapture) |
774 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(0, llvm::Attribute::NoAlias) |
775 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::ReadOnly) |
776 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoCapture) |
777 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(1, llvm::Attribute::NoAlias) |
778 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoCapture) |
779 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(2, llvm::Attribute::NoAlias) |
780 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(5, llvm::Attribute::NoCapture) |
781 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(5, llvm::Attribute::NoAlias) |
782 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoCapture) |
783 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(6, llvm::Attribute::NoAlias) |
784 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoCapture) |
785 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(7, llvm::Attribute::NoAlias) |
786 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(8, llvm::Attribute::NoCapture) |
787 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | .addParameterAttribute(8, llvm::Attribute::NoAlias) |
788 | 756 | .addFunctionAttribute(llvm::Attribute::NoRecurse) | |
789 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
1512 | .get(); |
790 | |||
791 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | k->list()[0]->create(mContext, &mModule); |
792 | 756 | } | |
793 | |||
794 | 772 | PointComputeGenerator::PointComputeGenerator(llvm::Module& module, | |
795 | const FunctionOptions& options, | ||
796 | FunctionRegistry& functionRegistry, | ||
797 | 772 | Logger& logger) | |
798 | 772 | : ComputeGenerator(module, options, functionRegistry, logger) {} | |
799 | |||
800 | |||
801 | 772 | AttributeRegistry::Ptr PointComputeGenerator::generate(const ast::Tree& tree) | |
802 | { | ||
803 | llvm::FunctionType* type = | ||
804 | 772 | llvmFunctionTypeFromSignature<PointKernelValue::Signature>(mContext); | |
805 | |||
806 |
1/2✓ Branch 2 taken 772 times.
✗ Branch 3 not taken.
|
772 | mFunction = llvm::Function::Create(type, |
807 | llvm::Function::ExternalLinkage, | ||
808 | PointKernelValue::getDefaultName(), | ||
809 | 772 | &mModule); | |
810 | |||
811 | // @note Might be worth always inlining the value kernel into the buffer kernel | ||
812 | //mFunction->addFnAttr(llvm::Attribute::AlwaysInline); | ||
813 | |||
814 | // Set up arguments for initial entry | ||
815 | |||
816 | llvm::Function::arg_iterator argIter = mFunction->arg_begin(); | ||
817 | 772 | const auto arguments = PointKernelValue::argumentKeys(); | |
818 | auto keyIter = arguments.cbegin(); | ||
819 | |||
820 |
3/4✗ Branch 0 not taken.
✓ Branch 1 taken 9264 times.
✓ Branch 2 taken 8492 times.
✓ Branch 3 taken 772 times.
|
9264 | for (; argIter != mFunction->arg_end(); ++argIter, ++keyIter) { |
821 | 8492 | argIter->setName(*keyIter); | |
822 | } | ||
823 | |||
824 | 772 | llvm::BasicBlock* entry = llvm::BasicBlock::Create(mContext, "k1.entry", mFunction); | |
825 | mBuilder.SetInsertPoint(entry); | ||
826 | |||
827 | // build the attribute registry | ||
828 | |||
829 | 772 | AttributeRegistry::Ptr registry = AttributeRegistry::create(tree); | |
830 | |||
831 | // intialise the global indices - do this here so it's only done once | ||
832 | |||
833 |
2/2✓ Branch 0 taken 5087 times.
✓ Branch 1 taken 772 times.
|
5859 | for (const AttributeRegistry::AccessData& access : registry->data()) { |
834 | const std::string token = access.tokenname(); | ||
835 | llvm::Value* index = llvm::cast<llvm::GlobalVariable> | ||
836 |
3/6✓ Branch 1 taken 5087 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5087 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 5087 times.
✗ Branch 9 not taken.
|
5087 | (mModule.getOrInsertGlobal(token, LLVMType<int64_t>::get(mContext))); |
837 |
1/2✓ Branch 1 taken 5087 times.
✗ Branch 2 not taken.
|
5087 | this->globals().insert(token, index); |
838 | } | ||
839 | |||
840 | // full code generation | ||
841 | // errors can stop traversal, but dont always, so check the log | ||
842 | |||
843 |
2/2✓ Branch 1 taken 767 times.
✓ Branch 2 taken 5 times.
|
772 | const size_t err = mLog.errors(); |
844 |
3/4✓ Branch 0 taken 767 times.
✗ Branch 1 not taken.
✓ Branch 2 taken 11 times.
✓ Branch 3 taken 756 times.
|
767 | if (!this->traverse(&tree) || (mLog.errors() > err)) return nullptr; |
845 | |||
846 | // insert free calls for any strings | ||
847 | |||
848 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | this->createFreeSymbolStrings(mBuilder); |
849 | |||
850 | // compute extra kernels (order here is important) | ||
851 | |||
852 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | this->computePKB(*registry); |
853 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | this->computePKAA(*registry); |
854 | // must come after PKB | ||
855 |
1/2✓ Branch 1 taken 756 times.
✗ Branch 2 not taken.
|
756 | this->computePKBR(*registry); |
856 | |||
857 | return registry; | ||
858 | } | ||
859 | |||
860 | 6082 | bool PointComputeGenerator::visit(const ast::Attribute* node) | |
861 | { | ||
862 | 12164 | llvm::Value* index = mModule.getGlobalVariable(node->tokenname()); | |
863 | 6082 | llvm::Type* type = llvmTypeFromToken(node->type(), mContext); | |
864 | |||
865 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 6082 times.
|
6082 | assert(index); |
866 | // index into the void* array of handles and load the value. | ||
867 | 6082 | index = mBuilder.CreateLoad(index); | |
868 |
2/4✓ Branch 1 taken 6082 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 6082 times.
✗ Branch 5 not taken.
|
6082 | llvm::Value* value = extractArgument(mFunction, "values"); // void** |
869 | 6082 | value = mBuilder.CreateGEP(value, index); // void** | |
870 | 6082 | value = mBuilder.CreateLoad(value); // void* | |
871 | 6082 | value = mBuilder.CreatePointerCast(value, type->getPointerTo()); // void* = ValueType* | |
872 | |||
873 | mValues.push(value); | ||
874 | 6082 | return true; | |
875 | } | ||
876 | |||
877 | } // namespace codegen_internal | ||
878 | |||
879 | } // namespace codegen | ||
880 | } // namespace ax | ||
881 | } // namespace OPENVDB_VERSION_NAME | ||
882 | } // namespace openvdb | ||
883 | |||
884 |