| 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 |