Line | Branch | Exec | Source |
---|---|---|---|
1 | // Copyright Contributors to the OpenVDB Project | ||
2 | // SPDX-License-Identifier: MPL-2.0 | ||
3 | |||
4 | /// @file codegen/StringFunctions.cc | ||
5 | /// | ||
6 | /// @authors Nick Avramoussis | ||
7 | /// | ||
8 | /// @brief A set of internal AX/IR functions for strings | ||
9 | /// | ||
10 | |||
11 | #include "Functions.h" | ||
12 | #include "FunctionTypes.h" | ||
13 | #include "Types.h" | ||
14 | #include "Utils.h" | ||
15 | #include "String.h" | ||
16 | |||
17 | #include "openvdb_ax/compiler/CompilerOptions.h" | ||
18 | |||
19 | namespace openvdb { | ||
20 | OPENVDB_USE_VERSION_NAMESPACE | ||
21 | namespace OPENVDB_VERSION_NAME { | ||
22 | |||
23 | namespace ax { | ||
24 | namespace codegen { | ||
25 | |||
26 | // String | ||
27 | |||
28 | 273 | inline FunctionGroup::UniquePtr axstrlen(const FunctionOptions& op) | |
29 | { | ||
30 | // @todo llvm::emitStrLen(args[1], B, M->getDataLayout()); from llvm/BuildLibCalls.h | ||
31 | // The emitStrLen requires the TargetLibraryInfo class, although this is | ||
32 | // only used to verify that the platform actually has strlen. The main | ||
33 | // benefit of calling this method is for function and parameter attribute | ||
34 | // tagging. TargetLibraryInfo is fairly expensive to construct so should | ||
35 | // be passed by the compiler if we need it | ||
36 | 273 | return FunctionBuilder("strlen") | |
37 |
1/2✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
|
273 | .addSignature<std::size_t(const char*)>(std::strlen, "strlen") |
38 |
2/4✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 273 times.
✗ Branch 5 not taken.
|
546 | .setArgumentNames({"ptr"}) |
39 |
1/2✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
|
273 | .setConstantFold(op.mConstantFoldCBindings) |
40 | .setPreferredImpl(FunctionBuilder::C) | ||
41 | .setDocumentation("strlen") | ||
42 |
1/2✓ Branch 1 taken 273 times.
✗ Branch 2 not taken.
|
546 | .get(); |
43 | } | ||
44 | |||
45 | 441 | inline FunctionGroup::UniquePtr axstringalloc(const FunctionOptions& op) | |
46 | { | ||
47 | auto generate = | ||
48 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | [](const std::vector<llvm::Value*>& args, |
49 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
50 | { | ||
51 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | assert(args.size() == 2); |
52 | llvm::LLVMContext& C = B.getContext(); | ||
53 | llvm::Function* base = B.GetInsertBlock()->getParent(); | ||
54 | 123 | llvm::Type* strType = LLVMType<codegen::String>::get(C); | |
55 | |||
56 | 123 | llvm::Value* str = args[0]; | |
57 | 123 | llvm::Value* size = args[1]; | |
58 | 123 | llvm::Value* cptr = B.CreateStructGEP(strType, str, 0); // char** | |
59 | 123 | llvm::Value* sso = B.CreateStructGEP(strType, str, 1); // char[]* | |
60 | 123 | llvm::Value* sso_load = B.CreateConstGEP2_64(sso, 0 ,0); // char* | |
61 | |||
62 | 123 | llvm::Value* cptr_load = B.CreateLoad(cptr); // char* | |
63 | 123 | llvm::Value* neq = B.CreateICmpNE(cptr_load, sso_load); | |
64 | |||
65 | 123 | llvm::BasicBlock* then = llvm::BasicBlock::Create(C, "then", base); | |
66 | 123 | llvm::BasicBlock* post = llvm::BasicBlock::Create(C, "post", base); | |
67 | 123 | B.CreateCondBr(neq, then, post); | |
68 | 123 | B.SetInsertPoint(then); | |
69 | { | ||
70 | llvm::BasicBlock* BB = B.GetInsertBlock(); | ||
71 | 123 | llvm::Instruction* inst = llvm::CallInst::CreateFree(cptr_load, BB); | |
72 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | assert(inst); |
73 | 123 | B.Insert(inst); | |
74 | 123 | B.CreateBr(post); | |
75 | } | ||
76 | |||
77 | B.SetInsertPoint(post); | ||
78 | |||
79 | 123 | llvm::Value* gt = B.CreateICmpSGT(size, B.getInt64(codegen::String::SSO_LENGTH-1)); | |
80 | |||
81 | 123 | then = llvm::BasicBlock::Create(C, "then", base); | |
82 | 123 | llvm::BasicBlock* el = llvm::BasicBlock::Create(C, "else", base); | |
83 | 123 | post = llvm::BasicBlock::Create(C, "post", base); | |
84 | 123 | B.CreateCondBr(gt, then, el); | |
85 | B.SetInsertPoint(then); | ||
86 | { | ||
87 | llvm::BasicBlock* BB = B.GetInsertBlock(); | ||
88 | llvm::Instruction* inst = | ||
89 | 369 | llvm::CallInst::CreateMalloc(BB, // location | |
90 | B.getInt64Ty(), // int ptr type | ||
91 | B.getInt8Ty(), // return type | ||
92 | 123 | B.CreateAdd(size, B.getInt64(1)), // size | |
93 | nullptr, | ||
94 | nullptr); | ||
95 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 123 times.
|
123 | assert(inst); |
96 | 123 | B.Insert(inst); | |
97 | 123 | B.CreateStore(inst, cptr); | |
98 | 123 | B.CreateBr(post); | |
99 | } | ||
100 | |||
101 | B.SetInsertPoint(el); | ||
102 | { | ||
103 | 123 | B.CreateStore(sso_load, cptr); | |
104 | 123 | B.CreateBr(post); | |
105 | } | ||
106 | |||
107 | B.SetInsertPoint(post); | ||
108 | // re-load cptr | ||
109 | 123 | cptr_load = B.CreateLoad(cptr); // char* | |
110 | 123 | llvm::Value* clast = B.CreateGEP(cptr_load, size); | |
111 | 123 | B.CreateStore(B.getInt8(int8_t('\0')), clast); // this->ptr[size] = '\0'; | |
112 | 123 | llvm::Value* len = B.CreateStructGEP(strType, str, 2); | |
113 | 123 | B.CreateStore(size, len); | |
114 | 123 | return nullptr; | |
115 | }; | ||
116 | |||
117 | static auto stralloc = [](codegen::String* str, const int64_t s) { | ||
118 | str->alloc(s); | ||
119 | }; | ||
120 | |||
121 | 441 | return FunctionBuilder("string::alloc") | |
122 | 882 | .addSignature<void(codegen::String*, const int64_t)>(generate, stralloc) | |
123 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 409 times.
|
441 | .setConstantFold(op.mConstantFoldCBindings) |
124 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 409 times.
|
441 | .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C) |
125 | .setDocumentation("") | ||
126 |
1/2✓ Branch 1 taken 441 times.
✗ Branch 2 not taken.
|
882 | .get(); |
127 | } | ||
128 | |||
129 | 114 | inline FunctionGroup::UniquePtr axstring(const FunctionOptions& op) | |
130 | { | ||
131 | auto generate = | ||
132 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
|
159 | [op](const std::vector<llvm::Value*>& args, |
133 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
134 | { | ||
135 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
|
159 | assert(args.size() >= 1); |
136 | |||
137 | llvm::LLVMContext& C = B.getContext(); | ||
138 | 159 | llvm::Type* strType = LLVMType<codegen::String>::get(C); | |
139 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 85 times.
|
159 | llvm::Value* str = args[0]; |
140 | |||
141 | llvm::Value* carr; | ||
142 |
2/2✓ Branch 0 taken 74 times.
✓ Branch 1 taken 85 times.
|
159 | if (args.size() == 1) carr = B.CreateGlobalStringPtr(""); |
143 | 85 | else carr = args[1]; | |
144 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 159 times.
|
159 | assert(carr); |
145 |
2/4✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 159 times.
✗ Branch 6 not taken.
|
318 | llvm::Value* slen = axstrlen(op)->execute({carr}, B); |
146 | |||
147 | 159 | llvm::Value* cptr = B.CreateStructGEP(strType, str, 0); // char** | |
148 | 159 | llvm::Value* sso = B.CreateStructGEP(strType, str, 1); // char[]* | |
149 | 159 | llvm::Value* sso_load = B.CreateConstGEP2_64(sso, 0 ,0); // char* | |
150 | 159 | llvm::Value* len = B.CreateStructGEP(strType, str, 2); | |
151 | 159 | B.CreateStore(sso_load, cptr); // this->ptr = this->SSO; | |
152 | 159 | B.CreateStore(B.getInt64(0), len); // this->len = 0; | |
153 | |||
154 |
1/2✓ Branch 2 taken 159 times.
✗ Branch 3 not taken.
|
477 | axstringalloc(op)->execute({str, slen}, B); |
155 | |||
156 | 159 | llvm::Value* cptr_load = B.CreateLoad(cptr); | |
157 | #if LLVM_VERSION_MAJOR >= 10 | ||
158 | 159 | B.CreateMemCpy(cptr_load, /*dest-align*/llvm::MaybeAlign(0), | |
159 | carr, /*src-align*/llvm::MaybeAlign(0), slen); | ||
160 | #elif LLVM_VERSION_MAJOR > 6 | ||
161 | B.CreateMemCpy(cptr_load, /*dest-align*/0, carr, /*src-align*/0, slen); | ||
162 | #else | ||
163 | B.CreateMemCpy(cptr_load, carr, slen, /*align*/0); | ||
164 | #endif | ||
165 | 159 | return nullptr; | |
166 | 114 | }; | |
167 | |||
168 | 3184 | static auto strinitc = [](codegen::String* str, const char* c) { | |
169 | 3184 | const int64_t s = std::strlen(c); | |
170 | 3184 | str->ptr = str->SSO; | |
171 | 3184 | str->len = 0; | |
172 | 3184 | str->alloc(s); | |
173 | 3184 | std::memcpy(str->ptr, c, s); | |
174 | 3184 | }; | |
175 | |||
176 | static auto strinit = [](codegen::String* str) { | ||
177 | strinitc(str, ""); | ||
178 | }; | ||
179 | |||
180 | 114 | return FunctionBuilder("string::string") | |
181 | 228 | .addSignature<void(codegen::String*), true>(generate, strinit) | |
182 |
1/4✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✗ Branch 4 not taken.
|
228 | .addSignature<void(codegen::String*, const char*), true>(generate, strinitc) |
183 | // dummy signature for initing an alloced string - use insertStaticAlloca instead | ||
184 | //.addSignature<void(codegen::String*)>(generate) | ||
185 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 82 times.
|
114 | .setConstantFold(op.mConstantFoldCBindings) |
186 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 82 times.
|
114 | .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C) |
187 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
114 | .addDependency("strlen") |
188 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
114 | .addDependency("string::alloc") |
189 | .setDocumentation("") | ||
190 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
228 | .get(); |
191 | } | ||
192 | |||
193 | 55 | inline FunctionGroup::UniquePtr axstringassign(const FunctionOptions& op) | |
194 | { | ||
195 | auto generate = | ||
196 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | [op](const std::vector<llvm::Value*>& args, |
197 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
198 | { | ||
199 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 54 times.
|
54 | assert(args.size() == 2); |
200 | 54 | llvm::Type* strType = LLVMType<codegen::String>::get(B.getContext()); | |
201 | 54 | llvm::Value* str0 = args[0]; | |
202 | 54 | llvm::Value* str1 = args[1]; | |
203 | |||
204 | 54 | llvm::Value* cptr0 = B.CreateStructGEP(strType, str0, 0); | |
205 | 54 | llvm::Value* cptr1 = B.CreateStructGEP(strType, str1, 0); | |
206 | 108 | llvm::Value* len = B.CreateLoad(B.CreateStructGEP(strType, str1, 2)); | |
207 | |||
208 |
2/4✓ Branch 2 taken 54 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 54 times.
✗ Branch 6 not taken.
|
108 | axstringalloc(op)->execute({str0, len}, B); |
209 | |||
210 | 54 | llvm::Value* cptr0_load = B.CreateLoad(cptr0); | |
211 | 54 | llvm::Value* cptr1_load = B.CreateLoad(cptr1); | |
212 | #if LLVM_VERSION_MAJOR >= 10 | ||
213 | 54 | B.CreateMemCpy(cptr0_load, /*dest-align*/llvm::MaybeAlign(0), | |
214 | cptr1_load, /*src-align*/llvm::MaybeAlign(0), len); | ||
215 | #elif LLVM_VERSION_MAJOR > 6 | ||
216 | B.CreateMemCpy(cptr0_load, /*dest-align*/0, cptr1_load, /*src-align*/0, len); | ||
217 | #else | ||
218 | B.CreateMemCpy(cptr0_load, cptr1_load, len, /*align*/0); | ||
219 | #endif | ||
220 | 54 | return nullptr; | |
221 | 55 | }; | |
222 | |||
223 | static auto strassign = [](codegen::String* a, const codegen::String* b) { | ||
224 | *a = *b; | ||
225 | }; | ||
226 | |||
227 | 55 | return FunctionBuilder("string::op=") | |
228 | 110 | .addSignature<void(codegen::String*, const codegen::String*)>(generate, strassign) | |
229 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | .setConstantFold(op.mConstantFoldCBindings) |
230 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 55 times.
|
55 | .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C) |
231 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
55 | .addDependency("string::alloc") |
232 | .setDocumentation("") | ||
233 |
1/2✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
|
110 | .get(); |
234 | } | ||
235 | |||
236 | 26 | inline FunctionGroup::UniquePtr axstringadd(const FunctionOptions& op) | |
237 | { | ||
238 | auto generate = | ||
239 | 25 | [op](const std::vector<llvm::Value*>& args, | |
240 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
241 | { | ||
242 | 25 | llvm::Type* strType = LLVMType<codegen::String>::get(B.getContext()); | |
243 | 25 | llvm::Value* result = args[0]; | |
244 | // don't need to init string as it will have been created with | ||
245 | // insertStaticAlloca which makes sure that cptr=SSO and len=0 | ||
246 | // axstring(op)->execute({result}, B); | ||
247 | |||
248 | 25 | llvm::Value* str0 = args[1]; | |
249 | 25 | llvm::Value* str1 = args[2]; | |
250 | 50 | llvm::Value* len0 = B.CreateLoad(B.CreateStructGEP(strType, str0, 2)); | |
251 | 50 | llvm::Value* len1 = B.CreateLoad(B.CreateStructGEP(strType, str1, 2)); | |
252 | |||
253 | 25 | llvm::Value* total = B.CreateAdd(len0, len1); | |
254 |
2/4✓ Branch 2 taken 25 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 25 times.
✗ Branch 6 not taken.
|
50 | axstringalloc(op)->execute({result, total}, B); |
255 | |||
256 | 50 | llvm::Value* dst = B.CreateLoad(B.CreateStructGEP(strType, result, 0)); //char* | |
257 | 50 | llvm::Value* src0 = B.CreateLoad(B.CreateStructGEP(strType, str0, 0)); //char* | |
258 | 50 | llvm::Value* src1 = B.CreateLoad(B.CreateStructGEP(strType, str1, 0)); //char* | |
259 | |||
260 | // cpy first | ||
261 | #if LLVM_VERSION_MAJOR >= 10 | ||
262 | 25 | B.CreateMemCpy(dst, /*dest-align*/llvm::MaybeAlign(0), | |
263 | src0, /*src-align*/llvm::MaybeAlign(0), len0); | ||
264 | #elif LLVM_VERSION_MAJOR > 6 | ||
265 | B.CreateMemCpy(dst, /*dest-align*/0, src0, /*src-align*/0, len0); | ||
266 | #else | ||
267 | B.CreateMemCpy(dst, src0, len0, /*align*/0); | ||
268 | #endif | ||
269 | |||
270 | // cpy second | ||
271 | 50 | dst = B.CreateGEP(dst, len0); | |
272 | #if LLVM_VERSION_MAJOR >= 10 | ||
273 | 25 | B.CreateMemCpy(dst, /*dest-align*/llvm::MaybeAlign(0), | |
274 | src1, /*src-align*/llvm::MaybeAlign(0), len1); | ||
275 | #elif LLVM_VERSION_MAJOR > 6 | ||
276 | B.CreateMemCpy(dst, /*dest-align*/0, src1, /*src-align*/0, len1); | ||
277 | #else | ||
278 | B.CreateMemCpy(dst, src1, len1, /*align*/0); | ||
279 | #endif | ||
280 | 25 | return nullptr; | |
281 | 26 | }; | |
282 | |||
283 | ✗ | static auto stradd = [](codegen::String* a, const codegen::String* b, const codegen::String* c) { | |
284 | ✗ | *a = *b + *c; | |
285 | ✗ | }; | |
286 | |||
287 | 26 | return FunctionBuilder("string::op+") | |
288 | 52 | .addSignature<void(codegen::String*, const codegen::String*, const codegen::String*), true>(generate, stradd) | |
289 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | .setConstantFold(op.mConstantFoldCBindings) |
290 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 26 times.
|
26 | .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C) |
291 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | .addDependency("string::string") |
292 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
26 | .addDependency("string::alloc") |
293 | .setDocumentation("") | ||
294 |
1/2✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
|
52 | .get(); |
295 | } | ||
296 | |||
297 | 114 | inline FunctionGroup::UniquePtr axstringclear(const FunctionOptions& op) | |
298 | { | ||
299 | auto generate = | ||
300 | 84 | [op](const std::vector<llvm::Value*>& args, | |
301 | llvm::IRBuilder<>& B) -> llvm::Value* | ||
302 | { | ||
303 |
3/6✓ Branch 2 taken 84 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 84 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 84 times.
✗ Branch 9 not taken.
|
168 | axstringalloc(op)->execute({args[0], B.getInt64(0)}, B); |
304 | 84 | return nullptr; | |
305 | 114 | }; | |
306 | |||
307 | static auto strclear = [](codegen::String* a) { a->clear(); }; | ||
308 | |||
309 | 114 | return FunctionBuilder("string::clear") | |
310 | 228 | .addSignature<void(codegen::String*)>(generate, strclear) | |
311 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 82 times.
|
114 | .setConstantFold(op.mConstantFoldCBindings) |
312 |
2/2✓ Branch 0 taken 32 times.
✓ Branch 1 taken 82 times.
|
114 | .setPreferredImpl(op.mPrioritiseIR ? FunctionBuilder::IR : FunctionBuilder::C) |
313 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
114 | .addDependency("string::alloc") |
314 | .setDocumentation("") | ||
315 |
1/2✓ Branch 1 taken 114 times.
✗ Branch 2 not taken.
|
228 | .get(); |
316 | } | ||
317 | |||
318 | |||
319 | /////////////////////////////////////////////////////////////////////////// | ||
320 | /////////////////////////////////////////////////////////////////////////// | ||
321 | |||
322 | |||
323 | 1486 | void insertStringFunctions(FunctionRegistry& registry, | |
324 | const FunctionOptions* options) | ||
325 | { | ||
326 |
3/4✓ Branch 0 taken 1485 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 1485 times.
✗ Branch 3 not taken.
|
1486 | const bool create = options && !options->mLazyFunctions; |
327 | 8916 | auto add = [&](const std::string& name, | |
328 | const FunctionRegistry::ConstructorT creator, | ||
329 | const bool internal = false) | ||
330 | { | ||
331 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 8916 times.
|
8916 | if (create) registry.insertAndCreate(name, creator, *options, internal); |
332 | 8916 | else registry.insert(name, creator, internal); | |
333 | 10402 | }; | |
334 | |||
335 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("strlen", axstrlen, true); |
336 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("string::alloc", axstringalloc, true); |
337 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("string::string", axstring, true); |
338 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("string::op=", axstringassign, true); |
339 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("string::op+", axstringadd, true); |
340 |
2/4✓ Branch 1 taken 1486 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1486 times.
✗ Branch 5 not taken.
|
1486 | add("string::clear", axstringclear, true); |
341 | 1486 | } | |
342 | |||
343 | |||
344 | } // namespace codegen | ||
345 | } // namespace ax | ||
346 | } // namespace OPENVDB_VERSION_NAME | ||
347 | } // namespace openvdb | ||
348 | |||
349 |