GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.4% 382 / 6 / 398
Functions: 95.6% 43 / 0 / 45
Branches: 62.5% 445 / 20 / 732

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 2157 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
17 2157 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
18
1/2
✓ Branch 8 → 9 taken 2157 times.
✗ Branch 8 → 72 not taken.
2157 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
19
6/10
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 2155 times.
✓ Branch 9 → 10 taken 2157 times.
✗ Branch 9 → 72 not taken.
✓ Branch 10 → 11 taken 2157 times.
✗ Branch 10 → 72 not taken.
✓ Branch 11 → 12 taken 2157 times.
✗ Branch 11 → 70 not taken.
✓ Branch 15 → 16 taken 2157 times.
✗ Branch 15 → 66 not taken.
4314 stdFunctionManager(sourceFile, resourceManager, module) {
20 // Attach information to the module
21
1/2
✓ Branch 17 → 18 taken 2157 times.
✗ Branch 17 → 49 not taken.
2157 module->setTargetTriple(cliOptions.targetTriple);
22
2/4
✓ Branch 21 → 22 taken 2157 times.
✗ Branch 21 → 52 not taken.
✓ Branch 22 → 23 taken 2157 times.
✗ Branch 22 → 50 not taken.
2157 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
23
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 2156 times.
2157 if (cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY) {
24
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 62 not taken.
1 module->setPICLevel(llvm::PICLevel::SmallPIC);
25
1/2
✓ Branch 26 → 29 taken 1 time.
✗ Branch 26 → 62 not taken.
1 module->setPIELevel(llvm::PIELevel::Default);
26 } else {
27
1/2
✓ Branch 27 → 28 taken 2156 times.
✗ Branch 27 → 62 not taken.
2156 module->setPICLevel(llvm::PICLevel::BigPIC);
28
1/2
✓ Branch 28 → 29 taken 2156 times.
✗ Branch 28 → 62 not taken.
2156 module->setPIELevel(llvm::PIELevel::Large);
29 }
30
1/2
✓ Branch 29 → 30 taken 2157 times.
✗ Branch 29 → 62 not taken.
2157 module->setUwtable(llvm::UWTableKind::Default);
31
1/2
✓ Branch 30 → 31 taken 2157 times.
✗ Branch 30 → 62 not taken.
2157 module->setFramePointer(llvm::FramePointerKind::All);
32
33 // Add module identifier metadata
34
2/4
✓ Branch 31 → 32 taken 2157 times.
✗ Branch 31 → 53 not taken.
✓ Branch 32 → 33 taken 2157 times.
✗ Branch 32 → 53 not taken.
2157 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
35
3/6
✓ Branch 34 → 35 taken 2157 times.
✗ Branch 34 → 54 not taken.
✓ Branch 36 → 37 taken 2157 times.
✗ Branch 36 → 54 not taken.
✓ Branch 37 → 38 taken 2157 times.
✗ Branch 37 → 54 not taken.
2157 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
36
37 // Initialize common LLVM types
38
4/8
✓ Branch 38 → 39 taken 2157 times.
✗ Branch 38 → 57 not taken.
✓ Branch 39 → 40 taken 2157 times.
✗ Branch 39 → 57 not taken.
✓ Branch 40 → 41 taken 2157 times.
✗ Branch 40 → 57 not taken.
✓ Branch 42 → 43 taken 2157 times.
✗ Branch 42 → 57 not taken.
2157 llvmTypes.lambdaFatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy(), builder.getInt64Ty()});
39
40 // Initialize debug info generator
41
2/2
✓ Branch 43 → 44 taken 27 times.
✓ Branch 43 → 48 taken 2130 times.
2157 if (cliOptions.instrumentation.generateDebugInfo)
42
2/4
✓ Branch 44 → 45 taken 27 times.
✗ Branch 44 → 61 not taken.
✓ Branch 45 → 46 taken 27 times.
✗ Branch 45 → 59 not taken.
27 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
43 2157 }
44
45 2157 std::any IRGenerator::visitEntry(const EntryNode *node) {
46 // Generate IR
47
1/2
✓ Branch 2 → 3 taken 2157 times.
✗ Branch 2 → 28 not taken.
2157 visitChildren(node);
48
49 // Generate test main if required
50
4/4
✓ Branch 4 → 5 taken 357 times.
✓ Branch 4 → 7 taken 1800 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 353 times.
2157 if (sourceFile->isMainFile && cliOptions.generateTestMain)
51 4 generateTestMain();
52
53 // Execute deferred VTable initializations
54
2/2
✓ Branch 21 → 9 taken 2239 times.
✓ Branch 21 → 22 taken 2157 times.
6553 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
55
1/2
✓ Branch 11 → 12 taken 2239 times.
✗ Branch 11 → 29 not taken.
2239 deferredVTableInit.execute();
56
57 // Finalize debug info generator
58 2157 diGenerator.finalize();
59
60 // Verify module
61 2157 verifyModule(node->codeLoc);
62
63
1/2
✓ Branch 24 → 25 taken 2157 times.
✗ Branch 24 → 30 not taken.
4314 return nullptr;
64 }
65
66 118620 llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, const std::string &varName) {
67
2/2
✓ Branch 2 → 3 taken 84501 times.
✓ Branch 2 → 10 taken 34119 times.
118620 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
68
2/4
✓ Branch 3 → 4 taken 84501 times.
✗ Branch 3 → 23 not taken.
✓ Branch 4 → 5 taken 84501 times.
✗ Branch 4 → 23 not taken.
84501 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
69
1/2
✓ Branch 6 → 7 taken 84501 times.
✗ Branch 6 → 24 not taken.
84501 allocaInst->setDebugLoc(llvm::DebugLoc());
70 84501 allocaInst->moveAfter(allocaInsertInst);
71 84501 allocaInsertInst = allocaInst;
72 } else { // This is the first alloca inst in the current function -> insert at the entry block
73 // Save current basic block and move insert cursor to entry block of the current function
74 34119 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
75 34119 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
76
77 // Allocate the size of the given LLVM type
78
2/4
✓ Branch 13 → 14 taken 34119 times.
✗ Branch 13 → 27 not taken.
✓ Branch 14 → 15 taken 34119 times.
✗ Branch 14 → 27 not taken.
34119 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
79
1/2
✓ Branch 16 → 17 taken 34119 times.
✗ Branch 16 → 28 not taken.
34119 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
80
81 // Restore old basic block
82 34119 builder.SetInsertPoint(currentBlock);
83 }
84
85 // Insert lifetime start marker
86
2/2
✓ Branch 19 → 20 taken 54 times.
✓ Branch 19 → 21 taken 118566 times.
118620 if (cliOptions.useLifetimeMarkers)
87 54 builder.CreateLifetimeStart(allocaInsertInst);
88
89 118620 return allocaInsertInst;
90 }
91
92 96728 llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) {
93 96728 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
94 96728 llvm::AllocaInst *alloca = insertAlloca(llvmType, varName);
95
96 // Insert type metadata
97
2/2
✓ Branch 4 → 5 taken 9 times.
✓ Branch 4 → 6 taken 96719 times.
96728 if (cliOptions.useTBAAMetadata)
98 9 mdGenerator.generateTypeMetadata(allocaInsertInst, qualType);
99
100 96728 return alloca;
101 }
102
103 210287 llvm::LoadInst *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile,
104 const std::string &varName) const {
105
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 210287 times.
210287 assert(ptr->getType()->isPointerTy());
106
2/4
✓ Branch 6 → 7 taken 210287 times.
✗ Branch 6 → 11 not taken.
✓ Branch 7 → 8 taken 210287 times.
✗ Branch 7 → 11 not taken.
210287 return builder.CreateLoad(llvmType, ptr, isVolatile, varName);
107 }
108
109 181234 llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) {
110 181234 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
111 181234 llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName);
112
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 181228 times.
181234 if (cliOptions.useTBAAMetadata)
113 6 mdGenerator.generateTBAAMetadata(load, qualType);
114 181234 return load;
115 }
116
117 117087 llvm::StoreInst *IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const {
118
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 117087 times.
117087 assert(ptr->getType()->isPointerTy());
119 117087 return builder.CreateStore(val, ptr, isVolatile);
120 }
121
122 31760 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) {
123 31760 llvm::StoreInst *store = insertStore(val, ptr, isVolatile);
124
2/2
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 31751 times.
31760 if (cliOptions.useTBAAMetadata)
125 9 mdGenerator.generateTBAAMetadata(store, qualType);
126 31760 }
127
128 57780 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
129 const std::string &varName) const {
130
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 57780 times.
57780 assert(basePtr->getType()->isPointerTy());
131
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 57780 times.
57780 assert(!indices.empty());
132
4/6
✓ Branch 4 → 5 taken 57106 times.
✓ Branch 4 → 7 taken 53027 times.
✓ Branch 6 → 7 taken 57106 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 57780 times.
167913 assert(std::ranges::all_of(indices, [](const llvm::Value *index) {
133 const llvm::Type *indexType = index->getType();
134 return indexType->isIntegerTy(32) || indexType->isIntegerTy(64);
135 }));
136
137 // Insert GEP
138
2/4
✓ Branch 12 → 13 taken 57780 times.
✗ Branch 12 → 17 not taken.
✓ Branch 13 → 14 taken 57780 times.
✗ Branch 13 → 17 not taken.
57780 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
139 }
140
141 25424 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index,
142 const std::string &varName) const {
143
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 25424 times.
25424 assert(basePtr->getType()->isPointerTy());
144
145 // If we use index 0 we can use the base pointer directly
146
2/2
✓ Branch 6 → 7 taken 7996 times.
✓ Branch 6 → 8 taken 17428 times.
25424 if (index == 0)
147 7996 return basePtr;
148
149 // Insert GEP
150
2/4
✓ Branch 8 → 9 taken 17428 times.
✗ Branch 8 → 13 not taken.
✓ Branch 9 → 10 taken 17428 times.
✗ Branch 9 → 13 not taken.
17428 return builder.CreateStructGEP(type, basePtr, index, varName);
151 }
152
153 118609 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
154 // Visit the given AST node
155
2/4
✓ Branch 2 → 3 taken 118609 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 118609 times.
✗ Branch 3 → 9 not taken.
118609 auto exprResult = any_cast<LLVMExprResult>(visit(node));
156
1/2
✓ Branch 5 → 6 taken 118609 times.
✗ Branch 5 → 12 not taken.
237218 return resolveValue(node, exprResult);
157 }
158
159 130708 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) {
160 130708 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
161 }
162
163 250372 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) {
164 // Check if the value is already present
165
2/2
✓ Branch 2 → 3 taken 80088 times.
✓ Branch 2 → 4 taken 170284 times.
250372 if (exprResult.value != nullptr)
166 80088 return exprResult.value;
167
168 // Check if a constant is present
169
2/2
✓ Branch 4 → 5 taken 48744 times.
✓ Branch 4 → 7 taken 121540 times.
170284 if (exprResult.constant != nullptr) {
170 48744 materializeConstant(exprResult);
171 48744 return exprResult.value;
172 }
173
174
3/4
✓ Branch 7 → 8 taken 1603 times.
✓ Branch 7 → 10 taken 119937 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 1603 times.
121540 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
175
176 // De-reference if reference type
177
4/4
✓ Branch 10 → 11 taken 110904 times.
✓ Branch 10 → 13 taken 10636 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 110897 times.
121540 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
178
4/4
✓ Branch 14 → 15 taken 1613 times.
✓ Branch 14 → 24 taken 119927 times.
✓ Branch 15 → 16 taken 1603 times.
✓ Branch 15 → 24 taken 10 times.
121540 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
179
2/4
✓ Branch 19 → 20 taken 1603 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 1603 times.
✗ Branch 20 → 34 not taken.
1603 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
180
181 // Load the value from the pointer
182
1/2
✓ Branch 24 → 25 taken 121540 times.
✗ Branch 24 → 46 not taken.
121540 const QualType referencedType = qualType.removeReferenceWrapper();
183
1/2
✓ Branch 28 → 29 taken 121540 times.
✗ Branch 28 → 40 not taken.
121540 exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile);
184
185 121540 return exprResult.value;
186 }
187
188 12981 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
189 // Visit the given AST node
190
2/4
✓ Branch 2 → 3 taken 12981 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 12981 times.
✗ Branch 3 → 9 not taken.
12981 auto exprResult = any_cast<LLVMExprResult>(visit(node));
191
1/2
✓ Branch 5 → 6 taken 12981 times.
✗ Branch 5 → 12 not taken.
25962 return resolveAddress(exprResult);
192 }
193
194 95079 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
195 // Check if an address is already present
196
2/2
✓ Branch 2 → 3 taken 78136 times.
✓ Branch 2 → 4 taken 16943 times.
95079 if (exprResult.ptr != nullptr)
197 78136 return exprResult.ptr;
198
199 // Check if the reference address is already present
200
3/4
✓ Branch 4 → 5 taken 12589 times.
✓ Branch 4 → 7 taken 4354 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 12589 times.
16943 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
201
3/4
✓ Branch 8 → 9 taken 13505 times.
✓ Branch 8 → 18 taken 3438 times.
✓ Branch 9 → 10 taken 13505 times.
✗ Branch 9 → 18 not taken.
16943 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
202
2/4
✓ Branch 13 → 14 taken 13505 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 13505 times.
✗ Branch 14 → 35 not taken.
13505 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
203 13505 return exprResult.ptr;
204 }
205
206 // If not, store the value or constant
207 3438 materializeConstant(exprResult);
208
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 3438 times.
3438 assert(exprResult.value != nullptr);
209
7/12
✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 3432 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 3432 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 3438 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 3432 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
6870 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
210 3438 insertStore(exprResult.value, exprResult.ptr, isVolatile);
211
212 3438 return exprResult.ptr;
213 }
214
215 7534 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
216 // Double
217
2/2
✓ Branch 3 → 4 taken 16 times.
✓ Branch 3 → 9 taken 7518 times.
7534 if (symbolType.is(TY_DOUBLE))
218
2/4
✓ Branch 4 → 5 taken 16 times.
✗ Branch 4 → 129 not taken.
✓ Branch 5 → 6 taken 16 times.
✗ Branch 5 → 127 not taken.
16 return llvm::ConstantFP::get(context, llvm::APFloat(0.0));
219
220 // Int
221
2/2
✓ Branch 10 → 11 taken 724 times.
✓ Branch 10 → 13 taken 6794 times.
7518 if (symbolType.is(TY_INT))
222 724 return builder.getInt32(0);
223
224 // Short
225
2/2
✓ Branch 14 → 15 taken 9 times.
✓ Branch 14 → 17 taken 6785 times.
6794 if (symbolType.is(TY_SHORT))
226 9 return builder.getInt16(0);
227
228 // Long
229
2/2
✓ Branch 18 → 19 taken 2652 times.
✓ Branch 18 → 21 taken 4133 times.
6785 if (symbolType.is(TY_LONG))
230 2652 return builder.getInt64(0);
231
232 // Byte or char
233
3/4
✓ Branch 21 → 22 taken 4133 times.
✗ Branch 21 → 130 not taken.
✓ Branch 22 → 23 taken 90 times.
✓ Branch 22 → 25 taken 4043 times.
4133 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
234 90 return builder.getInt8(0);
235
236 // String
237
2/2
✓ Branch 26 → 27 taken 742 times.
✓ Branch 26 → 35 taken 3301 times.
4043 if (symbolType.is(TY_STRING)) {
238
3/6
✓ Branch 27 → 28 taken 742 times.
✗ Branch 27 → 132 not taken.
✓ Branch 28 → 29 taken 742 times.
✗ Branch 28 → 131 not taken.
✓ Branch 29 → 30 taken 742 times.
✗ Branch 29 → 131 not taken.
742 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
239
1/2
✓ Branch 30 → 31 taken 742 times.
✗ Branch 30 → 34 not taken.
742 if (cliOptions.comparableOutput)
240
2/4
✓ Branch 31 → 32 taken 742 times.
✗ Branch 31 → 133 not taken.
✓ Branch 32 → 33 taken 742 times.
✗ Branch 32 → 133 not taken.
742 globalString->setAlignment(llvm::Align(4));
241 742 return globalString;
242 }
243
244 // Bool
245
2/2
✓ Branch 36 → 37 taken 88 times.
✓ Branch 36 → 39 taken 3213 times.
3301 if (symbolType.is(TY_BOOL))
246 88 return builder.getFalse();
247
248 // Pointer or reference
249
3/4
✓ Branch 39 → 40 taken 3213 times.
✗ Branch 39 → 134 not taken.
✓ Branch 40 → 41 taken 3054 times.
✓ Branch 40 → 44 taken 159 times.
3213 if (symbolType.isOneOf({TY_PTR, TY_REF}))
250 3054 return llvm::Constant::getNullValue(builder.getPtrTy());
251
252 // Array
253
2/2
✓ Branch 45 → 46 taken 53 times.
✓ Branch 45 → 61 taken 106 times.
159 if (symbolType.isArray()) {
254 // Get array size
255
1/2
✓ Branch 46 → 47 taken 53 times.
✗ Branch 46 → 143 not taken.
53 const size_t arraySize = symbolType.getArraySize();
256
257 // Get default value for item
258
2/4
✓ Branch 47 → 48 taken 53 times.
✗ Branch 47 → 135 not taken.
✓ Branch 48 → 49 taken 53 times.
✗ Branch 48 → 135 not taken.
53 llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained());
259
260 // Retrieve array and item type
261
2/4
✓ Branch 49 → 50 taken 53 times.
✗ Branch 49 → 136 not taken.
✓ Branch 50 → 51 taken 53 times.
✗ Branch 50 → 136 not taken.
53 llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile);
262
1/2
✓ Branch 51 → 52 taken 53 times.
✗ Branch 51 → 143 not taken.
53 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize);
263
264 // Create a constant array with n times the default value
265
1/2
✓ Branch 54 → 55 taken 53 times.
✗ Branch 54 → 137 not taken.
106 const std::vector itemConstants(arraySize, defaultItemValue);
266
1/2
✓ Branch 57 → 58 taken 53 times.
✗ Branch 57 → 140 not taken.
53 return llvm::ConstantArray::get(arrayType, itemConstants);
267 53 }
268
269 // Function or procedure
270
3/4
✓ Branch 61 → 62 taken 106 times.
✗ Branch 61 → 144 not taken.
✓ Branch 62 → 63 taken 58 times.
✓ Branch 62 → 70 taken 48 times.
106 if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
271
2/4
✓ Branch 63 → 64 taken 58 times.
✗ Branch 63 → 145 not taken.
✓ Branch 64 → 65 taken 58 times.
✗ Branch 64 → 145 not taken.
58 llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR));
272 58 llvm::Constant *sizeDefaultValue = builder.getInt64(0);
273
1/2
✓ Branch 67 → 68 taken 58 times.
✗ Branch 67 → 146 not taken.
58 return llvm::ConstantStruct::get(llvmTypes.lambdaFatPtrType, {ptrDefaultValue, ptrDefaultValue, sizeDefaultValue});
274 }
275
276 // Struct
277
2/2
✓ Branch 71 → 72 taken 47 times.
✓ Branch 71 → 110 taken 1 time.
48 if (symbolType.is(TY_STRUCT)) {
278 // Retrieve field count
279
1/2
✓ Branch 72 → 73 taken 47 times.
✗ Branch 72 → 153 not taken.
47 Scope *structScope = symbolType.getBodyScope();
280
1/2
✗ Branch 73 → 74 not taken.
✓ Branch 73 → 75 taken 47 times.
47 assert(structScope != nullptr);
281
1/2
✓ Branch 75 → 76 taken 47 times.
✗ Branch 75 → 153 not taken.
47 const size_t fieldCount = structScope->getFieldCount();
282
283 // Get default values for all fields of the struct
284 47 std::vector<llvm::Constant *> fieldConstants;
285
1/2
✓ Branch 76 → 77 taken 47 times.
✗ Branch 76 → 151 not taken.
47 fieldConstants.reserve(fieldCount);
286
287 // Add default value for each struct field
288
2/2
✓ Branch 102 → 78 taken 105 times.
✓ Branch 102 → 103 taken 47 times.
152 for (size_t i = 0; i < fieldCount; i++) {
289 // Get entry of the field
290
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 105 times.
105 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
291
3/6
✓ Branch 83 → 84 taken 105 times.
✗ Branch 83 → 87 not taken.
✓ Branch 84 → 85 taken 105 times.
✗ Branch 84 → 149 not taken.
✓ Branch 85 → 86 taken 105 times.
✗ Branch 85 → 87 not taken.
105 assert(fieldEntry != nullptr && fieldEntry->isField());
292
293 // Retrieve default field value
294 llvm::Constant *defaultFieldValue;
295
4/6
✓ Branch 88 → 89 taken 105 times.
✗ Branch 88 → 90 not taken.
✓ Branch 91 → 92 taken 105 times.
✗ Branch 91 → 97 not taken.
✓ Branch 92 → 93 taken 3 times.
✓ Branch 92 → 97 taken 102 times.
105 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue)
296
3/6
✓ Branch 93 → 94 taken 3 times.
✗ Branch 93 → 149 not taken.
✓ Branch 94 → 95 taken 3 times.
✗ Branch 94 → 148 not taken.
✓ Branch 95 → 96 taken 3 times.
✗ Branch 95 → 148 not taken.
3 defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(manIdx), fieldEntry->getQualType(), fieldNode);
297 else
298
2/4
✓ Branch 97 → 98 taken 102 times.
✗ Branch 97 → 149 not taken.
✓ Branch 98 → 99 taken 102 times.
✗ Branch 98 → 149 not taken.
102 defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType());
299
300
1/2
✓ Branch 100 → 101 taken 105 times.
✗ Branch 100 → 149 not taken.
105 fieldConstants.push_back(defaultFieldValue);
301 }
302
303
2/4
✓ Branch 103 → 104 taken 47 times.
✗ Branch 103 → 151 not taken.
✓ Branch 104 → 105 taken 47 times.
✗ Branch 104 → 151 not taken.
47 const auto structType = llvm::cast<llvm::StructType>(symbolType.toLLVMType(sourceFile));
304
1/2
✓ Branch 106 → 107 taken 47 times.
✗ Branch 106 → 150 not taken.
47 return llvm::ConstantStruct::get(structType, fieldConstants);
305 47 }
306
307 // Interface
308
1/2
✓ Branch 111 → 112 taken 1 time.
✗ Branch 111 → 118 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
309 1 const auto structType = llvm::cast<llvm::StructType>(symbolType.toLLVMType(sourceFile));
310 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
311 }
312
313 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
314 }
315
316 46070 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
317
2/2
✓ Branch 3 → 4 taken 1760 times.
✓ Branch 3 → 9 taken 44310 times.
46070 if (type.is(TY_DOUBLE))
318
2/4
✓ Branch 4 → 5 taken 1760 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 1760 times.
✗ Branch 5 → 54 not taken.
1760 return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue));
319
320
2/2
✓ Branch 10 → 11 taken 7830 times.
✓ Branch 10 → 13 taken 36480 times.
44310 if (type.is(TY_INT))
321 7830 return builder.getInt32(compileTimeValue.intValue);
322
323
2/2
✓ Branch 14 → 15 taken 1217 times.
✓ Branch 14 → 17 taken 35263 times.
36480 if (type.is(TY_SHORT))
324 1217 return builder.getInt16(compileTimeValue.shortValue);
325
326
2/2
✓ Branch 18 → 19 taken 16727 times.
✓ Branch 18 → 21 taken 18536 times.
35263 if (type.is(TY_LONG))
327 16727 return builder.getInt64(compileTimeValue.longValue);
328
329
3/4
✓ Branch 21 → 22 taken 18536 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 4663 times.
✓ Branch 22 → 25 taken 13873 times.
18536 if (type.isOneOf({TY_BYTE, TY_CHAR}))
330 4663 return builder.getInt8(compileTimeValue.charValue);
331
332
2/2
✓ Branch 26 → 27 taken 8977 times.
✓ Branch 26 → 36 taken 4896 times.
13873 if (type.is(TY_STRING)) {
333 8977 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
334
2/4
✓ Branch 30 → 31 taken 8977 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 8977 times.
✗ Branch 31 → 58 not taken.
26931 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
335 }
336
337
1/2
✓ Branch 37 → 38 taken 4896 times.
✗ Branch 37 → 40 not taken.
4896 if (type.is(TY_BOOL))
338 4896 return builder.getInt1(compileTimeValue.boolValue);
339
340 if (type.is(TY_PTR))
341 return llvm::Constant::getNullValue(builder.getPtrTy());
342
343 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
344 }
345
346 96992 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
347
2/4
✓ Branch 2 → 3 taken 96992 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 96992 times.
✗ Branch 3 → 7 not taken.
96992 return llvm::BasicBlock::Create(context, blockName);
348 }
349
350 96992 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
351
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 96992 times.
96992 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
352 // If no parent function were passed, use the current function
353
2/2
✓ Branch 5 → 6 taken 62702 times.
✓ Branch 5 → 8 taken 34290 times.
96992 if (!parentFct)
354 62702 parentFct = builder.GetInsertBlock()->getParent();
355 // Append block to current function
356 96992 parentFct->insert(parentFct->end(), block);
357 // Set insert point to the block
358 96992 builder.SetInsertPoint(block);
359 96992 blockAlreadyTerminated = false;
360 96992 }
361
362 29140 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
363 29140 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
364 29140 generateScopeCleanup(stmtLstNode);
365 29140 blockAlreadyTerminated = true;
366 29140 }
367
368 32272 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
369
2/2
✓ Branch 2 → 3 taken 8990 times.
✓ Branch 2 → 4 taken 23282 times.
32272 if (blockAlreadyTerminated)
370 8990 return;
371 23282 builder.CreateBr(targetBlock);
372 23282 blockAlreadyTerminated = true;
373 }
374
375 26532 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
376 Likelihood likelihood /*=UNSPECIFIED*/) {
377
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 26532 times.
26532 if (blockAlreadyTerminated)
378 return;
379 26532 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
380 26532 blockAlreadyTerminated = true;
381
382
2/2
✓ Branch 5 → 6 taken 4766 times.
✓ Branch 5 → 7 taken 21766 times.
26532 if (likelihood != Likelihood::UNSPECIFIED)
383 4766 mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood);
384 }
385
386 34277 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
387 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
388
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 34277 times.
34277 if (cliOptions.disableVerifier)
389 return;
390
391 // Verify function
392 34277 std::string output;
393
1/2
✓ Branch 5 → 6 taken 34277 times.
✗ Branch 5 → 20 not taken.
34277 llvm::raw_string_ostream oss(output);
394 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
395 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
396 34277 }
397
398 2157 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
399 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
400
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 2157 times.
2157 if (cliOptions.disableVerifier)
401 return;
402
403 // Verify module
404 2157 std::string output;
405
1/2
✓ Branch 5 → 6 taken 2157 times.
✗ Branch 5 → 20 not taken.
2157 llvm::raw_string_ostream oss(output);
406 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
407 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
408 2157 }
409
410 16885 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
411 // Get entry of left side
412
2/4
✓ Branch 2 → 3 taken 16885 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 16885 times.
✗ Branch 3 → 16 not taken.
16885 auto exprResult = std::any_cast<LLVMExprResult>(visit(lhsNode));
413 16885 SymbolTableEntry *entry = exprResult.entry;
414
7/10
✓ Branch 5 → 6 taken 15456 times.
✓ Branch 5 → 10 taken 1429 times.
✓ Branch 6 → 7 taken 15456 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 15456 times.
✗ Branch 7 → 19 not taken.
✓ Branch 8 → 9 taken 1292 times.
✓ Branch 8 → 10 taken 14164 times.
✓ Branch 10 → 11 taken 15593 times.
✗ Branch 10 → 19 not taken.
16885 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? exprResult.refPtr : resolveAddress(exprResult);
415
1/2
✓ Branch 12 → 13 taken 16885 times.
✗ Branch 12 → 19 not taken.
33770 return doAssignment(lhsAddress, entry, rhsNode, node);
416 }
417
418 39190 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
419 const ASTNode *node, bool isDecl) {
420 // Get symbol type of right side
421
1/2
✓ Branch 2 → 3 taken 39190 times.
✗ Branch 2 → 13 not taken.
39190 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
422
2/4
✓ Branch 3 → 4 taken 39190 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 39190 times.
✗ Branch 4 → 10 not taken.
39190 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
423
1/2
✓ Branch 6 → 7 taken 39190 times.
✗ Branch 6 → 13 not taken.
78380 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
424 }
425
426 39968 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
427 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
428 // Deduce some information about the assignment
429
4/4
✓ Branch 2 → 3 taken 38539 times.
✓ Branch 2 → 7 taken 1429 times.
✓ Branch 5 → 6 taken 2947 times.
✓ Branch 5 → 7 taken 35592 times.
39968 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
430
8/10
✓ Branch 8 → 9 taken 37021 times.
✓ Branch 8 → 15 taken 2947 times.
✓ Branch 9 → 10 taken 37021 times.
✗ Branch 9 → 247 not taken.
✓ Branch 10 → 11 taken 37021 times.
✗ Branch 10 → 247 not taken.
✓ Branch 11 → 12 taken 6051 times.
✓ Branch 11 → 15 taken 30970 times.
✓ Branch 13 → 14 taken 670 times.
✓ Branch 13 → 15 taken 5381 times.
39968 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
431
432
2/2
✓ Branch 16 → 17 taken 2947 times.
✓ Branch 16 → 57 taken 37021 times.
39968 if (isRefAssign) {
433
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 2947 times.
2947 assert(lhsEntry != nullptr);
434
2/2
✓ Branch 19 → 20 taken 1655 times.
✓ Branch 19 → 33 taken 1292 times.
2947 if (isDecl) { // Reference gets initially assigned
435 // Get address of right side
436 1655 llvm::Value *rhsAddress = resolveAddress(rhs);
437
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 1655 times.
1655 assert(rhsAddress != nullptr);
438
439 // Store lhs pointer to rhs
440
2/4
✓ Branch 26 → 27 taken 1655 times.
✗ Branch 26 → 248 not taken.
✓ Branch 27 → 28 taken 1655 times.
✗ Branch 27 → 248 not taken.
1655 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
441 1655 lhsEntry->updateAddress(refAddress);
442 1655 insertStore(rhsAddress, refAddress);
443
444 1655 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
445 }
446
447 // Reference to reference assignment (only for struct fields that are not initialized yet)
448 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
449
6/8
✓ Branch 33 → 34 taken 1034 times.
✓ Branch 33 → 40 taken 258 times.
✓ Branch 35 → 36 taken 1034 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 997 times.
✓ Branch 36 → 40 taken 37 times.
✓ Branch 38 → 39 taken 997 times.
✗ Branch 38 → 40 not taken.
1292 const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField();
450 // Assigning the result variable
451 1292 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
452
4/4
✓ Branch 42 → 43 taken 295 times.
✓ Branch 42 → 44 taken 997 times.
✓ Branch 43 → 44 taken 11 times.
✓ Branch 43 → 49 taken 284 times.
1292 if (isInitialFieldRefAssign || isReturnValAssign) {
453 // Get address of right side
454 1008 llvm::Value *referencedAddress = resolveAddress(rhs);
455
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 1008 times.
1008 assert(referencedAddress != nullptr);
456
457 // Store the rhs* to the lhs**
458 1008 insertStore(referencedAddress, lhsAddress);
459
460 1008 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
461 }
462
463 // Load referenced address
464
2/4
✓ Branch 52 → 53 taken 284 times.
✗ Branch 52 → 254 not taken.
✓ Branch 53 → 54 taken 284 times.
✗ Branch 53 → 254 not taken.
284 lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress);
465 }
466
467
8/8
✓ Branch 57 → 58 taken 21428 times.
✓ Branch 57 → 63 taken 15877 times.
✓ Branch 59 → 60 taken 3299 times.
✓ Branch 59 → 63 taken 18129 times.
✓ Branch 61 → 62 taken 3288 times.
✓ Branch 61 → 63 taken 11 times.
✓ Branch 64 → 65 taken 3288 times.
✓ Branch 64 → 70 taken 34017 times.
37305 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
468
1/2
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 3288 times.
3288 assert(lhsEntry != nullptr);
469 // Directly set the address to the lhs entry (temp stealing)
470 3288 llvm::Value *rhsAddress = resolveAddress(rhs);
471 3288 lhsEntry->updateAddress(rhsAddress);
472 3288 rhs.entry = lhsEntry;
473 3288 return rhs;
474 }
475
476 // Allocate new memory if the lhs address does not exist
477
2/2
✓ Branch 70 → 71 taken 17845 times.
✓ Branch 70 → 81 taken 16172 times.
34017 if (!lhsAddress) {
478
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 17845 times.
17845 assert(lhsEntry != nullptr);
479
2/4
✓ Branch 76 → 77 taken 17845 times.
✗ Branch 76 → 260 not taken.
✓ Branch 77 → 78 taken 17845 times.
✗ Branch 77 → 260 not taken.
17845 lhsAddress = insertAlloca(lhsEntry->getQualType());
480 17845 lhsEntry->updateAddress(lhsAddress);
481 }
482
483 // 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
484
10/10
✓ Branch 81 → 82 taken 32588 times.
✓ Branch 81 → 90 taken 1429 times.
✓ Branch 84 → 85 taken 7719 times.
✓ Branch 84 → 90 taken 24869 times.
✓ Branch 86 → 87 taken 7 times.
✓ Branch 86 → 90 taken 7712 times.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 88 → 90 taken 5 times.
✓ Branch 91 → 92 taken 2 times.
✓ Branch 91 → 107 taken 34015 times.
34017 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
485 // Get address of right side
486
1/2
✓ Branch 92 → 93 taken 2 times.
✗ Branch 92 → 273 not taken.
2 llvm::Value *rhsAddress = resolveAddress(rhs);
487
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 2 times.
2 assert(rhsAddress != nullptr);
488
1/2
✓ Branch 95 → 96 taken 2 times.
✗ Branch 95 → 273 not taken.
2 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
489
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)};
490
1/2
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 266 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
491
1/2
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 273 not taken.
2 insertStore(firstItemAddress, lhsAddress);
492 2 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
493 }
494
495 // Handle operator overloads
496
6/6
✓ Branch 107 → 108 taken 15877 times.
✓ Branch 107 → 111 taken 18138 times.
✓ Branch 109 → 110 taken 411 times.
✓ Branch 109 → 111 taken 15466 times.
✓ Branch 112 → 113 taken 411 times.
✓ Branch 112 → 129 taken 33604 times.
34015 if (!isDecl && conversionManager.callsOverloadedOpFct(node, DEFAULT_OP_IDX)) {
497 411 ResolverFct lhsV = [&] { return static_cast<llvm::Value *>(nullptr); };
498
1/2
✓ Branch 114 → 115 taken 411 times.
✗ Branch 114 → 274 not taken.
411 ResolverFct rhsV = [&] { return resolveValue(rhsSType, rhs); };
499 822 ResolverFct lhsP = [&] { return lhsAddress; };
500 822 ResolverFct rhsP = [&] { return resolveAddress(rhs); };
501 411 return conversionManager.callOperatorOverloadFct<2>(node, {lhsV, lhsP, rhsV, rhsP}, DEFAULT_OP_IDX);
502 411 }
503
504 // Check if we need to copy the rhs to the lhs. This happens for structs
505
2/2
✓ Branch 129 → 130 taken 448 times.
✓ Branch 129 → 215 taken 33156 times.
33604 if (needsCopy) {
506 // Get address of right side
507
1/2
✓ Branch 130 → 131 taken 448 times.
✗ Branch 130 → 350 not taken.
448 llvm::Value *rhsAddress = resolveAddress(rhs);
508
1/2
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 133 taken 448 times.
448 assert(rhsAddress != nullptr);
509
510 // If the lhs already holds an initialized, non-trivially-destructible struct, its old value must be
511 // destructed before the copy overwrites it, otherwise its owning members (heap pointers, strings, ...)
512 // would leak. The typechecker only sets a dtor in exactly those cases. To stay correct for a self-
513 // assignment like 'a = a', the destruct + copy are skipped entirely when both sides share the address
514 // (the assignment is a no-op in that case, and destructing first would corrupt the value to copy from).
515
1/2
✓ Branch 133 → 134 taken 448 times.
✗ Branch 133 → 135 not taken.
448 const auto *assignNode = dynamic_cast<const AssignExprNode *>(node);
516
3/4
✓ Branch 136 → 137 taken 437 times.
✓ Branch 136 → 139 taken 11 times.
✓ Branch 137 → 138 taken 437 times.
✗ Branch 137 → 350 not taken.
448 const Function *lhsDtor = assignNode ? assignNode->lhsDtorFct.at(manIdx) : nullptr;
517 448 llvm::BasicBlock *bCopyEnd = nullptr;
518
2/2
✓ Branch 140 → 141 taken 10 times.
✓ Branch 140 → 161 taken 438 times.
448 if (lhsDtor != nullptr) {
519
2/4
✓ Branch 143 → 144 taken 10 times.
✗ Branch 143 → 294 not taken.
✓ Branch 144 → 145 taken 10 times.
✗ Branch 144 → 292 not taken.
20 llvm::BasicBlock *bCopy = createBlock("assign.copy");
520
2/4
✓ Branch 149 → 150 taken 10 times.
✗ Branch 149 → 300 not taken.
✓ Branch 150 → 151 taken 10 times.
✗ Branch 150 → 298 not taken.
10 bCopyEnd = createBlock("assign.copy.end");
521
3/6
✓ Branch 153 → 154 taken 10 times.
✗ Branch 153 → 304 not taken.
✓ Branch 154 → 155 taken 10 times.
✗ Branch 154 → 304 not taken.
✓ Branch 155 → 156 taken 10 times.
✗ Branch 155 → 304 not taken.
10 insertCondJump(builder.CreateICmpEQ(lhsAddress, rhsAddress), bCopyEnd, bCopy);
522
1/2
✓ Branch 156 → 157 taken 10 times.
✗ Branch 156 → 350 not taken.
10 switchToBlock(bCopy);
523
1/2
✓ Branch 158 → 159 taken 10 times.
✗ Branch 158 → 305 not taken.
10 generateCtorOrDtorCall(lhsAddress, lhsDtor, {});
524 }
525
526
2/4
✓ Branch 161 → 162 taken 448 times.
✗ Branch 161 → 308 not taken.
✓ Branch 162 → 163 taken 448 times.
✗ Branch 162 → 308 not taken.
448 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
527
3/4
✓ Branch 163 → 164 taken 448 times.
✗ Branch 163 → 350 not taken.
✓ Branch 164 → 165 taken 317 times.
✓ Branch 164 → 181 taken 131 times.
448 if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
528 // Create shallow copy
529
1/2
✓ Branch 165 → 166 taken 317 times.
✗ Branch 165 → 316 not taken.
317 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
530
3/10
✓ Branch 166 → 167 taken 317 times.
✗ Branch 166 → 168 not taken.
✓ Branch 167 → 171 taken 317 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 317 times.
✗ Branch 309 → 310 not taken.
✗ Branch 309 → 312 not taken.
317 const std::string copyName = lhsEntry ? lhsEntry->name : "";
531
3/6
✓ Branch 174 → 175 taken 317 times.
✗ Branch 174 → 177 not taken.
✗ Branch 175 → 176 not taken.
✓ Branch 175 → 177 taken 317 times.
✓ Branch 178 → 179 taken 317 times.
✗ Branch 178 → 314 not taken.
317 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
532 317 } else {
533 // Check if we have a copy ctor
534
1/2
✓ Branch 181 → 182 taken 131 times.
✗ Branch 181 → 349 not taken.
131 Scope *structScope = rhsSTypeNonRef.getBodyScope();
535
2/4
✓ Branch 182 → 183 taken 131 times.
✗ Branch 182 → 321 not taken.
✓ Branch 187 → 188 taken 131 times.
✗ Branch 187 → 317 not taken.
393 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
536
2/4
✓ Branch 191 → 192 taken 131 times.
✗ Branch 191 → 325 not taken.
✓ Branch 192 → 193 taken 131 times.
✗ Branch 192 → 323 not taken.
131 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
537
1/2
✓ Branch 195 → 196 taken 131 times.
✗ Branch 195 → 204 not taken.
131 if (copyCtor != nullptr) {
538 // Call copy ctor
539
2/4
✓ Branch 198 → 199 taken 131 times.
✗ Branch 198 → 331 not taken.
✓ Branch 199 → 200 taken 131 times.
✗ Branch 199 → 329 not taken.
262 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
540 } else {
541 const std::string structName = rhsSTypeNonRef.getName();
542 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
543 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
544 }
545 131 }
546
547 // Close the self-assignment guard
548
2/2
✓ Branch 211 → 212 taken 10 times.
✓ Branch 211 → 214 taken 438 times.
448 if (bCopyEnd != nullptr) {
549
1/2
✓ Branch 212 → 213 taken 10 times.
✗ Branch 212 → 350 not taken.
10 insertJump(bCopyEnd);
550
1/2
✓ Branch 213 → 214 taken 10 times.
✗ Branch 213 → 350 not taken.
10 switchToBlock(bCopyEnd);
551 }
552 448 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
553 }
554
555 // Optimization: If we have the address of both sides, we can do a memcpy instead of loading and storing the value
556 33156 llvm::Value *rhsValue = nullptr;
557
8/8
✓ Branch 216 → 217 taken 1815 times.
✓ Branch 216 → 220 taken 31341 times.
✓ Branch 217 → 218 taken 1753 times.
✓ Branch 217 → 220 taken 62 times.
✓ Branch 218 → 219 taken 1746 times.
✓ Branch 218 → 220 taken 7 times.
✓ Branch 221 → 222 taken 1746 times.
✓ Branch 221 → 243 taken 31410 times.
33156 if (rhsSType.is(TY_STRUCT) && rhs.value == nullptr && rhs.constant == nullptr) {
558 // Create shallow copy
559
2/4
✓ Branch 222 → 223 taken 1746 times.
✗ Branch 222 → 351 not taken.
✓ Branch 223 → 224 taken 1746 times.
✗ Branch 223 → 351 not taken.
1746 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
560
1/2
✓ Branch 224 → 225 taken 1746 times.
✗ Branch 224 → 359 not taken.
1746 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
561
1/2
✓ Branch 225 → 226 taken 1746 times.
✗ Branch 225 → 359 not taken.
1746 llvm::Value *rhsAddress = resolveAddress(rhs);
562
1/2
✗ Branch 226 → 227 not taken.
✓ Branch 226 → 228 taken 1746 times.
1746 assert(rhsAddress != nullptr);
563
6/10
✓ Branch 228 → 229 taken 1737 times.
✓ Branch 228 → 230 taken 9 times.
✓ Branch 229 → 233 taken 1737 times.
✗ Branch 229 → 352 not taken.
✓ Branch 232 → 233 taken 9 times.
✗ Branch 232 → 352 not taken.
✓ Branch 233 → 234 taken 9 times.
✓ Branch 233 → 236 taken 1737 times.
✗ Branch 352 → 353 not taken.
✗ Branch 352 → 355 not taken.
1755 const std::string copyName = lhsEntry ? lhsEntry->name : "";
564
4/6
✓ Branch 236 → 237 taken 1737 times.
✓ Branch 236 → 239 taken 9 times.
✗ Branch 237 → 238 not taken.
✓ Branch 237 → 239 taken 1737 times.
✓ Branch 240 → 241 taken 1746 times.
✗ Branch 240 → 357 not taken.
1746 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
565 1746 } else {
566 // We can load the value from the right side and store it to the left side
567 // Retrieve value of the right side
568 31410 rhsValue = resolveValue(rhsSType, rhs);
569 // Store the value to the address
570 31410 insertStore(rhsValue, lhsAddress, rhsSType);
571 }
572
573 33156 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
574
5/14
✓ Branch 117 → 118 taken 411 times.
✗ Branch 117 → 277 not taken.
✓ Branch 118 → 119 taken 411 times.
✗ Branch 118 → 277 not taken.
✓ Branch 119 → 120 taken 411 times.
✗ Branch 119 → 277 not taken.
✓ Branch 120 → 121 taken 411 times.
✗ Branch 120 → 277 not taken.
✓ Branch 121 → 122 taken 411 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.
411 }
575
576 2442 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
577 bool isVolatile) const {
578 // Retrieve size to copy
579
1/2
✓ Branch 3 → 4 taken 2442 times.
✗ Branch 3 → 19 not taken.
2442 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
580
581 // Create values for memcpy intrinsic
582
2/4
✓ Branch 4 → 5 taken 2442 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 2442 times.
✗ Branch 5 → 19 not taken.
2442 llvm::Value *structSize = builder.getInt64(typeSize);
583
1/2
✓ Branch 6 → 7 taken 2442 times.
✗ Branch 6 → 19 not taken.
2442 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
584
585 // Call memcpy intrinsic to execute the shallow copy
586
1/2
✓ Branch 7 → 8 taken 2442 times.
✗ Branch 7 → 19 not taken.
2442 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
587
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 2442 times.
2442 assert(targetAddress != nullptr);
588
3/6
✓ Branch 10 → 11 taken 2442 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 2442 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 2442 times.
✗ Branch 13 → 15 not taken.
2442 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
589 2442 }
590
591 82967 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) {
592
6/6
✓ Branch 12 → 13 taken 87783 times.
✓ Branch 12 → 15 taken 54878 times.
✓ Branch 14 → 15 taken 4816 times.
✓ Branch 14 → 16 taken 82967 times.
✓ Branch 17 → 3 taken 59694 times.
✓ Branch 17 → 18 taken 82967 times.
142661 while (symbolType.isPtr() || symbolType.isRef()) {
593
1/2
✓ Branch 6 → 7 taken 59694 times.
✗ Branch 6 → 19 not taken.
59694 ptr = insertLoad(symbolType, ptr);
594
1/2
✓ Branch 9 → 10 taken 59694 times.
✗ Branch 9 → 25 not taken.
59694 symbolType = symbolType.getContained();
595 }
596 82967 }
597
598 304 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
599 // Get unused name
600
1/2
✓ Branch 2 → 3 taken 304 times.
✗ Branch 2 → 19 not taken.
304 const std::string globalName = getUnusedGlobalName(baseName);
601 // Create global
602
1/2
✓ Branch 5 → 6 taken 304 times.
✗ Branch 5 → 15 not taken.
304 module->getOrInsertGlobal(globalName, constant->getType());
603
1/2
✓ Branch 7 → 8 taken 304 times.
✗ Branch 7 → 16 not taken.
304 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
604 // Set initializer to the given constant
605
1/2
✓ Branch 8 → 9 taken 304 times.
✗ Branch 8 → 17 not taken.
304 global->setInitializer(constant);
606 304 global->setConstant(true);
607
1/2
✓ Branch 10 → 11 taken 304 times.
✗ Branch 10 → 17 not taken.
304 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
608 304 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
609 304 return global;
610 304 }
611
612 10217 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
613 // Get unused name
614
1/2
✓ Branch 2 → 3 taken 10217 times.
✗ Branch 2 → 21 not taken.
10217 const std::string globalName = getUnusedGlobalName(baseName);
615 // Create global
616
2/4
✓ Branch 3 → 4 taken 10217 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 10217 times.
✗ Branch 5 → 15 not taken.
10217 builder.CreateGlobalString(value, globalName, 0, module);
617
1/2
✓ Branch 7 → 8 taken 10217 times.
✗ Branch 7 → 17 not taken.
10217 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
618 // If the output should be comparable, fix alignment to 4 bytes
619
1/2
✓ Branch 8 → 9 taken 10217 times.
✗ Branch 8 → 12 not taken.
10217 if (cliOptions.comparableOutput)
620
2/4
✓ Branch 9 → 10 taken 10217 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 10217 times.
✗ Branch 10 → 18 not taken.
10217 global->setAlignment(llvm::Align(4));
621 10217 return global;
622 10217 }
623
624 10217 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
625 const CodeLoc &codeLoc) const {
626 10217 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
627 // Create debug info
628
2/2
✓ Branch 3 → 4 taken 52 times.
✓ Branch 3 → 10 taken 10165 times.
10217 if (cliOptions.instrumentation.generateDebugInfo)
629
3/6
✓ Branch 5 → 6 taken 52 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 52 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 52 times.
✗ Branch 7 → 12 not taken.
52 diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc);
630 10217 return global;
631 }
632
633 17495 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
634 // Find an unused global name
635 17495 std::string globalName;
636 17495 unsigned int suffixNumber = 0;
637 do {
638
1/2
✓ Branch 5 → 6 taken 764705 times.
✗ Branch 5 → 15 not taken.
764705 globalName = baseName + std::to_string(suffixNumber);
639 764705 suffixNumber++;
640
3/4
✓ Branch 10 → 11 taken 764705 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 747210 times.
✓ Branch 11 → 13 taken 17495 times.
764705 } while (module->getNamedGlobal(globalName) != nullptr);
641 17495 return globalName;
642 }
643
644 52182 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
645 // Skip results, that do not contain a constant or already have a value
646
3/4
✓ Branch 2 → 3 taken 49850 times.
✓ Branch 2 → 4 taken 2332 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 49850 times.
52182 if (exprResult.value != nullptr || exprResult.constant == nullptr)
647 2332 return;
648
649 // Default case: the value to the constant
650 49850 exprResult.value = exprResult.constant;
651 }
652
653 41892 bool IRGenerator::isSymbolDSOLocal(bool isPublic) const {
654 // If we are compiling a shared library and export the global symbol, we need to drop dso_local
655 // because it may be interposed by other shared objects by the dynamic linker.
656
3/4
✓ Branch 2 → 3 taken 38039 times.
✓ Branch 2 → 4 taken 3853 times.
✓ Branch 3 → 4 taken 38039 times.
✗ Branch 3 → 5 not taken.
41892 return !(isPublic && cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY);
657 }
658
659 14386 llvm::GlobalValue::LinkageTypes IRGenerator::getSymbolLinkageType(bool isPublic) const {
660
2/2
✓ Branch 2 → 3 taken 11703 times.
✓ Branch 2 → 4 taken 2683 times.
14386 return isPublic ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::PrivateLinkage;
661 }
662
663 6717 llvm::GlobalValue::LinkageTypes IRGenerator::getVTableLinkageType(bool isPublic) const {
664 // VTables, type infos and type info names are ODR entities that may legitimately be emitted in more than one
665 // translation unit (e.g. an interface that is forward-declared in one file and fully defined in another). Giving
666 // them weak ODR linkage lets the linker coalesce the duplicates. On ELF this pairs with the comdat group below; on
667 // MachO, which has no comdat support, the weak/coalesced linkage is what prevents a duplicate-symbol error.
668
2/2
✓ Branch 2 → 3 taken 6639 times.
✓ Branch 2 → 4 taken 78 times.
6717 return isPublic ? llvm::GlobalValue::WeakODRLinkage : llvm::GlobalValue::PrivateLinkage;
669 }
670
671 6717 void IRGenerator::attachComdatToSymbol(llvm::GlobalVariable *global, const std::string &comdatName, bool isPublic) const {
672 // MachO does not support comdat annotations
673
6/6
✓ Branch 2 → 3 taken 6639 times.
✓ Branch 2 → 6 taken 78 times.
✓ Branch 4 → 5 taken 6624 times.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 7 → 8 taken 6624 times.
✓ Branch 7 → 12 taken 93 times.
6717 if (isPublic && cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO)
674
2/4
✓ Branch 9 → 10 taken 6624 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 6624 times.
✗ Branch 10 → 13 not taken.
6624 global->setComdat(module->getOrInsertComdat(comdatName));
675 6717 }
676
677 4162 std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) {
678
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 4162 times.
4162 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
679
3/4
✓ Branch 4 → 5 taken 4162 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 4064 times.
✓ Branch 5 → 7 taken 98 times.
4162 const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget;
680
681 // Backup target triple and data layout
682
1/2
✓ Branch 9 → 10 taken 4162 times.
✗ Branch 9 → 45 not taken.
4162 const llvm::Triple targetTriple = llvmModule->getTargetTriple();
683
1/2
✓ Branch 11 → 12 taken 4162 times.
✗ Branch 11 → 43 not taken.
4162 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
684 // Remove target triple and data layout
685
2/2
✓ Branch 12 → 13 taken 4064 times.
✓ Branch 12 → 19 taken 98 times.
4162 if (eliminateTarget) {
686 4064 llvmModule->setTargetTriple(llvm::Triple());
687
2/4
✓ Branch 16 → 17 taken 4064 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 4064 times.
✗ Branch 17 → 34 not taken.
4064 llvmModule->setDataLayout("");
688 }
689
690 // Get IR string
691 4162 std::string output;
692
1/2
✓ Branch 20 → 21 taken 4162 times.
✗ Branch 20 → 39 not taken.
4162 llvm::raw_string_ostream oss(output);
693
1/2
✓ Branch 21 → 22 taken 4162 times.
✗ Branch 21 → 37 not taken.
4162 llvmModule->print(oss, nullptr);
694
695 // Restore target triple and data layout
696
2/2
✓ Branch 22 → 23 taken 4064 times.
✓ Branch 22 → 29 taken 98 times.
4162 if (eliminateTarget) {
697
1/2
✓ Branch 23 → 24 taken 4064 times.
✗ Branch 23 → 35 not taken.
4064 llvmModule->setTargetTriple(targetTriple);
698
1/2
✓ Branch 27 → 28 taken 4064 times.
✗ Branch 27 → 36 not taken.
4064 llvmModule->setDataLayout(targetDataLayout);
699 }
700
701 4162 return output;
702 4162 }
703
704 /**
705 * Returns the operator function list for the current manifestation and the given node
706 *
707 * @param node Node to retrieve the op fct pointer list from
708 * @return Op fct pointer list
709 */
710 62970 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
711
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 62970 times.
62970 assert(node->getOpFctPointers()->size() > manIdx);
712 62970 return node->getOpFctPointers()->at(manIdx);
713 }
714
715 } // namespace spice::compiler
716