1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file codegen/VolumeFunctions.cc
5 ///
6 /// @authors Nick Avramoussis, Richard Jones
7 ///
8 /// @brief  Contains the function objects that define the functions used in
9 ///   volume compute function generation, to be inserted into the FunctionRegistry.
10 ///   These define the functions available when operating on volumes.
11 ///   Also includes the definitions for the volume value retrieval and setting.
12 ///
13 
14 #include "Functions.h"
15 #include "FunctionTypes.h"
16 #include "Types.h"
17 #include "Utils.h"
18 
19 #include "openvdb_ax/compiler/CompilerOptions.h"
20 #include "openvdb_ax/Exceptions.h"
21 
22 #include <openvdb/version.h>
23 
24 #include <unordered_map>
25 #include <cstdlib>
26 #include <cstring>
27 
28 namespace openvdb {
29 OPENVDB_USE_VERSION_NAMESPACE
30 namespace OPENVDB_VERSION_NAME {
31 
32 namespace ax {
33 namespace codegen {
34 
35 
36 namespace {
37 
38 #define OPENVDB_AX_CHECK_MODULE_CONTEXT(B) \
39     { \
40         const llvm::Function* F = B.GetInsertBlock()->getParent(); \
41         const llvm::Module* M = F ? F->getParent() : nullptr; \
42         if (!M || M->getName() != "ax.volume.module") { \
43             OPENVDB_THROW(AXCompilerError, "Function \"" << (F ? F->getName().str() : "unknown") << \
44                 "\" cannot be called for the current target:\"" << (M ? M->getName().str() : "unknown") << \
45                 "\". This function only runs on OpenVDB Grids (not OpenVDB Point Grids)."); \
46         } \
47     }
48 
49 }
50 
axcoordtooffset(const FunctionOptions & op)51 inline FunctionGroup::UniquePtr axcoordtooffset(const FunctionOptions& op)
52 {
53     using LeafNodeT = openvdb::BoolGrid::TreeType::LeafNodeType;
54 
55     /// @warning This function assumes that the node in question is a LeafNode!
56     ///   This means that the result of this method is ONLY correct if the
57     ///   origin points to an existing leaf node, OR if the offset is zero.
58     ///   Currently the VolumeExectuable processes non-leaf nodes (active tiles)
59     ///   individually, so the offset for these nodes is always zero. Should
60     ///   we need to processes a non-leaf node with a non-zero offset, this
61     ///   function should be extended to take a "level" param from the parent
62     ///   which identifies the node level and can thus be used to call the
63     ///   appropriate offset logic.
64 
65     static auto generate = [](const std::vector<llvm::Value*>& args,
66          llvm::IRBuilder<>& B) -> llvm::Value*
67     {
68         assert(args.size() == 1);
69         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
70         llvm::Value* x = B.CreateConstGEP2_64(args[0], 0, 0);
71         llvm::Value* y = B.CreateConstGEP2_64(args[0], 0, 1);
72         llvm::Value* z = B.CreateConstGEP2_64(args[0], 0, 2);
73         llvm::Value* dimmin1 = LLVMType<int32_t>::get(B.getContext(), int32_t(LeafNodeT::DIM-1u));
74         llvm::Value* l2d2 = LLVMType<int32_t>::get(B.getContext(), int32_t(2*LeafNodeT::LOG2DIM));
75         llvm::Value* l2d = LLVMType<int32_t>::get(B.getContext(), int32_t(LeafNodeT::LOG2DIM));
76 
77         // ((xyz[0] & (DIM-1u)) << 2*Log2Dim)
78         x = B.CreateLoad(x);
79         x = binaryOperator(x, dimmin1, ast::tokens::BITAND, B);
80         x = binaryOperator(x, l2d2, ast::tokens::SHIFTLEFT, B);
81 
82         // ((xyz[1] & (DIM-1u)) << Log2Dim)
83         y = B.CreateLoad(y);
84         y = binaryOperator(y, dimmin1, ast::tokens::BITAND, B);
85         y = binaryOperator(y, l2d, ast::tokens::SHIFTLEFT, B);
86 
87         // (xyz[2] & (DIM-1u))
88         z = B.CreateLoad(z);
89         z = binaryOperator(z, dimmin1, ast::tokens::BITAND, B);
90 
91         return
92             binaryOperator(z,
93                 binaryOperator(x, y, ast::tokens::PLUS, B),
94                     ast::tokens::PLUS, B);
95     };
96 
97     static auto coordtooffset =
98         [](const openvdb::math::Vec3<int32_t>* iscoord)
99     {
100         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(iscoord);
101         return int32_t(LeafNodeT::coordToOffset(*ijk));
102     };
103 
104     return FunctionBuilder("coordtooffset")
105         .addSignature<int32_t(const openvdb::math::Vec3<int32_t>*)>(generate,
106                 (int32_t(*)(const openvdb::math::Vec3<int32_t>*))(coordtooffset))
107         .setArgumentNames({"coord"})
108         .addFunctionAttribute(llvm::Attribute::ReadOnly)
109         .addFunctionAttribute(llvm::Attribute::NoRecurse)
110         .addFunctionAttribute(llvm::Attribute::NoUnwind)
111         .addFunctionAttribute(llvm::Attribute::AlwaysInline)
112         .setConstantFold(op.mConstantFoldCBindings)
113         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
114         .setDocumentation("Return the linear table offset of the given global or local coordinates.")
115         .get();
116 }
117 
axoffsettocoord(const FunctionOptions & op)118 inline FunctionGroup::UniquePtr axoffsettocoord(const FunctionOptions& op)
119 {
120     using LeafNodeT = openvdb::BoolGrid::TreeType::LeafNodeType;
121 
122     /// @warning This function assumes that the node in question is a LeafNode!
123     ///   This means that the result of this method is ONLY correct if the
124     ///   origin points to an existing leaf node, OR if the offset is zero.
125     ///   Currently the VolumeExectuable processes non-leaf nodes (active tiles)
126     ///   individually, so the offset for these nodes is always zero. Should
127     ///   we need to processes a non-leaf node with a non-zero offset, this
128     ///   function should be extended to take a "level" param from the parent
129     ///   which identifies the node level and can thus be used to call the
130     ///   appropriate offset logic.
131 
132     static auto generate = [](const std::vector<llvm::Value*>& args,
133          llvm::IRBuilder<>& B) -> llvm::Value*
134     {
135         assert(args.size() == 2);
136         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
137 
138         llvm::Value* ijk = args[0];
139         llvm::Value* offset = args[1];
140 
141         llvm::Value* l2d2 = LLVMType<int32_t>::get(B.getContext(), int32_t(2*LeafNodeT::LOG2DIM));
142         llvm::Value* l2d = LLVMType<int32_t>::get(B.getContext(), int32_t(LeafNodeT::LOG2DIM));
143 
144         // (offset >> 2*Log2Dim)
145         llvm::Value* x = binaryOperator(offset, l2d2, ast::tokens::SHIFTRIGHT, B);
146         B.CreateStore(x, B.CreateConstGEP2_64(ijk, 0, 0));
147 
148         // (offset &= ((1<<2*Log2Dim)-1))
149         static constexpr int32_t ymask = ((1<<2*LeafNodeT::LOG2DIM)-1);
150         offset = binaryOperator(offset, B.getInt32(ymask), ast::tokens::BITAND, B);
151 
152         // (n >> Log2Dim)
153         llvm::Value* y = binaryOperator(offset, l2d, ast::tokens::SHIFTRIGHT, B);
154         B.CreateStore(y, B.CreateConstGEP2_64(ijk, 0, 1));
155 
156         // (n & ((1<<Log2Dim)-1))
157         static constexpr int32_t zmask = ((1<<LeafNodeT::LOG2DIM)-1);
158         llvm::Value* z = binaryOperator(offset, B.getInt32(zmask), ast::tokens::BITAND, B);
159         B.CreateStore(z, B.CreateConstGEP2_64(ijk, 0, 2));
160         return nullptr;
161     };
162 
163     static auto offsetToCoord =
164         [](openvdb::math::Vec3<int32_t>* out, const int32_t offset)
165     {
166         *out = LeafNodeT::offsetToLocalCoord(offset).asVec3i();
167     };
168 
169     using OffsetToCoordT = void(openvdb::math::Vec3<int32_t>*, const int32_t);
170 
171     return FunctionBuilder("offsettocoord")
172         .addSignature<OffsetToCoordT, true>(generate, (OffsetToCoordT*)(offsetToCoord))
173         .setArgumentNames({"offset"})
174         .addParameterAttribute(0, llvm::Attribute::NoAlias)
175         .addParameterAttribute(0, llvm::Attribute::WriteOnly)
176         .addParameterAttribute(0, llvm::Attribute::NoCapture)
177         .addFunctionAttribute(llvm::Attribute::NoUnwind)
178         .addFunctionAttribute(llvm::Attribute::NoRecurse)
179         .addFunctionAttribute(llvm::Attribute::AlwaysInline)
180         .setConstantFold(op.mConstantFoldCBindings)
181         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
182         .setDocumentation("")
183         .get();
184 }
185 
axoffsettoglobalcoord(const FunctionOptions & op)186 inline FunctionGroup::UniquePtr axoffsettoglobalcoord(const FunctionOptions& op)
187 {
188     using LeafNodeT = openvdb::BoolGrid::TreeType::LeafNodeType;
189 
190     /// @warning This function assumes that the node in question is a LeafNode!
191     ///   This means that the result of this method is ONLY correct if the
192     ///   origin points to an existing leaf node, OR if the offset is zero.
193     ///   Currently the VolumeExectuable processes non-leaf nodes (active tiles)
194     ///   individually, so the offset for these nodes is always zero. Should
195     ///   we need to processes a non-leaf node with a non-zero offset, this
196     ///   function should be extended to take a "level" param from the parent
197     ///   which identifies the node level and can thus be used to call the
198     ///   appropriate offset logic.
199 
200     auto generate = [op](const std::vector<llvm::Value*>& args,
201          llvm::IRBuilder<>& B) -> llvm::Value*
202     {
203         assert(args.size() == 3);
204         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
205 
206         llvm::Value* result = args[0];
207         llvm::Value* offset = args[1];
208         llvm::Value* origin = args[2];
209 
210         llvm::Value* local = axoffsettocoord(op)->execute({offset}, B);
211 
212         for (size_t i = 0; i < 3; ++i){
213             llvm::Value* lx = B.CreateConstGEP2_64(local, 0, i);
214             llvm::Value* ox = B.CreateConstGEP2_64(origin, 0, i);
215             ox = binaryOperator(B.CreateLoad(ox), B.CreateLoad(lx), ast::tokens::PLUS, B);
216             B.CreateStore(ox, B.CreateConstGEP2_64(result, 0, i));
217         }
218 
219         return nullptr;
220     };
221 
222     static auto offsetToGlobalCoord =
223         [](openvdb::math::Vec3<int32_t>* out, const int32_t offset, const openvdb::math::Vec3<int32_t>* in)
224     {
225         auto coord = LeafNodeT::offsetToLocalCoord(offset);
226         out->x() = coord.x() + in->x();
227         out->y() = coord.y() + in->y();
228         out->z() = coord.z() + in->z();
229     };
230 
231     using OffsetToGlobalCoordT = void(openvdb::math::Vec3<int32_t>*,const int32_t,const openvdb::math::Vec3<int32_t>*);
232 
233     return FunctionBuilder("offsettoglobalcoord")
234         .addSignature<OffsetToGlobalCoordT, true>(generate, (OffsetToGlobalCoordT*)(offsetToGlobalCoord))
235         .setArgumentNames({"offset", "coord"})
236         .addParameterAttribute(0, llvm::Attribute::NoAlias)
237         .addParameterAttribute(0, llvm::Attribute::WriteOnly)
238         .addParameterAttribute(2, llvm::Attribute::NoAlias)
239         .addParameterAttribute(2, llvm::Attribute::ReadOnly)
240         .addFunctionAttribute(llvm::Attribute::NoUnwind)
241         .addFunctionAttribute(llvm::Attribute::AlwaysInline)
242         .setConstantFold(op.mConstantFoldCBindings)
243         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
244         .setDocumentation("")
245         .get();
246 }
247 
axindextoworld(const FunctionOptions & op)248 inline FunctionGroup::UniquePtr axindextoworld(const FunctionOptions& op)
249 {
250     static auto indexToWorld =
251         [](openvdb::math::Vec3<double>* out,
252            const openvdb::math::Vec3<int32_t>* coord,
253            const void* transform)
254     {
255         const openvdb::math::Transform* const transformPtr =
256                 static_cast<const openvdb::math::Transform*>(transform);
257         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
258         *out = transformPtr->indexToWorld(*ijk);
259     };
260 
261     using IndexToWorldT = void(openvdb::math::Vec3<double>*, const openvdb::math::Vec3<int32_t>*, const void*);
262 
263     return FunctionBuilder("indextoworld")
264         .addSignature<IndexToWorldT, true>((IndexToWorldT*)(indexToWorld))
265         .setArgumentNames({"coord", "transform"})
266         .addParameterAttribute(0, llvm::Attribute::NoAlias)
267         .addParameterAttribute(0, llvm::Attribute::WriteOnly)
268         .addParameterAttribute(1, llvm::Attribute::NoAlias)
269         .addParameterAttribute(1, llvm::Attribute::ReadOnly)
270         .addFunctionAttribute(llvm::Attribute::NoUnwind)
271         .addFunctionAttribute(llvm::Attribute::AlwaysInline)
272         .setConstantFold(false)
273         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
274         .setDocumentation("Converted the given index space coordiante to a world space value based on the currently executing volume.")
275         .get();
276 }
277 
axgetcoord(const FunctionOptions & op)278 inline FunctionGroup::UniquePtr axgetcoord(const FunctionOptions& op)
279 {
280     auto generate = [op](const std::vector<llvm::Value*>&,
281          llvm::IRBuilder<>& B) -> llvm::Value*
282     {
283         // Pull out parent function arguments
284         llvm::Function* compute = B.GetInsertBlock()->getParent();
285         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
286         llvm::Value* origin = extractArgument(compute, "origin");
287         llvm::Value* offset = extractArgument(compute, "offset");
288         return axoffsettoglobalcoord(op)->execute({offset, origin}, B);
289     };
290 
291     return FunctionBuilder("getcoord")
292         .addSignature<openvdb::math::Vec3<int32_t>*()>(generate)
293         .setEmbedIR(true)
294         .setConstantFold(false)
295         .addDependency("offsettoglobalcoord")
296         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
297         .setDocumentation("Returns the current voxel's ijk index space coordiante.")
298         .get();
299 }
300 
301 template <size_t Index>
axgetcoord(const FunctionOptions & op)302 inline FunctionGroup::UniquePtr axgetcoord(const FunctionOptions& op)
303 {
304     static_assert(Index <= 2, "Invalid index for axgetcoord");
305 
306     auto generate = [op](const std::vector<llvm::Value*>&,
307          llvm::IRBuilder<>& B) -> llvm::Value*
308     {
309         llvm::Value* coord = axgetcoord(op)->execute({}, B);
310         return B.CreateLoad(B.CreateConstGEP2_64(coord, 0, Index));
311     };
312 
313     return FunctionBuilder((Index == 0 ? "getcoordx" : Index == 1 ? "getcoordy" : "getcoordz"))
314         .addSignature<int32_t()>(generate)
315         .setEmbedIR(true)
316         .setConstantFold(false)
317         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
318         .addDependency("getcoord")
319         .setDocumentation((
320              Index == 0 ? "Returns the current voxel's X index value in index space as an integer." :
321              Index == 1 ? "Returns the current voxel's Y index value in index space as an integer." :
322                           "Returns the current voxel's Z index value in index space as an integer."))
323         .get();
324 }
325 
axgetvoxelpws(const FunctionOptions & op)326 inline FunctionGroup::UniquePtr axgetvoxelpws(const FunctionOptions& op)
327 {
328     auto generate = [op](const std::vector<llvm::Value*>&,
329          llvm::IRBuilder<>& B) -> llvm::Value*
330     {
331         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
332         llvm::Function* compute = B.GetInsertBlock()->getParent();
333         llvm::Value* transform = extractArgument(compute, "transforms");
334         llvm::Value* wi = extractArgument(compute, "write_index");
335         transform = B.CreateGEP(transform, wi);
336         transform = B.CreateLoad(transform);
337         llvm::Value* coord = axgetcoord(op)->execute({}, B);
338         return axindextoworld(op)->execute({coord, transform}, B);
339     };
340 
341     return FunctionBuilder("getvoxelpws")
342         .addSignature<openvdb::math::Vec3<double>*()>(generate)
343         .setEmbedIR(true)
344         .setConstantFold(false)
345         .addDependency("getcoord")
346         .addDependency("indextoworld")
347         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
348         .setDocumentation("Returns the current voxel's position in world space as a vector float.")
349         .get();
350 }
351 
axisactive(const FunctionOptions & op)352 inline FunctionGroup::UniquePtr axisactive(const FunctionOptions& op)
353 {
354     static auto generate = [](const std::vector<llvm::Value*>&,
355          llvm::IRBuilder<>& B) -> llvm::Value*
356     {
357         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
358         // Pull out parent function arguments
359         llvm::Function* compute = B.GetInsertBlock()->getParent();
360         return extractArgument(compute, "active");
361     };
362 
363     return FunctionBuilder("isactive")
364         .addSignature<bool()>(generate)
365         .setEmbedIR(true)
366         .setConstantFold(false)
367         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
368         .setDocumentation("Returns whether the current voxel or tile is active.")
369         .get();
370 }
371 
axsetvoxel(const FunctionOptions & op)372 inline FunctionGroup::UniquePtr axsetvoxel(const FunctionOptions& op)
373 {
374     static auto setvoxelptr =
375         [](void* accessor,
376            const openvdb::math::Vec3<int32_t>* coord,
377            const int32_t level,
378            const bool ison,
379            const auto value)
380     {
381         using ValueType = typename std::remove_const
382             <typename std::remove_pointer
383                 <decltype(value)>::type>::type;
384         using GridType = typename openvdb::BoolGrid::ValueConverter<ValueType>::Type;
385         using RootNodeType = typename GridType::TreeType::RootNodeType;
386         using AccessorType = typename GridType::Accessor;
387 
388         assert(accessor);
389         assert(coord);
390 
391         // set value only to avoid changing topology
392         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
393         AccessorType* const accessorPtr = static_cast<AccessorType*>(accessor);
394 
395         if (level != -1) {
396             assert(level >= 0);
397             accessorPtr->addTile(Index(level), *ijk, *value, ison);
398         }
399         else {
400             // Check the depth to avoid creating voxel topology for higher levels
401             // @note  This option is not configurable outside of the executable
402             const int depth = accessorPtr->getValueDepth(*ijk);
403             if (depth == static_cast<int>(RootNodeType::LEVEL)) {
404                 // voxel/leaf level
405                 assert(accessorPtr->probeConstLeaf(*ijk));
406                 if (ison) accessorPtr->setValueOn(*ijk, *value);
407                 else      accessorPtr->setValueOff(*ijk, *value);
408             }
409             else {
410                 // If the current depth is not the maximum (i.e voxel/leaf level) then
411                 // we're iterating over tiles of an internal node (NodeT0 is the leaf level).
412                 // We can't call setValueOnly or other variants as this will forcer voxel
413                 // topology to be created. Whilst the VolumeExecutables runs in such a
414                 // way that this is safe, it's not desirable; we just want to change the
415                 // tile value. There is no easy way to do this; we have to set a new tile
416                 // with the same active state.
417                 // @warning This code assume that getValueDepth() is always called to force
418                 // a node cache.
419                 using NodeT1 = typename AccessorType::NodeT1;
420                 using NodeT2 = typename AccessorType::NodeT2;
421                 if (NodeT1* node = accessorPtr->template getNode<NodeT1>()) {
422                     const openvdb::Index index = node->coordToOffset(*ijk);
423                     assert(node->isChildMaskOff(index));
424                     node->addTile(index, *value, ison);
425                 }
426                 else if (NodeT2* node = accessorPtr->template getNode<NodeT2>()) {
427                     const openvdb::Index index = node->coordToOffset(*ijk);
428                     assert(node->isChildMaskOff(index));
429                     node->addTile(index, *value, ison);
430                 }
431                 else {
432                     const int level = RootNodeType::LEVEL - depth;
433                     accessorPtr->addTile(level, *ijk, *value, ison);
434                 }
435             }
436         }
437     };
438 
439     static auto setvoxelstr =
440         [](void* accessor,
441            const openvdb::math::Vec3<int32_t>* coord,
442            const int32_t level,
443            const bool ison,
444            codegen::String* value)
445     {
446         const std::string copy(value->str());
447         setvoxelptr(accessor, coord, level, ison, &copy);
448     };
449 
450     static auto setvoxel =
451         [](void* accessor,
452            const openvdb::math::Vec3<int32_t>* coord,
453            const int32_t level,
454            const bool ison,
455            const auto value) {
456         setvoxelptr(accessor, coord, level, ison, &value);
457     };
458 
459     using SetVoxelD = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const double);
460     using SetVoxelF = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const float);
461     using SetVoxelI64 = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const int64_t);
462     using SetVoxelI32 = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const int32_t);
463     using SetVoxelI16 = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const int16_t);
464     using SetVoxelB = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const bool);
465     using SetVoxelV2D = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec2<double>*);
466     using SetVoxelV2F = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec2<float>*);
467     using SetVoxelV2I = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec2<int32_t>*);
468     using SetVoxelV3D = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec3<double>*);
469     using SetVoxelV3F = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec3<float>*);
470     using SetVoxelV3I = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec3<int32_t>*);
471     using SetVoxelV4D = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec4<double>*);
472     using SetVoxelV4F = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec4<float>*);
473     using SetVoxelV4I = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Vec4<int32_t>*);
474     using SetVoxelM3D = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Mat3<double>*);
475     using SetVoxelM3F = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Mat3<float>*);
476     using SetVoxelM4D = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Mat4<double>*);
477     using SetVoxelM4F = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, const openvdb::math::Mat4<float>*);
478     using SetVoxelStr = void(void*, const openvdb::math::Vec3<int32_t>*, const int32_t, const bool, codegen::String*);
479 
480     return FunctionBuilder("setvoxel")
481         .addSignature<SetVoxelD>((SetVoxelD*)(setvoxel))
482         .addSignature<SetVoxelF>((SetVoxelF*)(setvoxel))
483         .addSignature<SetVoxelI64>((SetVoxelI64*)(setvoxel))
484         .addSignature<SetVoxelI32>((SetVoxelI32*)(setvoxel))
485         .addSignature<SetVoxelI16>((SetVoxelI16*)(setvoxel))
486         .addSignature<SetVoxelB>((SetVoxelB*)(setvoxel))
487             .addParameterAttribute(0, llvm::Attribute::NoAlias)
488             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
489             .addParameterAttribute(0, llvm::Attribute::NoCapture)
490             .addParameterAttribute(1, llvm::Attribute::ReadOnly)
491             .addParameterAttribute(1, llvm::Attribute::NoCapture)
492             .addFunctionAttribute(llvm::Attribute::NoUnwind)
493             .addFunctionAttribute(llvm::Attribute::NoRecurse)
494             .setConstantFold(false)
495         .addSignature<SetVoxelV2D>((SetVoxelV2D*)(setvoxelptr))
496         .addSignature<SetVoxelV2F>((SetVoxelV2F*)(setvoxelptr))
497         .addSignature<SetVoxelV2I>((SetVoxelV2I*)(setvoxelptr))
498         .addSignature<SetVoxelV3D>((SetVoxelV3D*)(setvoxelptr))
499         .addSignature<SetVoxelV3F>((SetVoxelV3F*)(setvoxelptr))
500         .addSignature<SetVoxelV3I>((SetVoxelV3I*)(setvoxelptr))
501         .addSignature<SetVoxelV4D>((SetVoxelV4D*)(setvoxelptr))
502         .addSignature<SetVoxelV4F>((SetVoxelV4F*)(setvoxelptr))
503         .addSignature<SetVoxelV4I>((SetVoxelV4I*)(setvoxelptr))
504         .addSignature<SetVoxelM3D>((SetVoxelM3D*)(setvoxelptr))
505         .addSignature<SetVoxelM3F>((SetVoxelM3F*)(setvoxelptr))
506         .addSignature<SetVoxelM4D>((SetVoxelM4D*)(setvoxelptr))
507         .addSignature<SetVoxelM4F>((SetVoxelM4F*)(setvoxelptr))
508         .addSignature<SetVoxelStr>((SetVoxelStr*)(setvoxelstr))
509             .addParameterAttribute(0, llvm::Attribute::NoAlias)
510             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
511             .addParameterAttribute(0, llvm::Attribute::NoCapture)
512             .addParameterAttribute(1, llvm::Attribute::ReadOnly)
513             .addParameterAttribute(1, llvm::Attribute::NoCapture)
514             .addParameterAttribute(4, llvm::Attribute::NoAlias)
515             .addParameterAttribute(4, llvm::Attribute::ReadOnly)
516             .addParameterAttribute(4, llvm::Attribute::NoCapture)
517             .addFunctionAttribute(llvm::Attribute::NoUnwind)
518             .addFunctionAttribute(llvm::Attribute::NoRecurse)
519             .setConstantFold(false)
520         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
521         .setDocumentation("Internal function for setting the value of a voxel.")
522         .get();
523 }
524 
axgetvoxel(const FunctionOptions & op)525 inline FunctionGroup::UniquePtr axgetvoxel(const FunctionOptions& op)
526 {
527     static auto getvoxel =
528         [](void* accessor,
529            const openvdb::math::Vec3<int32_t>* coord,
530            auto value)
531     {
532         using ValueType = typename std::remove_pointer<decltype(value)>::type;
533         using GridType = typename openvdb::BoolGrid::ValueConverter<ValueType>::Type;
534         using AccessorType = typename GridType::Accessor;
535 
536         assert(accessor);
537         assert(coord);
538         assert(value);
539 
540         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
541         (*value) = static_cast<const AccessorType*>(accessor)->getValue(*ijk);
542     };
543 
544     static auto getvoxelstr =
545         [](void* accessor,
546            const openvdb::math::Vec3<int32_t>* coord,
547            codegen::String* value)
548     {
549         using GridType = openvdb::BoolGrid::ValueConverter<std::string>::Type;
550         using AccessorType = GridType::Accessor;
551 
552         assert(accessor);
553         assert(coord);
554         assert(value);
555 
556         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
557         const std::string& str = static_cast<const AccessorType*>(accessor)->getValue(*ijk);
558         // Copy the string to AX's required representation
559         *value = str;
560     };
561 
562     static auto getvoxel_s2t =
563         [](void* accessor,
564            void* sourceTransform,
565            void* targetTransform,
566            const openvdb::math::Vec3<int32_t>* origin,
567            const int32_t offset,
568            auto value)
569     {
570         using ValueType = typename std::remove_pointer<decltype(value)>::type;
571         using GridType = typename openvdb::BoolGrid::ValueConverter<ValueType>::Type;
572         using LeafNodeT = typename GridType::TreeType::LeafNodeType;
573         using AccessorType = typename GridType::Accessor;
574 
575         assert(accessor);
576         assert(origin);
577         assert(sourceTransform);
578         assert(targetTransform);
579 
580         const AccessorType* const accessorPtr = static_cast<const AccessorType*>(accessor);
581         const openvdb::math::Transform* const sourceTransformPtr =
582                 static_cast<const openvdb::math::Transform*>(sourceTransform);
583         const openvdb::math::Transform* const targetTransformPtr =
584                 static_cast<const openvdb::math::Transform*>(targetTransform);
585 
586         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(origin);
587         auto coord = *ijk + LeafNodeT::offsetToLocalCoord(offset);
588         coord = targetTransformPtr->worldToIndexCellCentered(sourceTransformPtr->indexToWorld(coord));
589         (*value) = accessorPtr->getValue(coord);
590     };
591 
592     static auto getvoxelstr_s2t =
593         [](void* accessor,
594            void* sourceTransform,
595            void* targetTransform,
596            const openvdb::math::Vec3<int32_t>* origin,
597            const int32_t offset,
598            codegen::String* value)
599     {
600         using GridType = typename openvdb::BoolGrid::ValueConverter<std::string>::Type;
601         using LeafNodeT = typename GridType::TreeType::LeafNodeType;
602         using AccessorType = typename GridType::Accessor;
603 
604         assert(accessor);
605         assert(origin);
606         assert(sourceTransform);
607         assert(targetTransform);
608 
609         const AccessorType* const accessorPtr = static_cast<const AccessorType*>(accessor);
610         const openvdb::math::Transform* const sourceTransformPtr =
611                 static_cast<const openvdb::math::Transform*>(sourceTransform);
612         const openvdb::math::Transform* const targetTransformPtr =
613                 static_cast<const openvdb::math::Transform*>(targetTransform);
614 
615         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(origin);
616         auto coord = *ijk + LeafNodeT::offsetToLocalCoord(offset);
617         coord = targetTransformPtr->worldToIndexCellCentered(sourceTransformPtr->indexToWorld(coord));
618         const std::string& str = accessorPtr->getValue(coord);
619         // Copy the string to AX's required representation
620         *value = str;
621     };
622 
623     using GetVoxelS2T_D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, double*);
624     using GetVoxelS2T_F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, float*);
625     using GetVoxelS2T_I64 = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, int64_t*);
626     using GetVoxelS2T_I32 = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, int32_t*);
627     using GetVoxelS2T_I16 = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, int16_t*);
628     using GetVoxelS2T_B = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, bool*);
629     using GetVoxelS2T_V2D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec2<double>*);
630     using GetVoxelS2T_V2F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec2<float>*);
631     using GetVoxelS2T_V2I = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec2<int32_t>*);
632     using GetVoxelS2T_V3D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec3<double>*);
633     using GetVoxelS2T_V3F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec3<float>*);
634     using GetVoxelS2T_V3I = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec3<int32_t>*);
635     using GetVoxelS2T_V4D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec4<double>*);
636     using GetVoxelS2T_V4F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec4<float>*);
637     using GetVoxelS2T_V4I = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Vec4<int32_t>*);
638     using GetVoxelS2T_M3D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Mat3<double>*);
639     using GetVoxelS2T_M3F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Mat3<float>*);
640     using GetVoxelS2T_M4D = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Mat4<double>*);
641     using GetVoxelS2T_M4F = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, openvdb::math::Mat4<float>*);
642     using GetVoxelS2T_Str = void(void*, void*, void*, const openvdb::math::Vec3<int32_t>*, int32_t, codegen::String*);
643 
644     using GetVoxelD = void(void*, const openvdb::math::Vec3<int32_t>*, double*);
645     using GetVoxelF = void(void*, const openvdb::math::Vec3<int32_t>*, float*);
646     using GetVoxelI64 = void(void*, const openvdb::math::Vec3<int32_t>*, int64_t*);
647     using GetVoxelI32 = void(void*, const openvdb::math::Vec3<int32_t>*, int32_t*);
648     using GetVoxelI16 = void(void*, const openvdb::math::Vec3<int32_t>*, int16_t*);
649     using GetVoxelB = void(void*, const openvdb::math::Vec3<int32_t>*, bool*);
650     using GetVoxelV2D = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec2<double>*);
651     using GetVoxelV2F = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec2<float>*);
652     using GetVoxelV2I = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec2<int32_t>*);
653     using GetVoxelV3D = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec3<double>*);
654     using GetVoxelV3F = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec3<float>*);
655     using GetVoxelV3I = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec3<int32_t>*);
656     using GetVoxelV4D = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec4<double>*);
657     using GetVoxelV4F = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec4<float>*);
658     using GetVoxelV4I = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Vec4<int32_t>*);
659     using GetVoxelM3D = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Mat3<double>*);
660     using GetVoxelM3F = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Mat3<float>*);
661     using GetVoxelM4D = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Mat4<double>*);
662     using GetVoxelM4F = void(void*, const openvdb::math::Vec3<int32_t>*, openvdb::math::Mat4<float>*);
663     using GetVoxelStr = void(void*, const openvdb::math::Vec3<int32_t>*, codegen::String*);
664 
665     return FunctionBuilder("getvoxel")
666         .addSignature<GetVoxelD>((GetVoxelD*)(getvoxel))
667         .addSignature<GetVoxelF>((GetVoxelF*)(getvoxel))
668         .addSignature<GetVoxelI64>((GetVoxelI64*)(getvoxel))
669         .addSignature<GetVoxelI32>((GetVoxelI32*)(getvoxel))
670         .addSignature<GetVoxelI16>((GetVoxelI16*)(getvoxel))
671         .addSignature<GetVoxelB>((GetVoxelB*)(getvoxel))
672         .addSignature<GetVoxelV2D>((GetVoxelV2D*)(getvoxel))
673         .addSignature<GetVoxelV2F>((GetVoxelV2F*)(getvoxel))
674         .addSignature<GetVoxelV2I>((GetVoxelV2I*)(getvoxel))
675         .addSignature<GetVoxelV3D>((GetVoxelV3D*)(getvoxel))
676         .addSignature<GetVoxelV3F>((GetVoxelV3F*)(getvoxel))
677         .addSignature<GetVoxelV3I>((GetVoxelV3I*)(getvoxel))
678         .addSignature<GetVoxelV4D>((GetVoxelV4D*)(getvoxel))
679         .addSignature<GetVoxelV4F>((GetVoxelV4F*)(getvoxel))
680         .addSignature<GetVoxelV4I>((GetVoxelV4I*)(getvoxel))
681         .addSignature<GetVoxelM3F>((GetVoxelM3F*)(getvoxel))
682         .addSignature<GetVoxelM3D>((GetVoxelM3D*)(getvoxel))
683         .addSignature<GetVoxelM4F>((GetVoxelM4F*)(getvoxel))
684         .addSignature<GetVoxelM4D>((GetVoxelM4D*)(getvoxel))
685         .addSignature<GetVoxelStr>((GetVoxelStr*)(getvoxelstr))
686             .addParameterAttribute(0, llvm::Attribute::NoAlias)
687             .addParameterAttribute(1, llvm::Attribute::NoAlias)
688             .addParameterAttribute(1, llvm::Attribute::ReadOnly)
689             .addParameterAttribute(2, llvm::Attribute::WriteOnly)
690             .addParameterAttribute(2, llvm::Attribute::NoAlias)
691             .addFunctionAttribute(llvm::Attribute::NoUnwind)
692             .addFunctionAttribute(llvm::Attribute::NoRecurse)
693             .setConstantFold(false)
694         .addSignature<GetVoxelS2T_D>((GetVoxelS2T_D*)(getvoxel_s2t))
695         .addSignature<GetVoxelS2T_F>((GetVoxelS2T_F*)(getvoxel_s2t))
696         .addSignature<GetVoxelS2T_I64>((GetVoxelS2T_I64*)(getvoxel_s2t))
697         .addSignature<GetVoxelS2T_I32>((GetVoxelS2T_I32*)(getvoxel_s2t))
698         .addSignature<GetVoxelS2T_I16>((GetVoxelS2T_I16*)(getvoxel_s2t))
699         .addSignature<GetVoxelS2T_B>((GetVoxelS2T_B*)(getvoxel_s2t))
700         .addSignature<GetVoxelS2T_V2D>((GetVoxelS2T_V2D*)(getvoxel_s2t))
701         .addSignature<GetVoxelS2T_V2F>((GetVoxelS2T_V2F*)(getvoxel_s2t))
702         .addSignature<GetVoxelS2T_V2I>((GetVoxelS2T_V2I*)(getvoxel_s2t))
703         .addSignature<GetVoxelS2T_V3D>((GetVoxelS2T_V3D*)(getvoxel_s2t))
704         .addSignature<GetVoxelS2T_V3F>((GetVoxelS2T_V3F*)(getvoxel_s2t))
705         .addSignature<GetVoxelS2T_V3I>((GetVoxelS2T_V3I*)(getvoxel_s2t))
706         .addSignature<GetVoxelS2T_V4D>((GetVoxelS2T_V4D*)(getvoxel_s2t))
707         .addSignature<GetVoxelS2T_V4F>((GetVoxelS2T_V4F*)(getvoxel_s2t))
708         .addSignature<GetVoxelS2T_V4I>((GetVoxelS2T_V4I*)(getvoxel_s2t))
709         .addSignature<GetVoxelS2T_M3F>((GetVoxelS2T_M3F*)(getvoxel_s2t))
710         .addSignature<GetVoxelS2T_M3D>((GetVoxelS2T_M3D*)(getvoxel_s2t))
711         .addSignature<GetVoxelS2T_M4F>((GetVoxelS2T_M4F*)(getvoxel_s2t))
712         .addSignature<GetVoxelS2T_M4D>((GetVoxelS2T_M4D*)(getvoxel_s2t))
713         .addSignature<GetVoxelS2T_Str>((GetVoxelS2T_Str*)(getvoxelstr_s2t))
714             .addParameterAttribute(0, llvm::Attribute::NoAlias)
715             .addParameterAttribute(1, llvm::Attribute::NoAlias)
716             .addParameterAttribute(1, llvm::Attribute::ReadOnly)
717             .addParameterAttribute(2, llvm::Attribute::ReadOnly)
718             .addParameterAttribute(3, llvm::Attribute::WriteOnly)
719             .addParameterAttribute(3, llvm::Attribute::NoAlias)
720             .addFunctionAttribute(llvm::Attribute::NoUnwind)
721             .addFunctionAttribute(llvm::Attribute::NoRecurse)
722             .setConstantFold(false)
723         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
724         .setDocumentation("Internal function for setting the value of a voxel.")
725         .get();
726 }
727 
axprobevalue(const FunctionOptions & op)728 inline FunctionGroup::UniquePtr axprobevalue(const FunctionOptions& op)
729 {
730     static auto probe =
731         [](void* accessor,
732            const openvdb::math::Vec3<int32_t>* coord,
733            bool* ison,
734            auto value)
735     {
736         using ValueType = typename std::remove_pointer<decltype(value)>::type;
737         using GridType = typename openvdb::BoolGrid::ValueConverter<ValueType>::Type;
738         using AccessorType = typename GridType::Accessor;
739 
740         assert(accessor);
741         assert(coord);
742         assert(value);
743         assert(ison);
744 
745         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
746         *ison = static_cast<const AccessorType*>(accessor)->probeValue(*ijk, *value);
747     };
748 
749     static auto probestr =
750         [](void* accessor,
751            const openvdb::math::Vec3<int32_t>* coord,
752            bool* ison,
753            codegen::String* value)
754     {
755         using GridType = openvdb::BoolGrid::ValueConverter<std::string>::Type;
756         using AccessorType = GridType::Accessor;
757 
758         assert(accessor);
759         assert(coord);
760         assert(value);
761         assert(ison);
762 
763         const openvdb::Coord* ijk = reinterpret_cast<const openvdb::Coord*>(coord);
764 
765         std::string str;
766         *ison = static_cast<const AccessorType*>(accessor)->probeValue(*ijk, str);
767         // Copy the string to AX's required representation
768         *value = str;
769     };
770 
771     using ProbeValueD = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, double*);
772     using ProbeValueF = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, float*);
773     using ProbeValueI64 = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, int64_t*);
774     using ProbeValueI32 = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, int32_t*);
775     using ProbeValueI16 = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, int16_t*);
776     using ProbeValueB = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, bool*);
777     using ProbeValueV2D = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec2<double>*);
778     using ProbeValueV2F = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec2<float>*);
779     using ProbeValueV2I = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec2<int32_t>*);
780     using ProbeValueV3D = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec3<double>*);
781     using ProbeValueV3F = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec3<float>*);
782     using ProbeValueV3I = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec3<int32_t>*);
783     using ProbeValueV4D = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec4<double>*);
784     using ProbeValueV4F = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec4<float>*);
785     using ProbeValueV4I = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Vec4<int32_t>*);
786     using ProbeValueM3D = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Mat3<double>*);
787     using ProbeValueM3F = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Mat3<float>*);
788     using ProbeValueM4D = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Mat4<double>*);
789     using ProbeValueM4F = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, openvdb::math::Mat4<float>*);
790     using ProbeValueStr = void(void*, const openvdb::math::Vec3<int32_t>*, bool*, codegen::String*);
791 
792     return FunctionBuilder("probevalue")
793         .addSignature<ProbeValueD>((ProbeValueD*)(probe))
794         .addSignature<ProbeValueF>((ProbeValueF*)(probe))
795         .addSignature<ProbeValueI64>((ProbeValueI64*)(probe))
796         .addSignature<ProbeValueI32>((ProbeValueI32*)(probe))
797         .addSignature<ProbeValueI16>((ProbeValueI16*)(probe))
798         .addSignature<ProbeValueB>((ProbeValueB*)(probe))
799         .addSignature<ProbeValueV2D>((ProbeValueV2D*)(probe))
800         .addSignature<ProbeValueV2F>((ProbeValueV2F*)(probe))
801         .addSignature<ProbeValueV2I>((ProbeValueV2I*)(probe))
802         .addSignature<ProbeValueV3D>((ProbeValueV3D*)(probe))
803         .addSignature<ProbeValueV3F>((ProbeValueV3F*)(probe))
804         .addSignature<ProbeValueV3I>((ProbeValueV3I*)(probe))
805         .addSignature<ProbeValueV4D>((ProbeValueV4D*)(probe))
806         .addSignature<ProbeValueV4F>((ProbeValueV4F*)(probe))
807         .addSignature<ProbeValueV4I>((ProbeValueV4I*)(probe))
808         .addSignature<ProbeValueM3F>((ProbeValueM3F*)(probe))
809         .addSignature<ProbeValueM3D>((ProbeValueM3D*)(probe))
810         .addSignature<ProbeValueM4F>((ProbeValueM4F*)(probe))
811         .addSignature<ProbeValueM4D>((ProbeValueM4D*)(probe))
812         .addSignature<ProbeValueStr>((ProbeValueStr*)(probestr))
813             .addParameterAttribute(0, llvm::Attribute::NoAlias)
814             .addParameterAttribute(1, llvm::Attribute::NoAlias)
815             .addParameterAttribute(1, llvm::Attribute::ReadOnly)
816             .addParameterAttribute(2, llvm::Attribute::WriteOnly)
817             .addParameterAttribute(2, llvm::Attribute::NoAlias)
818             .addParameterAttribute(3, llvm::Attribute::WriteOnly)
819             .addParameterAttribute(3, llvm::Attribute::NoAlias)
820             .addFunctionAttribute(llvm::Attribute::NoUnwind)
821             .addFunctionAttribute(llvm::Attribute::NoRecurse)
822             .setConstantFold(false)
823         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
824         .setDocumentation("Internal function for getting the value of a voxel and its active state.")
825         .get();
826 }
827 
828 ////////////////////////////////////////////////////////////////////////
829 ////////////////////////////////////////////////////////////////////////
830 
insertVDBVolumeFunctions(FunctionRegistry & registry,const FunctionOptions * options)831 void insertVDBVolumeFunctions(FunctionRegistry& registry,
832     const FunctionOptions* options)
833 {
834     const bool create = options && !options->mLazyFunctions;
835     auto add = [&](const std::string& name,
836         const FunctionRegistry::ConstructorT creator,
837         const bool internal = false)
838     {
839         if (create) registry.insertAndCreate(name, creator, *options, internal);
840         else        registry.insert(name, creator, internal);
841     };
842 
843     // volume functions
844 
845     add("coordtooffset", axcoordtooffset, true);
846     add("offsettocoord", axoffsettocoord, true);
847     add("offsettoglobalcoord", axoffsettoglobalcoord, true);
848     add("indextoworld", axindextoworld, true);
849 
850     add("getcoord", axgetcoord);
851     add("getcoordx", axgetcoord<0>);
852     add("getcoordy", axgetcoord<1>);
853     add("getcoordz", axgetcoord<2>);
854     add("getvoxelpws", axgetvoxelpws);
855     add("isactive", axisactive, true); // needs tests
856 
857     add("getvoxel", axgetvoxel, true);
858     add("setvoxel", axsetvoxel, true);
859     add("probevalue", axprobevalue, true);
860 }
861 
862 } // namespace codegen
863 } // namespace ax
864 } // namespace OPENVDB_VERSION_NAME
865 } // namespace openvdb
866 
867