1 // Copyright Contributors to the OpenVDB Project
2 // SPDX-License-Identifier: MPL-2.0
3 
4 /// @file codegen/PointFunctions.cc
5 ///
6 /// @authors Nick Avramoussis, Richard Jones
7 ///
8 /// @brief  Contains the function objects that define the functions used in
9 ///   point compute function generation, to be inserted into the
10 ///   FunctionRegistry. These define the functions available when operating
11 ///   on points. Also includes the definitions for the point attribute
12 ///   retrieval and setting.
13 ///
14 
15 #include "Functions.h"
16 #include "FunctionTypes.h"
17 #include "Types.h"
18 #include "Utils.h"
19 #include "PointLeafLocalData.h"
20 
21 #include "../ast/Tokens.h"
22 #include "../compiler/CompilerOptions.h"
23 #include "../Exceptions.h"
24 
25 #include <openvdb/openvdb.h>
26 #include <openvdb/points/PointDataGrid.h>
27 
28 #include <unordered_map>
29 
30 namespace openvdb {
31 OPENVDB_USE_VERSION_NAMESPACE
32 namespace OPENVDB_VERSION_NAME {
33 
34 namespace ax {
35 namespace codegen {
36 
37 namespace
38 {
39 
40 #define OPENVDB_AX_CHECK_MODULE_CONTEXT(B) \
41     { \
42         const llvm::Function* F = B.GetInsertBlock()->getParent(); \
43         const llvm::Module* M = F ? F->getParent() : nullptr; \
44         if (!M || M->getName() != "ax.point.module") { \
45             OPENVDB_THROW(AXCompilerError, "Function \"" << (F ? F->getName().str() : "unknown") << \
46                 "\" cannot be called for the current target:\"" << (M ? M->getName().str() : "unknown") << \
47                 "\". This function only runs on OpenVDB Point Grids."); \
48         } \
49     }
50 
51 /// @brief  Retrieve a group handle from an expected vector of handles using the offset
52 ///         pointed to by the engine data. Note that HandleT should only ever be a GroupHandle
53 ///         or GroupWriteHandle object
54 template <typename HandleT>
55 inline HandleT*
groupHandle(const std::string & name,void ** groupHandles,const void * const data)56 groupHandle(const std::string& name, void** groupHandles, const void* const data)
57 {
58     const openvdb::points::AttributeSet* const attributeSet =
59         static_cast<const openvdb::points::AttributeSet*>(data);
60 
61     const size_t groupIdx = attributeSet->groupOffset(name);
62     if (groupIdx == openvdb::points::AttributeSet::INVALID_POS) return nullptr;
63 
64     return static_cast<HandleT*>(groupHandles[groupIdx]);
65 }
66 
67 }
68 
ax_ingroup(const FunctionOptions & op)69 inline FunctionGroup::UniquePtr ax_ingroup(const FunctionOptions& op)
70 {
71     static auto ingroup =
72         [](const codegen::String* const name,
73            const uint64_t index,
74            void** groupHandles,
75            const void* const leafDataPtr,
76            const void* const data) -> bool
77     {
78         assert(name);
79         assert(index < static_cast<uint64_t>(std::numeric_limits<openvdb::Index>::max()));
80 
81         if (name->size() == 0) return false;
82         if (!groupHandles) return false;
83 
84         const std::string nameStr = name->str();
85         const openvdb::points::GroupHandle* handle =
86             groupHandle<openvdb::points::GroupHandle>(nameStr, groupHandles, data);
87         if (handle) return handle->get(static_cast<openvdb::Index>(index));
88 
89         // If the handle doesn't exist, check to see if any new groups have
90         // been added
91         const codegen_internal::PointLeafLocalData* const leafData =
92             static_cast<const codegen_internal::PointLeafLocalData*>(leafDataPtr);
93         handle = leafData->get(nameStr);
94         return handle ? handle->get(static_cast<openvdb::Index>(index)) : false;
95     };
96 
97     using InGroup = bool(const codegen::String* const,
98        const uint64_t,
99        void**,
100        const void* const,
101        const void* const);
102 
103     return FunctionBuilder("_ingroup")
104         .addSignature<InGroup>(ingroup)
105         .addParameterAttribute(0, llvm::Attribute::ReadOnly)
106         .addParameterAttribute(2, llvm::Attribute::ReadOnly)
107         .addParameterAttribute(2, llvm::Attribute::NoAlias)
108         .addParameterAttribute(3, llvm::Attribute::ReadOnly)
109         .addParameterAttribute(3, llvm::Attribute::NoAlias)
110         .addParameterAttribute(4, llvm::Attribute::ReadOnly)
111         .addParameterAttribute(4, llvm::Attribute::NoAlias)
112         .addFunctionAttribute(llvm::Attribute::ReadOnly)
113         .addFunctionAttribute(llvm::Attribute::NoRecurse)
114         // @note  handle->get can throw, so no unwind. Maybe use getUnsafe?
115         .setConstantFold(false)
116         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
117         .setDocumentation("Internal function for querying point group data")
118         .get();
119 }
120 
axingroup(const FunctionOptions & op)121 inline FunctionGroup::UniquePtr axingroup(const FunctionOptions& op)
122 {
123     static auto generate =
124         [op](const std::vector<llvm::Value*>& args,
125              llvm::IRBuilder<>& B) -> llvm::Value*
126     {
127         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
128         // Pull out parent function arguments
129         llvm::Function* compute = B.GetInsertBlock()->getParent();
130         llvm::Value* point_index = extractArgument(compute, "point_index");
131         llvm::Value* group_handles = extractArgument(compute, "group_handles");
132         llvm::Value* leaf_data = extractArgument(compute, "leaf_data");
133         llvm::Value* attribute_set = extractArgument(compute, "attribute_set");
134         assert(point_index);
135         assert(group_handles);
136         assert(leaf_data);
137         assert(attribute_set);
138 
139         std::vector<llvm::Value*> input(args);
140         input.emplace_back(point_index);
141         input.emplace_back(group_handles);
142         input.emplace_back(leaf_data);
143         input.emplace_back(attribute_set);
144         return ax_ingroup(op)->execute(input, B);
145     };
146 
147     return FunctionBuilder("ingroup")
148         .addSignature<bool(const codegen::String* const)>(generate)
149         .addDependency("_ingroup")
150         .setEmbedIR(true)
151         .setConstantFold(false)
152         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
153         .setDocumentation( "Return whether or not the current point is "
154             "a member of the given group name. This returns false if the group does "
155             "not exist.")
156         .get();
157 }
158 
axeditgroup(const FunctionOptions & op)159 inline FunctionGroup::UniquePtr axeditgroup(const FunctionOptions& op)
160 {
161     static auto editgroup =
162         [](const codegen::String* const name,
163            const uint64_t index,
164            void** groupHandles,
165            void* const leafDataPtr,
166            const void* const data,
167            const bool flag)
168     {
169         assert(name);
170         if (name->size() == 0) return;
171 
172         // Get the group handle out of the pre-existing container of handles if they
173         // exist
174 
175         const std::string nameStr = name->str();
176         openvdb::points::GroupWriteHandle* handle = nullptr;
177         if (groupHandles) {
178             handle = groupHandle<openvdb::points::GroupWriteHandle>(nameStr, groupHandles, data);
179         }
180 
181         if (!handle) {
182             codegen_internal::PointLeafLocalData* const leafData =
183                 static_cast<codegen_internal::PointLeafLocalData*>(leafDataPtr);
184 
185             // If we are setting membership and the handle doesn't exist, create in in
186             // the set of new data thats being added
187             if (!flag && !leafData->hasGroup(nameStr)) return;
188             handle = leafData->getOrInsert(nameStr);
189             assert(handle);
190         }
191 
192         // set the group membership
193         handle->set(static_cast<openvdb::Index>(index), flag);
194     };
195 
196     static auto editgroupcstar =
197         [](const char* const name,
198            const uint64_t index,
199            void** groupHandles,
200            void* const leafDataPtr,
201            const void* const data,
202            const bool flag)
203     {
204         const codegen::String str(name);
205         editgroup(&str, index, groupHandles, leafDataPtr, data, flag);
206     };
207 
208     using EditGroup = void(const codegen::String* const,
209            const uint64_t,
210            void**,
211            void* const,
212            const void* const,
213            const bool);
214 
215     using EditGroupCstar = void(const char* const,
216            const uint64_t,
217            void**,
218            void* const,
219            const void* const,
220            const bool);
221 
222     return FunctionBuilder("editgroup")
223         .addSignature<EditGroup>(editgroup)
224         .addSignature<EditGroupCstar>(editgroupcstar)
225         .addParameterAttribute(0, llvm::Attribute::ReadOnly)
226         .addParameterAttribute(2, llvm::Attribute::ReadOnly)
227         .addParameterAttribute(3, llvm::Attribute::ReadOnly)
228         .addParameterAttribute(4, llvm::Attribute::ReadOnly)
229         .setConstantFold(false)
230         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
231         .setDocumentation("Internal function for setting point group data")
232         .get();
233 }
234 
axaddtogroup(const FunctionOptions & op)235 inline FunctionGroup::UniquePtr axaddtogroup(const FunctionOptions& op)
236 {
237     static auto generate =
238         [op](const std::vector<llvm::Value*>& args,
239              llvm::IRBuilder<>& B) -> llvm::Value*
240     {
241         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
242         // Pull out parent function arguments
243         llvm::Function* compute = B.GetInsertBlock()->getParent();
244         llvm::Value* point_index = extractArgument(compute, "point_index");
245         llvm::Value* group_handles = extractArgument(compute, "group_handles");
246         llvm::Value* leaf_data = extractArgument(compute, "leaf_data");
247         llvm::Value* attribute_set = extractArgument(compute, "attribute_set");
248         assert(point_index);
249         assert(group_handles);
250         assert(leaf_data);
251         assert(attribute_set);
252 
253         std::vector<llvm::Value*> input(args);
254         input.emplace_back(point_index);
255         input.emplace_back(group_handles);
256         input.emplace_back(leaf_data);
257         input.emplace_back(attribute_set);
258         input.emplace_back(llvm::ConstantInt::get(LLVMType<bool>::get(B.getContext()), true));
259         return axeditgroup(op)->execute(input, B);
260     };
261 
262     return FunctionBuilder("addtogroup")
263         .addSignature<void(const codegen::String* const)>(generate)
264         .addSignature<void(const char* const)>(generate) // to support axdeletepoint() @todo fix
265         .addDependency("editgroup")
266         .setEmbedIR(true)
267         .setConstantFold(false)
268         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
269         .setDocumentation("Add the current point to the given group "
270             "name, effectively setting its membership to true. If the group does not "
271             "exist, it is implicitly created. This function has no effect if the point "
272             "already belongs to the given group.")
273         .get();
274 }
275 
axremovefromgroup(const FunctionOptions & op)276 inline FunctionGroup::UniquePtr axremovefromgroup(const FunctionOptions& op)
277 {
278     static auto generate =
279         [op](const std::vector<llvm::Value*>& args,
280              llvm::IRBuilder<>& B) -> llvm::Value*
281     {
282         // Pull out parent function arguments
283         OPENVDB_AX_CHECK_MODULE_CONTEXT(B);
284         llvm::Function* compute = B.GetInsertBlock()->getParent();
285         llvm::Value* point_index = extractArgument(compute, "point_index");
286         llvm::Value* group_handles = extractArgument(compute, "group_handles");
287         llvm::Value* leaf_data = extractArgument(compute, "leaf_data");
288         llvm::Value* attribute_set = extractArgument(compute, "attribute_set");
289         assert(point_index);
290         assert(group_handles);
291         assert(leaf_data);
292         assert(attribute_set);
293 
294         std::vector<llvm::Value*> input(args);
295         input.emplace_back(point_index);
296         input.emplace_back(group_handles);
297         input.emplace_back(leaf_data);
298         input.emplace_back(attribute_set);
299         input.emplace_back(llvm::ConstantInt::get(LLVMType<bool>::get(B.getContext()), false));
300         return axeditgroup(op)->execute(input, B);
301     };
302 
303     return FunctionBuilder("removefromgroup")
304         .addSignature<void(const codegen::String* const)>(generate)
305         .addDependency("editgroup")
306         .setEmbedIR(true)
307         .setConstantFold(false)
308         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
309         .setDocumentation("Remove the current point from the "
310             "given group name, effectively setting its membership to false. This "
311             "function has no effect if the group does not exist.")
312         .get();
313 }
314 
axdeletepoint(const FunctionOptions & op)315 inline FunctionGroup::UniquePtr axdeletepoint(const FunctionOptions& op)
316 {
317     static auto generate =
318         [op](const std::vector<llvm::Value*>&,
319              llvm::IRBuilder<>& B) -> llvm::Value*
320     {
321         // args guaranteed to be empty
322         const std::string deadGroup = "__ax_dead";
323         llvm::Constant* loc = llvm::cast<llvm::Constant>(B.CreateGlobalStringPtr(deadGroup.c_str())); // char*
324         return axaddtogroup(op)->execute({loc}, B);
325     };
326 
327     return FunctionBuilder("deletepoint")
328         .addSignature<void()>(generate)
329         .addDependency("addtogroup")
330         .addFunctionAttribute(llvm::Attribute::AlwaysInline)
331         .setEmbedIR(true) // axaddtogroup needs access to parent function arguments
332         .setConstantFold(false)
333         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
334         .setDocumentation("Delete the current point from the point set. Note that this does not "
335             "stop AX execution - any additional AX commands will be executed on the "
336             "point and it will remain accessible until the end of execution.")
337         .get();
338 }
339 
axsetattribute(const FunctionOptions & op)340 inline FunctionGroup::UniquePtr axsetattribute(const FunctionOptions& op)
341 {
342     static auto setattribptr =
343         [](void* attributeHandle, uint64_t index, const auto value)
344     {
345         using ValueType = typename std::remove_const
346             <typename std::remove_pointer
347                 <decltype(value)>::type>::type;
348         using AttributeHandleType = openvdb::points::AttributeWriteHandle<ValueType>;
349 
350         assert(attributeHandle);
351         assert(value);
352         assert(index < static_cast<uint64_t>(std::numeric_limits<openvdb::Index>::max()));
353 
354         AttributeHandleType* handle = static_cast<AttributeHandleType*>(attributeHandle);
355         handle->set(static_cast<openvdb::Index>(index), *value);
356     };
357 
358     static auto setattribstr =
359         [](void* attributeHandle,
360            const uint64_t index,
361            const codegen::String* value,
362            void* const leafDataPtr)
363     {
364         using AttributeHandleType = openvdb::points::StringAttributeWriteHandle;
365 
366         assert(attributeHandle);
367         assert(value);
368         assert(leafDataPtr);
369         assert(index < static_cast<uint64_t>(std::numeric_limits<openvdb::Index>::max()));
370 
371         const std::string s = value->str();
372         AttributeHandleType* const handle =
373             static_cast<AttributeHandleType*>(attributeHandle);
374         codegen_internal::PointLeafLocalData* const leafData =
375             static_cast<codegen_internal::PointLeafLocalData*>(leafDataPtr);
376 
377         // Check to see if the string exists in the metadata cache. If so, set the string and
378         // remove any new data associated with it, otherwise set the new data
379 
380         if (handle->contains(s)) {
381             handle->set(static_cast<openvdb::Index>(index), s);
382             leafData->removeNewStringData(&(handle->array()), index);
383         }
384         else {
385             leafData->setNewStringData(&(handle->array()), index, s);
386         }
387     };
388 
389     static auto setattrib =
390         [](void* attributeHandle,
391            uint64_t index,
392            const auto value) {
393         setattribptr(attributeHandle, index, &value);
394     };
395 
396     using SetAttribD = void(void*, uint64_t, const double);
397     using SetAttribF = void(void*, uint64_t, const float);
398     using SetAttribI64 = void(void*, uint64_t, const int64_t);
399     using SetAttribI32 = void(void*, uint64_t, const int32_t);
400     using SetAttribI16 = void(void*, uint64_t, const int16_t);
401     using SetAttribB = void(void*, uint64_t, const bool);
402     using SetAttribV2D = void(void*, uint64_t, const openvdb::math::Vec2<double>*);
403     using SetAttribV2F = void(void*, uint64_t, const openvdb::math::Vec2<float>*);
404     using SetAttribV2I = void(void*, uint64_t, const openvdb::math::Vec2<int32_t>*);
405     using SetAttribV3D = void(void*, uint64_t, const openvdb::math::Vec3<double>*);
406     using SetAttribV3F = void(void*, uint64_t, const openvdb::math::Vec3<float>*);
407     using SetAttribV3I = void(void*, uint64_t, const openvdb::math::Vec3<int32_t>*);
408     using SetAttribV4D = void(void*, uint64_t, const openvdb::math::Vec4<double>*);
409     using SetAttribV4F = void(void*, uint64_t, const openvdb::math::Vec4<float>*);
410     using SetAttribV4I = void(void*, uint64_t, const openvdb::math::Vec4<int32_t>*);
411     using SetAttribM3D = void(void*, uint64_t, const openvdb::math::Mat3<double>*);
412     using SetAttribM3F = void(void*, uint64_t, const openvdb::math::Mat3<float>*);
413     using SetAttribM4D = void(void*, uint64_t, const openvdb::math::Mat4<double>*);
414     using SetAttribM4F = void(void*, uint64_t, const openvdb::math::Mat4<float>*);
415     using SetAttribStr = void(void*, uint64_t, const codegen::String*, void* const);
416 
417     return FunctionBuilder("setattribute")
418         .addSignature<SetAttribD>((SetAttribD*)(setattrib))
419         .addSignature<SetAttribF>((SetAttribF*)(setattrib))
420         .addSignature<SetAttribI64>((SetAttribI64*)(setattrib))
421         .addSignature<SetAttribI32>((SetAttribI32*)(setattrib))
422         .addSignature<SetAttribI16>((SetAttribI16*)(setattrib))
423         .addSignature<SetAttribB>((SetAttribB*)(setattrib))
424             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
425             .addFunctionAttribute(llvm::Attribute::NoRecurse)
426             .setConstantFold(false)
427         .addSignature<SetAttribV2D>((SetAttribV2D*)(setattribptr))
428         .addSignature<SetAttribV2F>((SetAttribV2F*)(setattribptr))
429         .addSignature<SetAttribV2I>((SetAttribV2I*)(setattribptr))
430         .addSignature<SetAttribV3D>((SetAttribV3D*)(setattribptr))
431         .addSignature<SetAttribV3F>((SetAttribV3F*)(setattribptr))
432         .addSignature<SetAttribV3I>((SetAttribV3I*)(setattribptr))
433         .addSignature<SetAttribV4D>((SetAttribV4D*)(setattribptr))
434         .addSignature<SetAttribV4F>((SetAttribV4F*)(setattribptr))
435         .addSignature<SetAttribV4I>((SetAttribV4I*)(setattribptr))
436         .addSignature<SetAttribM3D>((SetAttribM3D*)(setattribptr))
437         .addSignature<SetAttribM3F>((SetAttribM3F*)(setattribptr))
438         .addSignature<SetAttribM4D>((SetAttribM4D*)(setattribptr))
439         .addSignature<SetAttribM4F>((SetAttribM4F*)(setattribptr))
440             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
441             .addParameterAttribute(2, llvm::Attribute::ReadOnly)
442             .addFunctionAttribute(llvm::Attribute::NoRecurse)
443             .setConstantFold(false)
444         .addSignature<SetAttribStr>((SetAttribStr*)(setattribstr))
445             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
446             .addParameterAttribute(2, llvm::Attribute::ReadOnly)
447             .addParameterAttribute(3, llvm::Attribute::ReadOnly)
448             .addFunctionAttribute(llvm::Attribute::NoRecurse)
449             .setConstantFold(false)
450         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
451         .setDocumentation("Internal function for setting the value of a point attribute.")
452         .get();
453 }
454 
axgetattribute(const FunctionOptions & op)455 inline FunctionGroup::UniquePtr axgetattribute(const FunctionOptions& op)
456 {
457     static auto getattrib =
458         [](void* attributeHandle, uint64_t index, auto value)
459     {
460         using ValueType = typename std::remove_const
461             <typename std::remove_pointer
462                 <decltype(value)>::type>::type;
463         // typedef is a read handle. As write handles are derived types this
464         // is okay and lets us define the handle types outside IR for attributes that are
465         // only being read!
466         using AttributeHandleType = openvdb::points::AttributeHandle<ValueType>;
467 
468         assert(value);
469         assert(attributeHandle);
470         assert(index < static_cast<uint64_t>(std::numeric_limits<openvdb::Index>::max()));
471 
472         AttributeHandleType* handle = static_cast<AttributeHandleType*>(attributeHandle);
473         (*value) = handle->get(static_cast<openvdb::Index>(index));
474     };
475 
476     static auto getattribstr =
477         [](void* attributeHandle,
478            uint64_t index,
479            codegen::String* value,
480            const void* const leafDataPtr)
481     {
482         using AttributeHandleType = openvdb::points::StringAttributeHandle;
483 
484         assert(value);
485         assert(attributeHandle);
486         assert(leafDataPtr);
487         assert(index < static_cast<uint64_t>(std::numeric_limits<openvdb::Index>::max()));
488 
489         AttributeHandleType* const handle =
490             static_cast<AttributeHandleType*>(attributeHandle);
491         const codegen_internal::PointLeafLocalData* const leafData =
492             static_cast<const codegen_internal::PointLeafLocalData*>(leafDataPtr);
493 
494         std::string data;
495         if (!leafData->getNewStringData(&(handle->array()), index, data)) {
496             handle->get(data, static_cast<openvdb::Index>(index));
497         }
498 
499         *value = data;
500     };
501 
502     using GetAttribD = void(void*, uint64_t, double*);
503     using GetAttribF = void(void*, uint64_t, float*);
504     using GetAttribI64 = void(void*, uint64_t, int64_t*);
505     using GetAttribI32 = void(void*, uint64_t, int32_t*);
506     using GetAttribI16 = void(void*, uint64_t, int16_t*);
507     using GetAttribB = void(void*, uint64_t, bool*);
508     using GetAttribV2D = void(void*, uint64_t, openvdb::math::Vec2<double>*);
509     using GetAttribV2F = void(void*, uint64_t, openvdb::math::Vec2<float>*);
510     using GetAttribV2I = void(void*, uint64_t, openvdb::math::Vec2<int32_t>*);
511     using GetAttribV3D = void(void*, uint64_t, openvdb::math::Vec3<double>*);
512     using GetAttribV3F = void(void*, uint64_t, openvdb::math::Vec3<float>*);
513     using GetAttribV3I = void(void*, uint64_t, openvdb::math::Vec3<int32_t>*);
514     using GetAttribV4D = void(void*, uint64_t, openvdb::math::Vec4<double>*);
515     using GetAttribV4F = void(void*, uint64_t, openvdb::math::Vec4<float>*);
516     using GetAttribV4I = void(void*, uint64_t, openvdb::math::Vec4<int32_t>*);
517     using GetAttribM3D = void(void*, uint64_t, openvdb::math::Mat3<double>*);
518     using GetAttribM3F = void(void*, uint64_t, openvdb::math::Mat3<float>*);
519     using GetAttribM4D = void(void*, uint64_t, openvdb::math::Mat4<double>*);
520     using GetAttribM4F = void(void*, uint64_t, openvdb::math::Mat4<float>*);
521     using GetAttribStr = void(void*, uint64_t, codegen::String*, const void* const);
522 
523     return FunctionBuilder("getattribute")
524         .addSignature<GetAttribD>((GetAttribD*)(getattrib))
525         .addSignature<GetAttribF>((GetAttribF*)(getattrib))
526         .addSignature<GetAttribI64>((GetAttribI64*)(getattrib))
527         .addSignature<GetAttribI32>((GetAttribI32*)(getattrib))
528         .addSignature<GetAttribI16>((GetAttribI16*)(getattrib))
529         .addSignature<GetAttribB>((GetAttribB*)(getattrib))
530         .addSignature<GetAttribV2D>((GetAttribV2D*)(getattrib))
531         .addSignature<GetAttribV2F>((GetAttribV2F*)(getattrib))
532         .addSignature<GetAttribV2I>((GetAttribV2I*)(getattrib))
533         .addSignature<GetAttribV3D>((GetAttribV3D*)(getattrib))
534         .addSignature<GetAttribV3F>((GetAttribV3F*)(getattrib))
535         .addSignature<GetAttribV3I>((GetAttribV3I*)(getattrib))
536         .addSignature<GetAttribV4D>((GetAttribV4D*)(getattrib))
537         .addSignature<GetAttribV4F>((GetAttribV4F*)(getattrib))
538         .addSignature<GetAttribV4I>((GetAttribV4I*)(getattrib))
539         .addSignature<GetAttribM3D>((GetAttribM3D*)(getattrib))
540         .addSignature<GetAttribM3F>((GetAttribM3F*)(getattrib))
541         .addSignature<GetAttribM4D>((GetAttribM4D*)(getattrib))
542         .addSignature<GetAttribM4F>((GetAttribM4F*)(getattrib))
543             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
544             .addFunctionAttribute(llvm::Attribute::NoRecurse)
545             .setConstantFold(false)
546         .addSignature<GetAttribStr>((GetAttribStr*)(getattribstr))
547             .addParameterAttribute(0, llvm::Attribute::ReadOnly)
548             .addParameterAttribute(3, llvm::Attribute::ReadOnly)
549             .addFunctionAttribute(llvm::Attribute::NoRecurse)
550             .setConstantFold(false)
551         .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C)
552         .setDocumentation("Internal function for getting the value of a point attribute.")
553         .get();
554 }
555 
556 
557 ////////////////////////////////////////////////////////////////////////
558 ////////////////////////////////////////////////////////////////////////
559 
560 
insertVDBPointFunctions(FunctionRegistry & registry,const FunctionOptions * options)561 void insertVDBPointFunctions(FunctionRegistry& registry,
562     const FunctionOptions* options)
563 {
564     const bool create = options && !options->mLazyFunctions;
565     auto add = [&](const std::string& name,
566         const FunctionRegistry::ConstructorT creator,
567         const bool internal = false)
568     {
569         if (create) registry.insertAndCreate(name, creator, *options, internal);
570         else        registry.insert(name, creator, internal);
571     };
572 
573     // point functions
574 
575     add("addtogroup", axaddtogroup);
576     add("ingroup", axingroup);
577     add("removefromgroup",axremovefromgroup);
578     add("deletepoint", axdeletepoint);
579     add("_ingroup", ax_ingroup, true);
580     add("editgroup", axeditgroup, true);
581     add("getattribute", axgetattribute, true);
582     add("setattribute", axsetattribute, true);
583 }
584 
585 } // namespace codegen
586 } // namespace ax
587 } // namespace openvdb_version
588 } // namespace openvdb
589 
590 
591