GCC Code Coverage Report


Directory: ./
File: openvdb_ax/openvdb_ax/codegen/StringFunctions.cc
Date: 2022-07-25 17:40:05
Exec Total Coverage
Lines: 154 157 98.1%
Functions: 14 15 93.3%
Branches: 72 128 56.2%

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