GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.4% 380 / 6 / 396
Functions: 95.5% 42 / 0 / 44
Branches: 62.6% 443 / 20 / 728

src/irgenerator/IRGenerator.cpp
Line Branch Exec Source
1 // Copyright (c) 2021-2026 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <SourceFile.h>
6 #include <driver/Driver.h>
7 #include <global/GlobalResourceManager.h>
8 #include <symboltablebuilder/SymbolTableBuilder.h>
9 #include <typechecker/FunctionManager.h>
10
11 #include <llvm/IR/Module.h>
12 #include <llvm/IR/Verifier.h>
13
14 namespace spice::compiler {
15
16 1734 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
17 1734 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
18
1/2
✓ Branch 8 → 9 taken 1734 times.
✗ Branch 8 → 65 not taken.
1734 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
19
6/10
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 1732 times.
✓ Branch 9 → 10 taken 1734 times.
✗ Branch 9 → 65 not taken.
✓ Branch 10 → 11 taken 1734 times.
✗ Branch 10 → 65 not taken.
✓ Branch 11 → 12 taken 1734 times.
✗ Branch 11 → 63 not taken.
✓ Branch 15 → 16 taken 1734 times.
✗ Branch 15 → 59 not taken.
3468 stdFunctionManager(sourceFile, resourceManager, module) {
20 // Attach information to the module
21
1/2
✓ Branch 17 → 18 taken 1734 times.
✗ Branch 17 → 44 not taken.
1734 module->setTargetTriple(cliOptions.targetTriple);
22
2/4
✓ Branch 21 → 22 taken 1734 times.
✗ Branch 21 → 47 not taken.
✓ Branch 22 → 23 taken 1734 times.
✗ Branch 22 → 45 not taken.
1734 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
23
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 1733 times.
1734 if (cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY) {
24
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 55 not taken.
1 module->setPICLevel(llvm::PICLevel::SmallPIC);
25
1/2
✓ Branch 26 → 29 taken 1 time.
✗ Branch 26 → 55 not taken.
1 module->setPIELevel(llvm::PIELevel::Default);
26 } else {
27
1/2
✓ Branch 27 → 28 taken 1733 times.
✗ Branch 27 → 55 not taken.
1733 module->setPICLevel(llvm::PICLevel::BigPIC);
28
1/2
✓ Branch 28 → 29 taken 1733 times.
✗ Branch 28 → 55 not taken.
1733 module->setPIELevel(llvm::PIELevel::Large);
29 }
30
1/2
✓ Branch 29 → 30 taken 1734 times.
✗ Branch 29 → 55 not taken.
1734 module->setUwtable(llvm::UWTableKind::Default);
31
1/2
✓ Branch 30 → 31 taken 1734 times.
✗ Branch 30 → 55 not taken.
1734 module->setFramePointer(llvm::FramePointerKind::All);
32
33 // Add module identifier metadata
34
2/4
✓ Branch 31 → 32 taken 1734 times.
✗ Branch 31 → 48 not taken.
✓ Branch 32 → 33 taken 1734 times.
✗ Branch 32 → 48 not taken.
1734 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
35
3/6
✓ Branch 34 → 35 taken 1734 times.
✗ Branch 34 → 49 not taken.
✓ Branch 36 → 37 taken 1734 times.
✗ Branch 36 → 49 not taken.
✓ Branch 37 → 38 taken 1734 times.
✗ Branch 37 → 49 not taken.
1734 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
36
37 // Initialize debug info generator
38
2/2
✓ Branch 38 → 39 taken 24 times.
✓ Branch 38 → 43 taken 1710 times.
1734 if (cliOptions.instrumentation.generateDebugInfo)
39
2/4
✓ Branch 39 → 40 taken 24 times.
✗ Branch 39 → 54 not taken.
✓ Branch 40 → 41 taken 24 times.
✗ Branch 40 → 52 not taken.
24 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
40 1734 }
41
42 1734 std::any IRGenerator::visitEntry(const EntryNode *node) {
43 // Generate IR
44
1/2
✓ Branch 2 → 3 taken 1734 times.
✗ Branch 2 → 28 not taken.
1734 visitChildren(node);
45
46 // Generate test main if required
47
4/4
✓ Branch 4 → 5 taken 336 times.
✓ Branch 4 → 7 taken 1398 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 332 times.
1734 if (sourceFile->isMainFile && cliOptions.generateTestMain)
48 4 generateTestMain();
49
50 // Execute deferred VTable initializations
51
2/2
✓ Branch 21 → 9 taken 1459 times.
✓ Branch 21 → 22 taken 1734 times.
4927 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
52
1/2
✓ Branch 11 → 12 taken 1459 times.
✗ Branch 11 → 29 not taken.
1459 deferredVTableInit.execute();
53
54 // Finalize debug info generator
55 1734 diGenerator.finalize();
56
57 // Verify module
58 1734 verifyModule(node->codeLoc);
59
60
1/2
✓ Branch 24 → 25 taken 1734 times.
✗ Branch 24 → 30 not taken.
3468 return nullptr;
61 }
62
63 85340 llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, const std::string &varName) {
64
2/2
✓ Branch 2 → 3 taken 60436 times.
✓ Branch 2 → 10 taken 24904 times.
85340 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
65
2/4
✓ Branch 3 → 4 taken 60436 times.
✗ Branch 3 → 23 not taken.
✓ Branch 4 → 5 taken 60436 times.
✗ Branch 4 → 23 not taken.
60436 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
66
1/2
✓ Branch 6 → 7 taken 60436 times.
✗ Branch 6 → 24 not taken.
60436 allocaInst->setDebugLoc(llvm::DebugLoc());
67 60436 allocaInst->moveAfter(allocaInsertInst);
68 60436 allocaInsertInst = allocaInst;
69 } else { // This is the first alloca inst in the current function -> insert at the entry block
70 // Save current basic block and move insert cursor to entry block of the current function
71 24904 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
72 24904 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
73
74 // Allocate the size of the given LLVM type
75
2/4
✓ Branch 13 → 14 taken 24904 times.
✗ Branch 13 → 27 not taken.
✓ Branch 14 → 15 taken 24904 times.
✗ Branch 14 → 27 not taken.
24904 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
76
1/2
✓ Branch 16 → 17 taken 24904 times.
✗ Branch 16 → 28 not taken.
24904 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
77
78 // Restore old basic block
79 24904 builder.SetInsertPoint(currentBlock);
80 }
81
82 // Insert lifetime start marker
83
2/2
✓ Branch 19 → 20 taken 54 times.
✓ Branch 19 → 21 taken 85286 times.
85340 if (cliOptions.useLifetimeMarkers)
84 54 builder.CreateLifetimeStart(allocaInsertInst);
85
86 85340 return allocaInsertInst;
87 }
88
89 71473 llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) {
90 71473 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
91 71473 llvm::AllocaInst *alloca = insertAlloca(llvmType, varName);
92
93 // Insert type metadata
94
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 4 → 6 taken 71464 times.
71473 if (cliOptions.useTBAAMetadata)
95 9 mdGenerator.generateTypeMetadata(allocaInsertInst, qualType);
96
97 71473 return alloca;
98 }
99
100 162145 llvm::LoadInst *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile,
101 const std::string &varName) const {
102
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 162145 times.
162145 assert(ptr->getType()->isPointerTy());
103
2/4
✓ Branch 6 → 7 taken 162145 times.
✗ Branch 6 → 11 not taken.
✓ Branch 7 → 8 taken 162145 times.
✗ Branch 7 → 11 not taken.
162145 return builder.CreateLoad(llvmType, ptr, isVolatile, varName);
104 }
105
106 142375 llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) {
107 142375 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
108 142375 llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName);
109
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 142369 times.
142375 if (cliOptions.useTBAAMetadata)
110 6 mdGenerator.generateTBAAMetadata(load, qualType);
111 142375 return load;
112 }
113
114 86866 llvm::StoreInst *IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const {
115
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 86866 times.
86866 assert(ptr->getType()->isPointerTy());
116 86866 return builder.CreateStore(val, ptr, isVolatile);
117 }
118
119 25291 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) {
120 25291 llvm::StoreInst *store = insertStore(val, ptr, isVolatile);
121
2/2
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 25282 times.
25291 if (cliOptions.useTBAAMetadata)
122 9 mdGenerator.generateTBAAMetadata(store, qualType);
123 25291 }
124
125 42668 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
126 const std::string &varName) const {
127
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 42668 times.
42668 assert(basePtr->getType()->isPointerTy());
128
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 42668 times.
42668 assert(!indices.empty());
129
4/6
✓ Branch 4 → 5 taken 42122 times.
✓ Branch 4 → 7 taken 38782 times.
✓ Branch 6 → 7 taken 42122 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 42668 times.
123572 assert(std::ranges::all_of(indices, [](const llvm::Value *index) {
130 const llvm::Type *indexType = index->getType();
131 return indexType->isIntegerTy(32) || indexType->isIntegerTy(64);
132 }));
133
134 // Insert GEP
135
2/4
✓ Branch 12 → 13 taken 42668 times.
✗ Branch 12 → 17 not taken.
✓ Branch 13 → 14 taken 42668 times.
✗ Branch 13 → 17 not taken.
42668 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
136 }
137
138 16659 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index,
139 const std::string &varName) const {
140
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 16659 times.
16659 assert(basePtr->getType()->isPointerTy());
141
142 // If we use index 0 we can use the base pointer directly
143
2/2
✓ Branch 6 → 7 taken 4899 times.
✓ Branch 6 → 8 taken 11760 times.
16659 if (index == 0)
144 4899 return basePtr;
145
146 // Insert GEP
147
2/4
✓ Branch 8 → 9 taken 11760 times.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 11760 times.
✗ Branch 9 → 13 not taken.
11760 return builder.CreateStructGEP(type, basePtr, index, varName);
148 }
149
150 92292 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
151 // Visit the given AST node
152
2/4
✓ Branch 2 → 3 taken 92292 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 92292 times.
✗ Branch 3 → 9 not taken.
92292 auto exprResult = any_cast<LLVMExprResult>(visit(node));
153
1/2
✓ Branch 5 → 6 taken 92292 times.
✗ Branch 5 → 12 not taken.
184584 return resolveValue(node, exprResult);
154 }
155
156 102243 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) {
157 102243 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
158 }
159
160 199649 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) {
161 // Check if the value is already present
162
2/2
✓ Branch 2 → 3 taken 63809 times.
✓ Branch 2 → 4 taken 135840 times.
199649 if (exprResult.value != nullptr)
163 63809 return exprResult.value;
164
165 // Check if a constant is present
166
2/2
✓ Branch 4 → 5 taken 38277 times.
✓ Branch 4 → 7 taken 97563 times.
135840 if (exprResult.constant != nullptr) {
167 38277 materializeConstant(exprResult);
168 38277 return exprResult.value;
169 }
170
171
3/4
✓ Branch 7 → 8 taken 1279 times.
✓ Branch 7 → 10 taken 96284 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1279 times.
97563 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
172
173 // De-reference if reference type
174
4/4
✓ Branch 10 → 11 taken 89973 times.
✓ Branch 10 → 13 taken 7590 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 89966 times.
97563 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
175
4/4
✓ Branch 14 → 15 taken 1289 times.
✓ Branch 14 → 24 taken 96274 times.
✓ Branch 15 → 16 taken 1279 times.
✓ Branch 15 → 24 taken 10 times.
97563 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
176
2/4
✓ Branch 19 → 20 taken 1279 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 1279 times.
✗ Branch 20 → 34 not taken.
1279 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
177
178 // Load the value from the pointer
179
1/2
✓ Branch 24 → 25 taken 97563 times.
✗ Branch 24 → 46 not taken.
97563 const QualType referencedType = qualType.removeReferenceWrapper();
180
1/2
✓ Branch 28 → 29 taken 97563 times.
✗ Branch 28 → 40 not taken.
97563 exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile);
181
182 97563 return exprResult.value;
183 }
184
185 8988 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
186 // Visit the given AST node
187
2/4
✓ Branch 2 → 3 taken 8988 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 8988 times.
✗ Branch 3 → 9 not taken.
8988 auto exprResult = any_cast<LLVMExprResult>(visit(node));
188
1/2
✓ Branch 5 → 6 taken 8988 times.
✗ Branch 5 → 12 not taken.
17976 return resolveAddress(exprResult);
189 }
190
191 67843 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
192 // Check if an address is already present
193
2/2
✓ Branch 2 → 3 taken 56428 times.
✓ Branch 2 → 4 taken 11415 times.
67843 if (exprResult.ptr != nullptr)
194 56428 return exprResult.ptr;
195
196 // Check if the reference address is already present
197
3/4
✓ Branch 4 → 5 taken 8644 times.
✓ Branch 4 → 7 taken 2771 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 8644 times.
11415 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
198
3/4
✓ Branch 8 → 9 taken 9203 times.
✓ Branch 8 → 18 taken 2212 times.
✓ Branch 9 → 10 taken 9203 times.
✗ Branch 9 → 18 not taken.
11415 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
199
2/4
✓ Branch 13 → 14 taken 9203 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 9203 times.
✗ Branch 14 → 35 not taken.
9203 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
200 9203 return exprResult.ptr;
201 }
202
203 // If not, store the value or constant
204 2212 materializeConstant(exprResult);
205
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 2212 times.
2212 assert(exprResult.value != nullptr);
206
7/12
✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 2206 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 2206 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 2212 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 2206 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
4418 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
207 2212 insertStore(exprResult.value, exprResult.ptr, isVolatile);
208
209 2212 return exprResult.ptr;
210 }
211
212 5659 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
213 // Double
214
2/2
✓ Branch 3 → 4 taken 10 times.
✓ Branch 3 → 9 taken 5649 times.
5659 if (symbolType.is(TY_DOUBLE))
215
2/4
✓ Branch 4 → 5 taken 10 times.
✗ Branch 4 → 132 not taken.
✓ Branch 5 → 6 taken 10 times.
✗ Branch 5 → 130 not taken.
10 return llvm::ConstantFP::get(context, llvm::APFloat(0.0));
216
217 // Int
218
2/2
✓ Branch 10 → 11 taken 656 times.
✓ Branch 10 → 13 taken 4993 times.
5649 if (symbolType.is(TY_INT))
219 656 return builder.getInt32(0);
220
221 // Short
222
2/2
✓ Branch 14 → 15 taken 9 times.
✓ Branch 14 → 17 taken 4984 times.
4993 if (symbolType.is(TY_SHORT))
223 9 return builder.getInt16(0);
224
225 // Long
226
2/2
✓ Branch 18 → 19 taken 1964 times.
✓ Branch 18 → 21 taken 3020 times.
4984 if (symbolType.is(TY_LONG))
227 1964 return builder.getInt64(0);
228
229 // Byte or char
230
3/4
✓ Branch 21 → 22 taken 3020 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 40 times.
✓ Branch 22 → 25 taken 2980 times.
3020 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
231 40 return builder.getInt8(0);
232
233 // String
234
2/2
✓ Branch 26 → 27 taken 642 times.
✓ Branch 26 → 35 taken 2338 times.
2980 if (symbolType.is(TY_STRING)) {
235
3/6
✓ Branch 27 → 28 taken 642 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 642 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 642 times.
✗ Branch 29 → 134 not taken.
642 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
236
1/2
✓ Branch 30 → 31 taken 642 times.
✗ Branch 30 → 34 not taken.
642 if (cliOptions.comparableOutput)
237
2/4
✓ Branch 31 → 32 taken 642 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 642 times.
✗ Branch 32 → 136 not taken.
642 globalString->setAlignment(llvm::Align(4));
238 642 return globalString;
239 }
240
241 // Bool
242
2/2
✓ Branch 36 → 37 taken 72 times.
✓ Branch 36 → 39 taken 2266 times.
2338 if (symbolType.is(TY_BOOL))
243 72 return builder.getFalse();
244
245 // Pointer or reference
246
3/4
✓ Branch 39 → 40 taken 2266 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 2178 times.
✓ Branch 40 → 44 taken 88 times.
2266 if (symbolType.isOneOf({TY_PTR, TY_REF}))
247 2178 return llvm::Constant::getNullValue(builder.getPtrTy());
248
249 // Array
250
2/2
✓ Branch 45 → 46 taken 14 times.
✓ Branch 45 → 61 taken 74 times.
88 if (symbolType.isArray()) {
251 // Get array size
252
1/2
✓ Branch 46 → 47 taken 14 times.
✗ Branch 46 → 146 not taken.
14 const size_t arraySize = symbolType.getArraySize();
253
254 // Get default value for item
255
2/4
✓ Branch 47 → 48 taken 14 times.
✗ Branch 47 → 138 not taken.
✓ Branch 48 → 49 taken 14 times.
✗ Branch 48 → 138 not taken.
14 llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained());
256
257 // Retrieve array and item type
258
2/4
✓ Branch 49 → 50 taken 14 times.
✗ Branch 49 → 139 not taken.
✓ Branch 50 → 51 taken 14 times.
✗ Branch 50 → 139 not taken.
14 llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile);
259
1/2
✓ Branch 51 → 52 taken 14 times.
✗ Branch 51 → 146 not taken.
14 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize);
260
261 // Create a constant array with n times the default value
262
1/2
✓ Branch 54 → 55 taken 14 times.
✗ Branch 54 → 140 not taken.
28 const std::vector itemConstants(arraySize, defaultItemValue);
263
1/2
✓ Branch 57 → 58 taken 14 times.
✗ Branch 57 → 143 not taken.
14 return llvm::ConstantArray::get(arrayType, itemConstants);
264 14 }
265
266 // Function or procedure
267
3/4
✓ Branch 61 → 62 taken 74 times.
✗ Branch 61 → 147 not taken.
✓ Branch 62 → 63 taken 32 times.
✓ Branch 62 → 75 taken 42 times.
74 if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
268
2/2
✓ Branch 63 → 64 taken 12 times.
✓ Branch 63 → 69 taken 20 times.
32 if (!llvmTypes.fatPtrType)
269
3/6
✓ Branch 64 → 65 taken 12 times.
✗ Branch 64 → 148 not taken.
✓ Branch 65 → 66 taken 12 times.
✗ Branch 65 → 148 not taken.
✓ Branch 67 → 68 taken 12 times.
✗ Branch 67 → 148 not taken.
12 llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()});
270
271
2/4
✓ Branch 69 → 70 taken 32 times.
✗ Branch 69 → 150 not taken.
✓ Branch 70 → 71 taken 32 times.
✗ Branch 70 → 150 not taken.
32 llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR));
272
1/2
✓ Branch 72 → 73 taken 32 times.
✗ Branch 72 → 151 not taken.
32 return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue});
273 }
274
275 // Struct
276
2/2
✓ Branch 76 → 77 taken 41 times.
✓ Branch 76 → 114 taken 1 time.
42 if (symbolType.is(TY_STRUCT)) {
277 // Retrieve field count
278
1/2
✓ Branch 77 → 78 taken 41 times.
✗ Branch 77 → 158 not taken.
41 Scope *structScope = symbolType.getBodyScope();
279
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 41 times.
41 assert(structScope != nullptr);
280
1/2
✓ Branch 80 → 81 taken 41 times.
✗ Branch 80 → 158 not taken.
41 const size_t fieldCount = structScope->getFieldCount();
281
282 // Get default values for all fields of the struct
283 41 std::vector<llvm::Constant *> fieldConstants;
284
1/2
✓ Branch 81 → 82 taken 41 times.
✗ Branch 81 → 156 not taken.
41 fieldConstants.reserve(fieldCount);
285
286 // Add default value for each struct field
287
2/2
✓ Branch 107 → 83 taken 97 times.
✓ Branch 107 → 108 taken 41 times.
138 for (size_t i = 0; i < fieldCount; i++) {
288 // Get entry of the field
289
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 97 times.
97 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
290
3/6
✓ Branch 88 → 89 taken 97 times.
✗ Branch 88 → 92 not taken.
✓ Branch 89 → 90 taken 97 times.
✗ Branch 89 → 154 not taken.
✓ Branch 90 → 91 taken 97 times.
✗ Branch 90 → 92 not taken.
97 assert(fieldEntry != nullptr && fieldEntry->isField());
291
292 // Retrieve default field value
293 llvm::Constant *defaultFieldValue;
294
4/6
✓ Branch 93 → 94 taken 97 times.
✗ Branch 93 → 95 not taken.
✓ Branch 96 → 97 taken 97 times.
✗ Branch 96 → 102 not taken.
✓ Branch 97 → 98 taken 3 times.
✓ Branch 97 → 102 taken 94 times.
97 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue)
295
3/6
✓ Branch 98 → 99 taken 3 times.
✗ Branch 98 → 154 not taken.
✓ Branch 99 → 100 taken 3 times.
✗ Branch 99 → 153 not taken.
✓ Branch 100 → 101 taken 3 times.
✗ Branch 100 → 153 not taken.
3 defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(manIdx), fieldEntry->getQualType(), fieldNode);
296 else
297
2/4
✓ Branch 102 → 103 taken 94 times.
✗ Branch 102 → 154 not taken.
✓ Branch 103 → 104 taken 94 times.
✗ Branch 103 → 154 not taken.
94 defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType());
298
299
1/2
✓ Branch 105 → 106 taken 97 times.
✗ Branch 105 → 154 not taken.
97 fieldConstants.push_back(defaultFieldValue);
300 }
301
302
1/2
✓ Branch 108 → 109 taken 41 times.
✗ Branch 108 → 156 not taken.
41 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
303
1/2
✓ Branch 110 → 111 taken 41 times.
✗ Branch 110 → 155 not taken.
41 return llvm::ConstantStruct::get(structType, fieldConstants);
304 41 }
305
306 // Interface
307
1/2
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 121 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
308 1 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
309 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
310 }
311
312 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
313 }
314
315 36614 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
316
2/2
✓ Branch 3 → 4 taken 1518 times.
✓ Branch 3 → 9 taken 35096 times.
36614 if (type.is(TY_DOUBLE))
317
2/4
✓ Branch 4 → 5 taken 1518 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 1518 times.
✗ Branch 5 → 54 not taken.
1518 return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue));
318
319
2/2
✓ Branch 10 → 11 taken 6980 times.
✓ Branch 10 → 13 taken 28116 times.
35096 if (type.is(TY_INT))
320 6980 return builder.getInt32(compileTimeValue.intValue);
321
322
2/2
✓ Branch 14 → 15 taken 1073 times.
✓ Branch 14 → 17 taken 27043 times.
28116 if (type.is(TY_SHORT))
323 1073 return builder.getInt16(compileTimeValue.shortValue);
324
325
2/2
✓ Branch 18 → 19 taken 13234 times.
✓ Branch 18 → 21 taken 13809 times.
27043 if (type.is(TY_LONG))
326 13234 return builder.getInt64(compileTimeValue.longValue);
327
328
3/4
✓ Branch 21 → 22 taken 13809 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 4150 times.
✓ Branch 22 → 25 taken 9659 times.
13809 if (type.isOneOf({TY_BYTE, TY_CHAR}))
329 4150 return builder.getInt8(compileTimeValue.charValue);
330
331
2/2
✓ Branch 26 → 27 taken 6132 times.
✓ Branch 26 → 36 taken 3527 times.
9659 if (type.is(TY_STRING)) {
332 6132 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
333
2/4
✓ Branch 30 → 31 taken 6132 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 6132 times.
✗ Branch 31 → 58 not taken.
18396 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
334 }
335
336
1/2
✓ Branch 37 → 38 taken 3527 times.
✗ Branch 37 → 40 not taken.
3527 if (type.is(TY_BOOL))
337 3527 return builder.getInt1(compileTimeValue.boolValue);
338
339 if (type.is(TY_PTR))
340 return llvm::Constant::getNullValue(builder.getPtrTy());
341
342 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
343 }
344
345 74328 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
346
2/4
✓ Branch 2 → 3 taken 74328 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 74328 times.
✗ Branch 3 → 7 not taken.
74328 return llvm::BasicBlock::Create(context, blockName);
347 }
348
349 74328 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
350
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 74328 times.
74328 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
351 // If no parent function were passed, use the current function
352
2/2
✓ Branch 5 → 6 taken 49320 times.
✓ Branch 5 → 8 taken 25008 times.
74328 if (!parentFct)
353 49320 parentFct = builder.GetInsertBlock()->getParent();
354 // Append block to current function
355 74328 parentFct->insert(parentFct->end(), block);
356 // Set insert point to the block
357 74328 builder.SetInsertPoint(block);
358 74328 blockAlreadyTerminated = false;
359 74328 }
360
361 21746 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
362 21746 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
363 21746 generateScopeCleanup(stmtLstNode);
364 21746 blockAlreadyTerminated = true;
365 21746 }
366
367 25944 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
368
2/2
✓ Branch 2 → 3 taken 7280 times.
✓ Branch 2 → 4 taken 18664 times.
25944 if (blockAlreadyTerminated)
369 7280 return;
370 18664 builder.CreateBr(targetBlock);
371 18664 blockAlreadyTerminated = true;
372 }
373
374 20689 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
375 Likelihood likelihood /*=UNSPECIFIED*/) {
376
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 20689 times.
20689 if (blockAlreadyTerminated)
377 return;
378 20689 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
379 20689 blockAlreadyTerminated = true;
380
381
2/2
✓ Branch 5 → 6 taken 3502 times.
✓ Branch 5 → 7 taken 17187 times.
20689 if (likelihood != Likelihood::UNSPECIFIED)
382 3502 mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood);
383 }
384
385 25008 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
386 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
387
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 25008 times.
25008 if (cliOptions.disableVerifier)
388 return;
389
390 // Verify function
391 25008 std::string output;
392
1/2
✓ Branch 5 → 6 taken 25008 times.
✗ Branch 5 → 20 not taken.
25008 llvm::raw_string_ostream oss(output);
393 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
394 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
395 25008 }
396
397 1734 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
398 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
399
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1734 times.
1734 if (cliOptions.disableVerifier)
400 return;
401
402 // Verify module
403 1734 std::string output;
404
1/2
✓ Branch 5 → 6 taken 1734 times.
✗ Branch 5 → 20 not taken.
1734 llvm::raw_string_ostream oss(output);
405 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
406 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
407 1734 }
408
409 12953 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
410 // Get entry of left side
411
2/4
✓ Branch 2 → 3 taken 12953 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 12953 times.
✗ Branch 3 → 16 not taken.
12953 auto exprResult = std::any_cast<LLVMExprResult>(visit(lhsNode));
412 12953 SymbolTableEntry *entry = exprResult.entry;
413
7/10
✓ Branch 5 → 6 taken 11695 times.
✓ Branch 5 → 10 taken 1258 times.
✓ Branch 6 → 7 taken 11695 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 11695 times.
✗ Branch 7 → 19 not taken.
✓ Branch 8 → 9 taken 886 times.
✓ Branch 8 → 10 taken 10809 times.
✓ Branch 10 → 11 taken 12067 times.
✗ Branch 10 → 19 not taken.
12953 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? exprResult.refPtr : resolveAddress(exprResult);
414
1/2
✓ Branch 12 → 13 taken 12953 times.
✗ Branch 12 → 19 not taken.
25906 return doAssignment(lhsAddress, entry, rhsNode, node);
415 }
416
417 30189 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
418 const ASTNode *node, bool isDecl) {
419 // Get symbol type of right side
420
1/2
✓ Branch 2 → 3 taken 30189 times.
✗ Branch 2 → 13 not taken.
30189 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
421
2/4
✓ Branch 3 → 4 taken 30189 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 30189 times.
✗ Branch 4 → 10 not taken.
30189 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
422
1/2
✓ Branch 6 → 7 taken 30189 times.
✗ Branch 6 → 13 not taken.
60378 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
423 }
424
425 30565 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
426 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
427 // Deduce some information about the assignment
428
4/4
✓ Branch 2 → 3 taken 29307 times.
✓ Branch 2 → 7 taken 1258 times.
✓ Branch 5 → 6 taken 1937 times.
✓ Branch 5 → 7 taken 27370 times.
30565 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
429
8/10
✓ Branch 8 → 9 taken 28628 times.
✓ Branch 8 → 15 taken 1937 times.
✓ Branch 9 → 10 taken 28628 times.
✗ Branch 9 → 247 not taken.
✓ Branch 10 → 11 taken 28628 times.
✗ Branch 10 → 247 not taken.
✓ Branch 11 → 12 taken 4011 times.
✓ Branch 11 → 15 taken 24617 times.
✓ Branch 13 → 14 taken 452 times.
✓ Branch 13 → 15 taken 3559 times.
30565 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
430
431
2/2
✓ Branch 16 → 17 taken 1937 times.
✓ Branch 16 → 57 taken 28628 times.
30565 if (isRefAssign) {
432
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 1937 times.
1937 assert(lhsEntry != nullptr);
433
2/2
✓ Branch 19 → 20 taken 1051 times.
✓ Branch 19 → 33 taken 886 times.
1937 if (isDecl) { // Reference gets initially assigned
434 // Get address of right side
435 1051 llvm::Value *rhsAddress = resolveAddress(rhs);
436
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1051 times.
1051 assert(rhsAddress != nullptr);
437
438 // Store lhs pointer to rhs
439
2/4
✓ Branch 26 → 27 taken 1051 times.
✗ Branch 26 → 248 not taken.
✓ Branch 27 → 28 taken 1051 times.
✗ Branch 27 → 248 not taken.
1051 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
440 1051 lhsEntry->updateAddress(refAddress);
441 1051 insertStore(rhsAddress, refAddress);
442
443 1051 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
444 }
445
446 // Reference to reference assignment (only for struct fields that are not initialized yet)
447 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
448
6/8
✓ Branch 33 → 34 taken 699 times.
✓ Branch 33 → 40 taken 187 times.
✓ Branch 35 → 36 taken 699 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 673 times.
✓ Branch 36 → 40 taken 26 times.
✓ Branch 38 → 39 taken 673 times.
✗ Branch 38 → 40 not taken.
886 const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField();
449 // Assigning the result variable
450 886 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
451
4/4
✓ Branch 42 → 43 taken 213 times.
✓ Branch 42 → 44 taken 673 times.
✓ Branch 43 → 44 taken 11 times.
✓ Branch 43 → 49 taken 202 times.
886 if (isInitialFieldRefAssign || isReturnValAssign) {
452 // Get address of right side
453 684 llvm::Value *referencedAddress = resolveAddress(rhs);
454
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 684 times.
684 assert(referencedAddress != nullptr);
455
456 // Store the rhs* to the lhs**
457 684 insertStore(referencedAddress, lhsAddress);
458
459 684 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
460 }
461
462 // Load referenced address
463
2/4
✓ Branch 52 → 53 taken 202 times.
✗ Branch 52 → 254 not taken.
✓ Branch 53 → 54 taken 202 times.
✗ Branch 53 → 254 not taken.
202 lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress);
464 }
465
466
8/8
✓ Branch 57 → 58 taken 16561 times.
✓ Branch 57 → 63 taken 12269 times.
✓ Branch 59 → 60 taken 2197 times.
✓ Branch 59 → 63 taken 14364 times.
✓ Branch 61 → 62 taken 2191 times.
✓ Branch 61 → 63 taken 6 times.
✓ Branch 64 → 65 taken 2191 times.
✓ Branch 64 → 70 taken 26639 times.
28830 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
467
1/2
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 2191 times.
2191 assert(lhsEntry != nullptr);
468 // Directly set the address to the lhs entry (temp stealing)
469 2191 llvm::Value *rhsAddress = resolveAddress(rhs);
470 2191 lhsEntry->updateAddress(rhsAddress);
471 2191 rhs.entry = lhsEntry;
472 2191 return rhs;
473 }
474
475 // Allocate new memory if the lhs address does not exist
476
2/2
✓ Branch 70 → 71 taken 14279 times.
✓ Branch 70 → 81 taken 12360 times.
26639 if (!lhsAddress) {
477
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 14279 times.
14279 assert(lhsEntry != nullptr);
478
2/4
✓ Branch 76 → 77 taken 14279 times.
✗ Branch 76 → 260 not taken.
✓ Branch 77 → 78 taken 14279 times.
✗ Branch 77 → 260 not taken.
14279 lhsAddress = insertAlloca(lhsEntry->getQualType());
479 14279 lhsEntry->updateAddress(lhsAddress);
480 }
481
482 // Check if we try to assign an array by value to a pointer. Here we have to store the address of the first element to the lhs
483
10/10
✓ Branch 81 → 82 taken 25381 times.
✓ Branch 81 → 90 taken 1258 times.
✓ Branch 84 → 85 taken 6066 times.
✓ Branch 84 → 90 taken 19315 times.
✓ Branch 86 → 87 taken 7 times.
✓ Branch 86 → 90 taken 6059 times.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 88 → 90 taken 5 times.
✓ Branch 91 → 92 taken 2 times.
✓ Branch 91 → 107 taken 26637 times.
26639 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
484 // Get address of right side
485
1/2
✓ Branch 92 → 93 taken 2 times.
✗ Branch 92 → 273 not taken.
2 llvm::Value *rhsAddress = resolveAddress(rhs);
486
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 2 times.
2 assert(rhsAddress != nullptr);
487
1/2
✓ Branch 95 → 96 taken 2 times.
✗ Branch 95 → 273 not taken.
2 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
488
2/4
✓ Branch 96 → 97 taken 2 times.
✗ Branch 96 → 273 not taken.
✓ Branch 97 → 98 taken 2 times.
✗ Branch 97 → 273 not taken.
2 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
489
1/2
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 266 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
490
1/2
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 273 not taken.
2 insertStore(firstItemAddress, lhsAddress);
491 2 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
492 }
493
494 // Handle operator overloads
495
6/6
✓ Branch 107 → 108 taken 12269 times.
✓ Branch 107 → 111 taken 14368 times.
✓ Branch 109 → 110 taken 267 times.
✓ Branch 109 → 111 taken 12002 times.
✓ Branch 112 → 113 taken 267 times.
✓ Branch 112 → 129 taken 26370 times.
26637 if (!isDecl && conversionManager.callsOverloadedOpFct(node, DEFAULT_OP_IDX)) {
496 267 ResolverFct lhsV = [&] { return static_cast<llvm::Value *>(nullptr); };
497
1/2
✓ Branch 114 → 115 taken 267 times.
✗ Branch 114 → 274 not taken.
267 ResolverFct rhsV = [&] { return resolveValue(rhsSType, rhs); };
498 534 ResolverFct lhsP = [&] { return lhsAddress; };
499 534 ResolverFct rhsP = [&] { return resolveAddress(rhs); };
500 267 return conversionManager.callOperatorOverloadFct<2>(node, {lhsV, lhsP, rhsV, rhsP}, DEFAULT_OP_IDX);
501 267 }
502
503 // Check if we need to copy the rhs to the lhs. This happens for structs
504
2/2
✓ Branch 129 → 130 taken 322 times.
✓ Branch 129 → 215 taken 26048 times.
26370 if (needsCopy) {
505 // Get address of right side
506
1/2
✓ Branch 130 → 131 taken 322 times.
✗ Branch 130 → 350 not taken.
322 llvm::Value *rhsAddress = resolveAddress(rhs);
507
1/2
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 133 taken 322 times.
322 assert(rhsAddress != nullptr);
508
509 // If the lhs already holds an initialized, non-trivially-destructible struct, its old value must be
510 // destructed before the copy overwrites it, otherwise its owning members (heap pointers, strings, ...)
511 // would leak. The typechecker only sets a dtor in exactly those cases. To stay correct for a self-
512 // assignment like 'a = a', the destruct + copy are skipped entirely when both sides share the address
513 // (the assignment is a no-op in that case, and destructing first would corrupt the value to copy from).
514
1/2
✓ Branch 133 → 134 taken 322 times.
✗ Branch 133 → 135 not taken.
322 const auto *assignNode = dynamic_cast<const AssignExprNode *>(node);
515
3/4
✓ Branch 136 → 137 taken 316 times.
✓ Branch 136 → 139 taken 6 times.
✓ Branch 137 → 138 taken 316 times.
✗ Branch 137 → 350 not taken.
322 const Function *lhsDtor = assignNode ? assignNode->lhsDtorFct.at(manIdx) : nullptr;
516 322 llvm::BasicBlock *bCopyEnd = nullptr;
517
2/2
✓ Branch 140 → 141 taken 9 times.
✓ Branch 140 → 161 taken 313 times.
322 if (lhsDtor != nullptr) {
518
2/4
✓ Branch 143 → 144 taken 9 times.
✗ Branch 143 → 294 not taken.
✓ Branch 144 → 145 taken 9 times.
✗ Branch 144 → 292 not taken.
18 llvm::BasicBlock *bCopy = createBlock("assign.copy");
519
2/4
✓ Branch 149 → 150 taken 9 times.
✗ Branch 149 → 300 not taken.
✓ Branch 150 → 151 taken 9 times.
✗ Branch 150 → 298 not taken.
9 bCopyEnd = createBlock("assign.copy.end");
520
3/6
✓ Branch 153 → 154 taken 9 times.
✗ Branch 153 → 304 not taken.
✓ Branch 154 → 155 taken 9 times.
✗ Branch 154 → 304 not taken.
✓ Branch 155 → 156 taken 9 times.
✗ Branch 155 → 304 not taken.
9 insertCondJump(builder.CreateICmpEQ(lhsAddress, rhsAddress), bCopyEnd, bCopy);
521
1/2
✓ Branch 156 → 157 taken 9 times.
✗ Branch 156 → 350 not taken.
9 switchToBlock(bCopy);
522
1/2
✓ Branch 158 → 159 taken 9 times.
✗ Branch 158 → 305 not taken.
9 generateCtorOrDtorCall(lhsAddress, lhsDtor, {});
523 }
524
525
2/4
✓ Branch 161 → 162 taken 322 times.
✗ Branch 161 → 308 not taken.
✓ Branch 162 → 163 taken 322 times.
✗ Branch 162 → 308 not taken.
322 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
526
3/4
✓ Branch 163 → 164 taken 322 times.
✗ Branch 163 → 350 not taken.
✓ Branch 164 → 165 taken 239 times.
✓ Branch 164 → 181 taken 83 times.
322 if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
527 // Create shallow copy
528
1/2
✓ Branch 165 → 166 taken 239 times.
✗ Branch 165 → 316 not taken.
239 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
529
3/10
✓ Branch 166 → 167 taken 239 times.
✗ Branch 166 → 168 not taken.
✓ Branch 167 → 171 taken 239 times.
✗ Branch 167 → 309 not taken.
✗ Branch 170 → 171 not taken.
✗ Branch 170 → 309 not taken.
✗ Branch 171 → 172 not taken.
✓ Branch 171 → 174 taken 239 times.
✗ Branch 309 → 310 not taken.
✗ Branch 309 → 312 not taken.
239 const std::string copyName = lhsEntry ? lhsEntry->name : "";
530
3/6
✓ Branch 174 → 175 taken 239 times.
✗ Branch 174 → 177 not taken.
✗ Branch 175 → 176 not taken.
✓ Branch 175 → 177 taken 239 times.
✓ Branch 178 → 179 taken 239 times.
✗ Branch 178 → 314 not taken.
239 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
531 239 } else {
532 // Check if we have a copy ctor
533
1/2
✓ Branch 181 → 182 taken 83 times.
✗ Branch 181 → 349 not taken.
83 Scope *structScope = rhsSTypeNonRef.getBodyScope();
534
2/4
✓ Branch 182 → 183 taken 83 times.
✗ Branch 182 → 321 not taken.
✓ Branch 187 → 188 taken 83 times.
✗ Branch 187 → 317 not taken.
249 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
535
2/4
✓ Branch 191 → 192 taken 83 times.
✗ Branch 191 → 325 not taken.
✓ Branch 192 → 193 taken 83 times.
✗ Branch 192 → 323 not taken.
83 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
536
1/2
✓ Branch 195 → 196 taken 83 times.
✗ Branch 195 → 204 not taken.
83 if (copyCtor != nullptr) {
537 // Call copy ctor
538
2/4
✓ Branch 198 → 199 taken 83 times.
✗ Branch 198 → 331 not taken.
✓ Branch 199 → 200 taken 83 times.
✗ Branch 199 → 329 not taken.
166 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
539 } else {
540 const std::string structName = rhsSTypeNonRef.getName();
541 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
542 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
543 }
544 83 }
545
546 // Close the self-assignment guard
547
2/2
✓ Branch 211 → 212 taken 9 times.
✓ Branch 211 → 214 taken 313 times.
322 if (bCopyEnd != nullptr) {
548
1/2
✓ Branch 212 → 213 taken 9 times.
✗ Branch 212 → 350 not taken.
9 insertJump(bCopyEnd);
549
1/2
✓ Branch 213 → 214 taken 9 times.
✗ Branch 213 → 350 not taken.
9 switchToBlock(bCopyEnd);
550 }
551 322 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
552 }
553
554 // Optimization: If we have the address of both sides, we can do a memcpy instead of loading and storing the value
555 26048 llvm::Value *rhsValue = nullptr;
556
8/8
✓ Branch 216 → 217 taken 1144 times.
✓ Branch 216 → 220 taken 24904 times.
✓ Branch 217 → 218 taken 1093 times.
✓ Branch 217 → 220 taken 51 times.
✓ Branch 218 → 219 taken 1086 times.
✓ Branch 218 → 220 taken 7 times.
✓ Branch 221 → 222 taken 1086 times.
✓ Branch 221 → 243 taken 24962 times.
26048 if (rhsSType.is(TY_STRUCT) && rhs.value == nullptr && rhs.constant == nullptr) {
557 // Create shallow copy
558
2/4
✓ Branch 222 → 223 taken 1086 times.
✗ Branch 222 → 351 not taken.
✓ Branch 223 → 224 taken 1086 times.
✗ Branch 223 → 351 not taken.
1086 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
559
1/2
✓ Branch 224 → 225 taken 1086 times.
✗ Branch 224 → 359 not taken.
1086 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
560
1/2
✓ Branch 225 → 226 taken 1086 times.
✗ Branch 225 → 359 not taken.
1086 llvm::Value *rhsAddress = resolveAddress(rhs);
561
1/2
✗ Branch 226 → 227 not taken.
✓ Branch 226 → 228 taken 1086 times.
1086 assert(rhsAddress != nullptr);
562
6/10
✓ Branch 228 → 229 taken 1083 times.
✓ Branch 228 → 230 taken 3 times.
✓ Branch 229 → 233 taken 1083 times.
✗ Branch 229 → 352 not taken.
✓ Branch 232 → 233 taken 3 times.
✗ Branch 232 → 352 not taken.
✓ Branch 233 → 234 taken 3 times.
✓ Branch 233 → 236 taken 1083 times.
✗ Branch 352 → 353 not taken.
✗ Branch 352 → 355 not taken.
1089 const std::string copyName = lhsEntry ? lhsEntry->name : "";
563
4/6
✓ Branch 236 → 237 taken 1083 times.
✓ Branch 236 → 239 taken 3 times.
✗ Branch 237 → 238 not taken.
✓ Branch 237 → 239 taken 1083 times.
✓ Branch 240 → 241 taken 1086 times.
✗ Branch 240 → 357 not taken.
1086 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
564 1086 } else {
565 // We can load the value from the right side and store it to the left side
566 // Retrieve value of the right side
567 24962 rhsValue = resolveValue(rhsSType, rhs);
568 // Store the value to the address
569 24962 insertStore(rhsValue, lhsAddress, rhsSType);
570 }
571
572 26048 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
573
5/14
✓ Branch 117 → 118 taken 267 times.
✗ Branch 117 → 277 not taken.
✓ Branch 118 → 119 taken 267 times.
✗ Branch 118 → 277 not taken.
✓ Branch 119 → 120 taken 267 times.
✗ Branch 119 → 277 not taken.
✓ Branch 120 → 121 taken 267 times.
✗ Branch 120 → 277 not taken.
✓ Branch 121 → 122 taken 267 times.
✗ Branch 121 → 275 not taken.
✗ Branch 277 → 278 not taken.
✗ Branch 277 → 281 not taken.
✗ Branch 279 → 280 not taken.
✗ Branch 279 → 281 not taken.
267 }
574
575 1476 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
576 bool isVolatile) const {
577 // Retrieve size to copy
578
1/2
✓ Branch 3 → 4 taken 1476 times.
✗ Branch 3 → 19 not taken.
1476 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
579
580 // Create values for memcpy intrinsic
581
2/4
✓ Branch 4 → 5 taken 1476 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 1476 times.
✗ Branch 5 → 19 not taken.
1476 llvm::Value *structSize = builder.getInt64(typeSize);
582
1/2
✓ Branch 6 → 7 taken 1476 times.
✗ Branch 6 → 19 not taken.
1476 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
583
584 // Call memcpy intrinsic to execute the shallow copy
585
1/2
✓ Branch 7 → 8 taken 1476 times.
✗ Branch 7 → 19 not taken.
1476 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
586
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1476 times.
1476 assert(targetAddress != nullptr);
587
3/6
✓ Branch 10 → 11 taken 1476 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 1476 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 1476 times.
✗ Branch 13 → 15 not taken.
1476 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
588 1476 }
589
590 60925 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) {
591
6/6
✓ Branch 12 → 13 taken 64281 times.
✓ Branch 12 → 15 taken 41456 times.
✓ Branch 14 → 15 taken 3356 times.
✓ Branch 14 → 16 taken 60925 times.
✓ Branch 17 → 3 taken 44812 times.
✓ Branch 17 → 18 taken 60925 times.
105737 while (symbolType.isPtr() || symbolType.isRef()) {
592
1/2
✓ Branch 6 → 7 taken 44812 times.
✗ Branch 6 → 19 not taken.
44812 ptr = insertLoad(symbolType, ptr);
593
1/2
✓ Branch 9 → 10 taken 44812 times.
✗ Branch 9 → 25 not taken.
44812 symbolType = symbolType.getContained();
594 }
595 60925 }
596
597 130 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
598 // Get unused name
599
1/2
✓ Branch 2 → 3 taken 130 times.
✗ Branch 2 → 19 not taken.
130 const std::string globalName = getUnusedGlobalName(baseName);
600 // Create global
601
1/2
✓ Branch 5 → 6 taken 130 times.
✗ Branch 5 → 15 not taken.
130 module->getOrInsertGlobal(globalName, constant->getType());
602
1/2
✓ Branch 7 → 8 taken 130 times.
✗ Branch 7 → 16 not taken.
130 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
603 // Set initializer to the given constant
604
1/2
✓ Branch 8 → 9 taken 130 times.
✗ Branch 8 → 17 not taken.
130 global->setInitializer(constant);
605 130 global->setConstant(true);
606
1/2
✓ Branch 10 → 11 taken 130 times.
✗ Branch 10 → 17 not taken.
130 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
607 130 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
608 130 return global;
609 130 }
610
611 7316 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
612 // Get unused name
613
1/2
✓ Branch 2 → 3 taken 7316 times.
✗ Branch 2 → 21 not taken.
7316 const std::string globalName = getUnusedGlobalName(baseName);
614 // Create global
615
2/4
✓ Branch 3 → 4 taken 7316 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 7316 times.
✗ Branch 5 → 15 not taken.
7316 builder.CreateGlobalString(value, globalName, 0, module);
616
1/2
✓ Branch 7 → 8 taken 7316 times.
✗ Branch 7 → 17 not taken.
7316 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
617 // If the output should be comparable, fix alignment to 4 bytes
618
1/2
✓ Branch 8 → 9 taken 7316 times.
✗ Branch 8 → 12 not taken.
7316 if (cliOptions.comparableOutput)
619
2/4
✓ Branch 9 → 10 taken 7316 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 7316 times.
✗ Branch 10 → 18 not taken.
7316 global->setAlignment(llvm::Align(4));
620 7316 return global;
621 7316 }
622
623 7316 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
624 const CodeLoc &codeLoc) const {
625 7316 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
626 // Create debug info
627
2/2
✓ Branch 3 → 4 taken 44 times.
✓ Branch 3 → 10 taken 7272 times.
7316 if (cliOptions.instrumentation.generateDebugInfo)
628
3/6
✓ Branch 5 → 6 taken 44 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 44 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 44 times.
✗ Branch 7 → 12 not taken.
44 diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc);
629 7316 return global;
630 }
631
632 12611 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
633 // Find an unused global name
634 12611 std::string globalName;
635 12611 unsigned int suffixNumber = 0;
636 do {
637
1/2
✓ Branch 5 → 6 taken 357472 times.
✗ Branch 5 → 15 not taken.
357472 globalName = baseName + std::to_string(suffixNumber);
638 357472 suffixNumber++;
639
3/4
✓ Branch 10 → 11 taken 357472 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 344861 times.
✓ Branch 11 → 13 taken 12611 times.
357472 } while (module->getNamedGlobal(globalName) != nullptr);
640 12611 return globalName;
641 }
642
643 40489 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
644 // Skip results, that do not contain a constant or already have a value
645
3/4
✓ Branch 2 → 3 taken 39120 times.
✓ Branch 2 → 4 taken 1369 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 39120 times.
40489 if (exprResult.value != nullptr || exprResult.constant == nullptr)
646 1369 return;
647
648 // Default case: the value to the constant
649 39120 exprResult.value = exprResult.constant;
650 }
651
652 30376 bool IRGenerator::isSymbolDSOLocal(bool isPublic) const {
653 // If we are compiling a shared library and export the global symbol, we need to drop dso_local
654 // because it may be interposed by other shared objects by the dynamic linker.
655
3/4
✓ Branch 2 → 3 taken 27059 times.
✓ Branch 2 → 4 taken 3317 times.
✓ Branch 3 → 4 taken 27059 times.
✗ Branch 3 → 5 not taken.
30376 return !(isPublic && cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY);
656 }
657
658 15108 llvm::GlobalValue::LinkageTypes IRGenerator::getSymbolLinkageType(bool isPublic) const {
659
2/2
✓ Branch 2 → 3 taken 12690 times.
✓ Branch 2 → 4 taken 2418 times.
15108 return isPublic ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::PrivateLinkage;
660 }
661
662 4377 void IRGenerator::attachComdatToSymbol(llvm::GlobalVariable *global, const std::string &comdatName, bool isPublic) const {
663 // MachO does not support comdat annotations
664
6/6
✓ Branch 2 → 3 taken 4314 times.
✓ Branch 2 → 6 taken 63 times.
✓ Branch 4 → 5 taken 4299 times.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 7 → 8 taken 4299 times.
✓ Branch 7 → 12 taken 78 times.
4377 if (isPublic && cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO)
665
2/4
✓ Branch 9 → 10 taken 4299 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 4299 times.
✗ Branch 10 → 13 not taken.
4299 global->setComdat(module->getOrInsertComdat(comdatName));
666 4377 }
667
668 3333 std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) {
669
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 3333 times.
3333 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
670
3/4
✓ Branch 4 → 5 taken 3333 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 3235 times.
✓ Branch 5 → 7 taken 98 times.
3333 const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget;
671
672 // Backup target triple and data layout
673
1/2
✓ Branch 9 → 10 taken 3333 times.
✗ Branch 9 → 45 not taken.
3333 const llvm::Triple targetTriple = llvmModule->getTargetTriple();
674
1/2
✓ Branch 11 → 12 taken 3333 times.
✗ Branch 11 → 43 not taken.
3333 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
675 // Remove target triple and data layout
676
2/2
✓ Branch 12 → 13 taken 3235 times.
✓ Branch 12 → 19 taken 98 times.
3333 if (eliminateTarget) {
677 3235 llvmModule->setTargetTriple(llvm::Triple());
678
2/4
✓ Branch 16 → 17 taken 3235 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 3235 times.
✗ Branch 17 → 34 not taken.
3235 llvmModule->setDataLayout("");
679 }
680
681 // Get IR string
682 3333 std::string output;
683
1/2
✓ Branch 20 → 21 taken 3333 times.
✗ Branch 20 → 39 not taken.
3333 llvm::raw_string_ostream oss(output);
684
1/2
✓ Branch 21 → 22 taken 3333 times.
✗ Branch 21 → 37 not taken.
3333 llvmModule->print(oss, nullptr);
685
686 // Restore target triple and data layout
687
2/2
✓ Branch 22 → 23 taken 3235 times.
✓ Branch 22 → 29 taken 98 times.
3333 if (eliminateTarget) {
688
1/2
✓ Branch 23 → 24 taken 3235 times.
✗ Branch 23 → 35 not taken.
3235 llvmModule->setTargetTriple(targetTriple);
689
1/2
✓ Branch 27 → 28 taken 3235 times.
✗ Branch 27 → 36 not taken.
3235 llvmModule->setDataLayout(targetDataLayout);
690 }
691
692 3333 return output;
693 3333 }
694
695 /**
696 * Returns the operator function list for the current manifestation and the given node
697 *
698 * @param node Node to retrieve the op fct pointer list from
699 * @return Op fct pointer list
700 */
701 50440 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
702
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 50440 times.
50440 assert(node->getOpFctPointers()->size() > manIdx);
703 50440 return node->getOpFctPointers()->at(manIdx);
704 }
705
706 } // namespace spice::compiler
707