GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.0% 361 / 6 / 378
Functions: 100.0% 40 / 0 / 40
Branches: 63.1% 428 / 20 / 698

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 992 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
17 992 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
18
1/2
✓ Branch 8 → 9 taken 992 times.
✗ Branch 8 → 62 not taken.
992 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
19
6/10
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 990 times.
✓ Branch 9 → 10 taken 992 times.
✗ Branch 9 → 62 not taken.
✓ Branch 10 → 11 taken 992 times.
✗ Branch 10 → 62 not taken.
✓ Branch 11 → 12 taken 992 times.
✗ Branch 11 → 60 not taken.
✓ Branch 15 → 16 taken 992 times.
✗ Branch 15 → 56 not taken.
1984 stdFunctionManager(sourceFile, resourceManager, module) {
20 // Attach information to the module
21
1/2
✓ Branch 17 → 18 taken 992 times.
✗ Branch 17 → 41 not taken.
992 module->setTargetTriple(cliOptions.targetTriple);
22
2/4
✓ Branch 21 → 22 taken 992 times.
✗ Branch 21 → 44 not taken.
✓ Branch 22 → 23 taken 992 times.
✗ Branch 22 → 42 not taken.
992 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
23
1/2
✓ Branch 24 → 25 taken 992 times.
✗ Branch 24 → 52 not taken.
992 module->setPICLevel(llvm::PICLevel::BigPIC);
24
1/2
✓ Branch 25 → 26 taken 992 times.
✗ Branch 25 → 52 not taken.
992 module->setPIELevel(llvm::PIELevel::Large);
25
1/2
✓ Branch 26 → 27 taken 992 times.
✗ Branch 26 → 52 not taken.
992 module->setUwtable(llvm::UWTableKind::Default);
26
1/2
✓ Branch 27 → 28 taken 992 times.
✗ Branch 27 → 52 not taken.
992 module->setFramePointer(llvm::FramePointerKind::All);
27
28 // Add module identifier metadata
29
2/4
✓ Branch 28 → 29 taken 992 times.
✗ Branch 28 → 45 not taken.
✓ Branch 29 → 30 taken 992 times.
✗ Branch 29 → 45 not taken.
992 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
30
3/6
✓ Branch 31 → 32 taken 992 times.
✗ Branch 31 → 46 not taken.
✓ Branch 33 → 34 taken 992 times.
✗ Branch 33 → 46 not taken.
✓ Branch 34 → 35 taken 992 times.
✗ Branch 34 → 46 not taken.
992 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
31
32 // Initialize debug info generator
33
2/2
✓ Branch 35 → 36 taken 24 times.
✓ Branch 35 → 40 taken 968 times.
992 if (cliOptions.instrumentation.generateDebugInfo)
34
2/4
✓ Branch 36 → 37 taken 24 times.
✗ Branch 36 → 51 not taken.
✓ Branch 37 → 38 taken 24 times.
✗ Branch 37 → 49 not taken.
24 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
35 992 }
36
37 992 std::any IRGenerator::visitEntry(const EntryNode *node) {
38 // Generate IR
39
1/2
✓ Branch 2 → 3 taken 992 times.
✗ Branch 2 → 19 not taken.
992 visitChildren(node);
40
41 // Generate test main if required
42
4/4
✓ Branch 4 → 5 taken 258 times.
✓ Branch 4 → 7 taken 734 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 254 times.
992 if (sourceFile->isMainFile && cliOptions.generateTestMain)
43 4 generateTestMain();
44
45 // Execute deferred VTable initializations
46
2/2
✓ Branch 13 → 9 taken 396 times.
✓ Branch 13 → 14 taken 992 times.
1388 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
47
1/2
✓ Branch 10 → 11 taken 396 times.
✗ Branch 10 → 20 not taken.
396 deferredVTableInit.execute();
48
49 // Finalize debug info generator
50 992 diGenerator.finalize();
51
52 // Verify module
53 992 verifyModule(node->codeLoc);
54
55
1/2
✓ Branch 16 → 17 taken 992 times.
✗ Branch 16 → 21 not taken.
992 return nullptr;
56 }
57
58 40378 llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) {
59
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 40378 times.
40378 if (!cliOptions.namesForIRValues)
60 varName = "";
61
62
2/2
✓ Branch 4 → 5 taken 28718 times.
✓ Branch 4 → 12 taken 11660 times.
40378 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
63
2/4
✓ Branch 5 → 6 taken 28718 times.
✗ Branch 5 → 25 not taken.
✓ Branch 6 → 7 taken 28718 times.
✗ Branch 6 → 25 not taken.
28718 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
64
1/2
✓ Branch 8 → 9 taken 28718 times.
✗ Branch 8 → 26 not taken.
28718 allocaInst->setDebugLoc(llvm::DebugLoc());
65 28718 allocaInst->moveAfter(allocaInsertInst);
66 28718 allocaInsertInst = allocaInst;
67 } else { // This is the first alloca inst in the current function -> insert at the entry block
68 // Save current basic block and move insert cursor to entry block of the current function
69 11660 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
70 11660 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
71
72 // Allocate the size of the given LLVM type
73
2/4
✓ Branch 15 → 16 taken 11660 times.
✗ Branch 15 → 29 not taken.
✓ Branch 16 → 17 taken 11660 times.
✗ Branch 16 → 29 not taken.
11660 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
74
1/2
✓ Branch 18 → 19 taken 11660 times.
✗ Branch 18 → 30 not taken.
11660 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
75
76 // Restore old basic block
77 11660 builder.SetInsertPoint(currentBlock);
78 }
79
80 // Insert lifetime start marker
81
2/2
✓ Branch 21 → 22 taken 59 times.
✓ Branch 21 → 23 taken 40319 times.
40378 if (cliOptions.useLifetimeMarkers)
82 59 builder.CreateLifetimeStart(allocaInsertInst);
83
84 40378 return allocaInsertInst;
85 }
86
87 35033 llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) {
88 35033 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
89
2/4
✓ Branch 3 → 4 taken 35033 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 35033 times.
✗ Branch 4 → 10 not taken.
35033 llvm::AllocaInst *alloca = insertAlloca(llvmType, varName);
90
91 // Insert type metadata
92
2/2
✓ Branch 6 → 7 taken 9 times.
✓ Branch 6 → 8 taken 35024 times.
35033 if (cliOptions.useTBAAMetadata)
93 9 mdGenerator.generateTypeMetadata(allocaInsertInst, qualType);
94
95 35033 return alloca;
96 }
97
98 77453 llvm::LoadInst *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile,
99 const std::string &varName) const {
100
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 77453 times.
77453 assert(ptr->getType()->isPointerTy());
101
5/14
✓ Branch 6 → 7 taken 77453 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 11 taken 77453 times.
✗ Branch 7 → 22 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 77453 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 77453 times.
✗ Branch 12 → 20 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 77453 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 25 not taken.
77453 return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : "");
102 }
103
104 70173 llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) {
105 70173 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
106 70173 llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName);
107
2/2
✓ Branch 4 → 5 taken 8 times.
✓ Branch 4 → 6 taken 70165 times.
70173 if (cliOptions.useTBAAMetadata)
108 8 mdGenerator.generateTBAAMetadata(load, qualType);
109 70173 return load;
110 }
111
112 41691 llvm::StoreInst *IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const {
113
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 41691 times.
41691 assert(ptr->getType()->isPointerTy());
114 41691 return builder.CreateStore(val, ptr, isVolatile);
115 }
116
117 12565 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) {
118 12565 llvm::StoreInst *store = insertStore(val, ptr, isVolatile);
119
2/2
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 12556 times.
12565 if (cliOptions.useTBAAMetadata)
120 9 mdGenerator.generateTBAAMetadata(store, qualType);
121 12565 }
122
123 19741 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
124 std::string varName) const {
125
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 19741 times.
19741 assert(basePtr->getType()->isPointerTy());
126
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 19741 times.
19741 assert(!indices.empty());
127
4/6
✓ Branch 4 → 5 taken 19405 times.
✓ Branch 4 → 7 taken 17218 times.
✓ Branch 6 → 7 taken 19405 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 19741 times.
56364 assert(std::ranges::all_of(indices, [](const llvm::Value *index) {
128 const llvm::Type *indexType = index->getType();
129 return indexType->isIntegerTy(32) || indexType->isIntegerTy(64);
130 }));
131
132
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 19741 times.
19741 if (!cliOptions.namesForIRValues)
133 varName.clear();
134
135 // Insert GEP
136
2/4
✓ Branch 14 → 15 taken 19741 times.
✗ Branch 14 → 19 not taken.
✓ Branch 15 → 16 taken 19741 times.
✗ Branch 15 → 19 not taken.
19741 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
137 }
138
139 5575 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const {
140
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5575 times.
5575 assert(basePtr->getType()->isPointerTy());
141
142
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5575 times.
5575 if (!cliOptions.namesForIRValues)
143 varName.clear();
144
145 // If we use index 0 we can use the base pointer directly
146
2/2
✓ Branch 8 → 9 taken 1946 times.
✓ Branch 8 → 10 taken 3629 times.
5575 if (index == 0)
147 1946 return basePtr;
148
149 // Insert GEP
150
2/4
✓ Branch 10 → 11 taken 3629 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3629 times.
✗ Branch 11 → 15 not taken.
3629 return builder.CreateStructGEP(type, basePtr, index, varName);
151 }
152
153 47104 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
154 // Visit the given AST node
155
2/4
✓ Branch 2 → 3 taken 47104 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 47104 times.
✗ Branch 3 → 9 not taken.
47104 auto exprResult = any_cast<LLVMExprResult>(visit(node));
156
1/2
✓ Branch 5 → 6 taken 47104 times.
✗ Branch 5 → 12 not taken.
94208 return resolveValue(node, exprResult);
157 }
158
159 53729 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) {
160 53729 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
161 }
162
163 103670 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) {
164 // Check if the value is already present
165
2/2
✓ Branch 2 → 3 taken 33548 times.
✓ Branch 2 → 4 taken 70122 times.
103670 if (exprResult.value != nullptr)
166 33548 return exprResult.value;
167
168 // Check if a constant is present
169
2/2
✓ Branch 4 → 5 taken 18362 times.
✓ Branch 4 → 7 taken 51760 times.
70122 if (exprResult.constant != nullptr) {
170 18362 materializeConstant(exprResult);
171 18362 return exprResult.value;
172 }
173
174
3/4
✓ Branch 7 → 8 taken 576 times.
✓ Branch 7 → 10 taken 51184 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 576 times.
51760 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
175
176 // De-reference if reference type
177
4/4
✓ Branch 10 → 11 taken 48293 times.
✓ Branch 10 → 13 taken 3467 times.
✓ Branch 11 → 12 taken 10 times.
✓ Branch 11 → 13 taken 48283 times.
51760 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
178
4/4
✓ Branch 14 → 15 taken 580 times.
✓ Branch 14 → 24 taken 51180 times.
✓ Branch 15 → 16 taken 576 times.
✓ Branch 15 → 24 taken 4 times.
51760 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
179
3/6
✓ Branch 18 → 19 taken 576 times.
✗ Branch 18 → 36 not taken.
✓ Branch 19 → 20 taken 576 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 576 times.
✗ Branch 20 → 34 not taken.
1152 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
180
181 // Load the value from the pointer
182
1/2
✓ Branch 24 → 25 taken 51760 times.
✗ Branch 24 → 46 not taken.
51760 const QualType referencedType = qualType.removeReferenceWrapper();
183
2/4
✓ Branch 27 → 28 taken 51760 times.
✗ Branch 27 → 42 not taken.
✓ Branch 28 → 29 taken 51760 times.
✗ Branch 28 → 40 not taken.
51760 exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile);
184
185 51760 return exprResult.value;
186 }
187
188 2989 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
189 // Visit the given AST node
190
2/4
✓ Branch 2 → 3 taken 2989 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2989 times.
✗ Branch 3 → 9 not taken.
2989 auto exprResult = any_cast<LLVMExprResult>(visit(node));
191
1/2
✓ Branch 5 → 6 taken 2989 times.
✗ Branch 5 → 12 not taken.
5978 return resolveAddress(exprResult);
192 }
193
194 22993 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
195 // Check if an address is already present
196
2/2
✓ Branch 2 → 3 taken 19394 times.
✓ Branch 2 → 4 taken 3599 times.
22993 if (exprResult.ptr != nullptr)
197 19394 return exprResult.ptr;
198
199 // Check if the reference address is already present
200
3/4
✓ Branch 4 → 5 taken 2842 times.
✓ Branch 4 → 7 taken 757 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2842 times.
3599 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
201
3/4
✓ Branch 8 → 9 taken 2841 times.
✓ Branch 8 → 18 taken 758 times.
✓ Branch 9 → 10 taken 2841 times.
✗ Branch 9 → 18 not taken.
3599 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
202
3/6
✓ Branch 12 → 13 taken 2841 times.
✗ Branch 12 → 37 not taken.
✓ Branch 13 → 14 taken 2841 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 2841 times.
✗ Branch 14 → 35 not taken.
2841 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
203 2841 return exprResult.ptr;
204 }
205
206 // If not, store the value or constant
207 758 materializeConstant(exprResult);
208
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 758 times.
758 assert(exprResult.value != nullptr);
209
7/12
✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 752 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 752 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 758 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 752 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
1510 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
210 758 insertStore(exprResult.value, exprResult.ptr, isVolatile);
211
212 758 return exprResult.ptr;
213 }
214
215 2659 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
216 // Double
217
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 9 taken 2655 times.
2659 if (symbolType.is(TY_DOUBLE))
218
2/4
✓ Branch 4 → 5 taken 4 times.
✗ Branch 4 → 132 not taken.
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 130 not taken.
4 return llvm::ConstantFP::get(context, llvm::APFloat(0.0));
219
220 // Int
221
2/2
✓ Branch 10 → 11 taken 360 times.
✓ Branch 10 → 13 taken 2295 times.
2655 if (symbolType.is(TY_INT))
222 360 return builder.getInt32(0);
223
224 // Short
225
2/2
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 17 taken 2283 times.
2295 if (symbolType.is(TY_SHORT))
226 12 return builder.getInt16(0);
227
228 // Long
229
2/2
✓ Branch 18 → 19 taken 992 times.
✓ Branch 18 → 21 taken 1291 times.
2283 if (symbolType.is(TY_LONG))
230 992 return builder.getInt64(0);
231
232 // Byte or char
233
3/4
✓ Branch 21 → 22 taken 1291 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 22 → 25 taken 1271 times.
1291 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
234 20 return builder.getInt8(0);
235
236 // String
237
2/2
✓ Branch 26 → 27 taken 392 times.
✓ Branch 26 → 35 taken 879 times.
1271 if (symbolType.is(TY_STRING)) {
238
3/6
✓ Branch 27 → 28 taken 392 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 392 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 392 times.
✗ Branch 29 → 134 not taken.
392 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
239
1/2
✓ Branch 30 → 31 taken 392 times.
✗ Branch 30 → 34 not taken.
392 if (cliOptions.comparableOutput)
240
2/4
✓ Branch 31 → 32 taken 392 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 392 times.
✗ Branch 32 → 136 not taken.
392 globalString->setAlignment(llvm::Align(4));
241 392 return globalString;
242 }
243
244 // Bool
245
2/2
✓ Branch 36 → 37 taken 33 times.
✓ Branch 36 → 39 taken 846 times.
879 if (symbolType.is(TY_BOOL))
246 33 return builder.getFalse();
247
248 // Pointer or reference
249
3/4
✓ Branch 39 → 40 taken 846 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 789 times.
✓ Branch 40 → 44 taken 57 times.
846 if (symbolType.isOneOf({TY_PTR, TY_REF}))
250 789 return llvm::Constant::getNullValue(builder.getPtrTy());
251
252 // Array
253
2/2
✓ Branch 45 → 46 taken 14 times.
✓ Branch 45 → 61 taken 43 times.
57 if (symbolType.isArray()) {
254 // Get array size
255
1/2
✓ Branch 46 → 47 taken 14 times.
✗ Branch 46 → 146 not taken.
14 const size_t arraySize = symbolType.getArraySize();
256
257 // Get default value for item
258
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());
259
260 // Retrieve array and item type
261
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);
262
1/2
✓ Branch 51 → 52 taken 14 times.
✗ Branch 51 → 146 not taken.
14 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 14 times.
✗ Branch 54 → 140 not taken.
14 const std::vector itemConstants(arraySize, defaultItemValue);
266
1/2
✓ Branch 57 → 58 taken 14 times.
✗ Branch 57 → 143 not taken.
14 return llvm::ConstantArray::get(arrayType, itemConstants);
267 14 }
268
269 // Function or procedure
270
3/4
✓ Branch 61 → 62 taken 43 times.
✗ Branch 61 → 147 not taken.
✓ Branch 62 → 63 taken 16 times.
✓ Branch 62 → 75 taken 27 times.
43 if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
271
2/2
✓ Branch 63 → 64 taken 8 times.
✓ Branch 63 → 69 taken 8 times.
16 if (!llvmTypes.fatPtrType)
272
3/6
✓ Branch 64 → 65 taken 8 times.
✗ Branch 64 → 148 not taken.
✓ Branch 65 → 66 taken 8 times.
✗ Branch 65 → 148 not taken.
✓ Branch 67 → 68 taken 8 times.
✗ Branch 67 → 148 not taken.
8 llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()});
273
274
2/4
✓ Branch 69 → 70 taken 16 times.
✗ Branch 69 → 150 not taken.
✓ Branch 70 → 71 taken 16 times.
✗ Branch 70 → 150 not taken.
16 llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR));
275
1/2
✓ Branch 72 → 73 taken 16 times.
✗ Branch 72 → 151 not taken.
16 return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue});
276 }
277
278 // Struct
279
2/2
✓ Branch 76 → 77 taken 26 times.
✓ Branch 76 → 114 taken 1 time.
27 if (symbolType.is(TY_STRUCT)) {
280 // Retrieve field count
281
1/2
✓ Branch 77 → 78 taken 26 times.
✗ Branch 77 → 158 not taken.
26 Scope *structScope = symbolType.getBodyScope();
282
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 26 times.
26 assert(structScope != nullptr);
283
1/2
✓ Branch 80 → 81 taken 26 times.
✗ Branch 80 → 158 not taken.
26 const size_t fieldCount = structScope->getFieldCount();
284
285 // Get default values for all fields of the struct
286 26 std::vector<llvm::Constant *> fieldConstants;
287
1/2
✓ Branch 81 → 82 taken 26 times.
✗ Branch 81 → 156 not taken.
26 fieldConstants.reserve(fieldCount);
288
289 // Add default value for each struct field
290
2/2
✓ Branch 107 → 83 taken 63 times.
✓ Branch 107 → 108 taken 26 times.
89 for (size_t i = 0; i < fieldCount; i++) {
291 // Get entry of the field
292
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 63 times.
63 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
293
3/6
✓ Branch 88 → 89 taken 63 times.
✗ Branch 88 → 92 not taken.
✓ Branch 89 → 90 taken 63 times.
✗ Branch 89 → 154 not taken.
✓ Branch 90 → 91 taken 63 times.
✗ Branch 90 → 92 not taken.
63 assert(fieldEntry != nullptr && fieldEntry->isField());
294
295 // Retrieve default field value
296 llvm::Constant *defaultFieldValue;
297
4/6
✓ Branch 93 → 94 taken 63 times.
✗ Branch 93 → 95 not taken.
✓ Branch 96 → 97 taken 63 times.
✗ Branch 96 → 102 not taken.
✓ Branch 97 → 98 taken 4 times.
✓ Branch 97 → 102 taken 59 times.
63 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue)
298
3/6
✓ Branch 98 → 99 taken 4 times.
✗ Branch 98 → 154 not taken.
✓ Branch 99 → 100 taken 4 times.
✗ Branch 99 → 153 not taken.
✓ Branch 100 → 101 taken 4 times.
✗ Branch 100 → 153 not taken.
4 defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(), fieldEntry->getQualType(), fieldNode);
299 else
300
2/4
✓ Branch 102 → 103 taken 59 times.
✗ Branch 102 → 154 not taken.
✓ Branch 103 → 104 taken 59 times.
✗ Branch 103 → 154 not taken.
59 defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType());
301
302
1/2
✓ Branch 105 → 106 taken 63 times.
✗ Branch 105 → 154 not taken.
63 fieldConstants.push_back(defaultFieldValue);
303 }
304
305
1/2
✓ Branch 108 → 109 taken 26 times.
✗ Branch 108 → 156 not taken.
26 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
306
1/2
✓ Branch 110 → 111 taken 26 times.
✗ Branch 110 → 155 not taken.
26 return llvm::ConstantStruct::get(structType, fieldConstants);
307 26 }
308
309 // Interface
310
1/2
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 121 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
311 1 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
312 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
313 }
314
315 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
316 }
317
318 18455 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
319
2/2
✓ Branch 3 → 4 taken 623 times.
✓ Branch 3 → 9 taken 17832 times.
18455 if (type.is(TY_DOUBLE))
320
2/4
✓ Branch 4 → 5 taken 623 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 623 times.
✗ Branch 5 → 54 not taken.
623 return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue));
321
322
2/2
✓ Branch 10 → 11 taken 3728 times.
✓ Branch 10 → 13 taken 14104 times.
17832 if (type.is(TY_INT))
323 3728 return builder.getInt32(compileTimeValue.intValue);
324
325
2/2
✓ Branch 14 → 15 taken 879 times.
✓ Branch 14 → 17 taken 13225 times.
14104 if (type.is(TY_SHORT))
326 879 return builder.getInt16(compileTimeValue.shortValue);
327
328
2/2
✓ Branch 18 → 19 taken 6586 times.
✓ Branch 18 → 21 taken 6639 times.
13225 if (type.is(TY_LONG))
329 6586 return builder.getInt64(compileTimeValue.longValue);
330
331
3/4
✓ Branch 21 → 22 taken 6639 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2519 times.
✓ Branch 22 → 25 taken 4120 times.
6639 if (type.isOneOf({TY_BYTE, TY_CHAR}))
332 2519 return builder.getInt8(compileTimeValue.charValue);
333
334
2/2
✓ Branch 26 → 27 taken 2137 times.
✓ Branch 26 → 36 taken 1983 times.
4120 if (type.is(TY_STRING)) {
335 2137 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
336
2/4
✓ Branch 30 → 31 taken 2137 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 2137 times.
✗ Branch 31 → 58 not taken.
6411 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
337 }
338
339
1/2
✓ Branch 37 → 38 taken 1983 times.
✗ Branch 37 → 40 not taken.
1983 if (type.is(TY_BOOL))
340 1983 return builder.getInt1(compileTimeValue.boolValue);
341
342 if (type.is(TY_PTR))
343 return llvm::Constant::getNullValue(builder.getPtrTy());
344
345 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
346 }
347
348 34948 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
349
2/4
✓ Branch 2 → 3 taken 34948 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 34948 times.
✗ Branch 3 → 7 not taken.
34948 return llvm::BasicBlock::Create(context, blockName);
350 }
351
352 34948 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
353
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 34948 times.
34948 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
354 // If no parent function were passed, use the current function
355
2/2
✓ Branch 5 → 6 taken 23220 times.
✓ Branch 5 → 8 taken 11728 times.
34948 if (!parentFct)
356 23220 parentFct = builder.GetInsertBlock()->getParent();
357 // Append block to current function
358 34948 parentFct->insert(parentFct->end(), block);
359 // Set insert point to the block
360 34948 builder.SetInsertPoint(block);
361 34948 blockAlreadyTerminated = false;
362 34948 }
363
364 10391 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
365 10391 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
366 10391 generateScopeCleanup(stmtLstNode);
367 10391 blockAlreadyTerminated = true;
368 10391 }
369
370 12851 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
371
2/2
✓ Branch 2 → 3 taken 3674 times.
✓ Branch 2 → 4 taken 9177 times.
12851 if (blockAlreadyTerminated)
372 3674 return;
373 9177 builder.CreateBr(targetBlock);
374 9177 blockAlreadyTerminated = true;
375 }
376
377 9642 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
378 Likelihood likelihood /*=UNSPECIFIED*/) {
379
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 9642 times.
9642 if (blockAlreadyTerminated)
380 return;
381 9642 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
382 9642 blockAlreadyTerminated = true;
383
384
2/2
✓ Branch 5 → 6 taken 1222 times.
✓ Branch 5 → 7 taken 8420 times.
9642 if (likelihood != Likelihood::UNSPECIFIED)
385 1222 mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood);
386 }
387
388 11728 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
389 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
390
4/4
✓ Branch 2 → 3 taken 11727 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 206 times.
✓ Branch 3 → 5 taken 11521 times.
11728 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
391 207 return;
392
393 // Verify function
394 11521 std::string output;
395
1/2
✓ Branch 6 → 7 taken 11521 times.
✗ Branch 6 → 21 not taken.
11521 llvm::raw_string_ostream oss(output);
396 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
397 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
398 11521 }
399
400 992 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
401 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
402
4/4
✓ Branch 2 → 3 taken 991 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 24 times.
✓ Branch 3 → 5 taken 967 times.
992 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
403 25 return;
404
405 // Verify module
406 967 std::string output;
407
1/2
✓ Branch 6 → 7 taken 967 times.
✗ Branch 6 → 21 not taken.
967 llvm::raw_string_ostream oss(output);
408 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
409 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
410 967 }
411
412 5768 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
413 // Get entry of left side
414
2/4
✓ Branch 2 → 3 taken 5768 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 5768 times.
✗ Branch 3 → 15 not taken.
5768 auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode));
415
6/8
✓ Branch 5 → 6 taken 4930 times.
✓ Branch 5 → 10 taken 838 times.
✓ Branch 6 → 7 taken 4930 times.
✗ Branch 6 → 18 not taken.
✓ Branch 7 → 8 taken 4930 times.
✗ Branch 7 → 18 not taken.
✓ Branch 8 → 9 taken 250 times.
✓ Branch 8 → 10 taken 4680 times.
5768 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr;
416
1/2
✓ Branch 11 → 12 taken 5768 times.
✗ Branch 11 → 18 not taken.
11536 return doAssignment(lhsAddress, entry, rhsNode, node);
417 }
418
419 13978 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
420 const ASTNode *node, bool isDecl) {
421 // Get symbol type of right side
422
1/2
✓ Branch 2 → 3 taken 13978 times.
✗ Branch 2 → 13 not taken.
13978 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
423
2/4
✓ Branch 3 → 4 taken 13978 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 13978 times.
✗ Branch 4 → 10 not taken.
13978 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
424
1/2
✓ Branch 6 → 7 taken 13978 times.
✗ Branch 6 → 13 not taken.
27956 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
425 }
426
427 14096 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
428 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
429 // Deduce some information about the assignment
430
4/4
✓ Branch 2 → 3 taken 13258 times.
✓ Branch 2 → 7 taken 838 times.
✓ Branch 5 → 6 taken 504 times.
✓ Branch 5 → 7 taken 12754 times.
14096 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
431
8/10
✓ Branch 8 → 9 taken 13592 times.
✓ Branch 8 → 15 taken 504 times.
✓ Branch 9 → 10 taken 13592 times.
✗ Branch 9 → 195 not taken.
✓ Branch 10 → 11 taken 13592 times.
✗ Branch 10 → 195 not taken.
✓ Branch 11 → 12 taken 1440 times.
✓ Branch 11 → 15 taken 12152 times.
✓ Branch 13 → 14 taken 182 times.
✓ Branch 13 → 15 taken 1258 times.
14096 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
432
433
2/2
✓ Branch 16 → 17 taken 504 times.
✓ Branch 16 → 57 taken 13592 times.
14096 if (isRefAssign) {
434
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 504 times.
504 assert(lhsEntry != nullptr);
435
2/2
✓ Branch 19 → 20 taken 254 times.
✓ Branch 19 → 33 taken 250 times.
504 if (isDecl) { // Reference gets initially assigned
436 // Get address of right side
437 254 llvm::Value *rhsAddress = resolveAddress(rhs);
438
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 254 times.
254 assert(rhsAddress != nullptr);
439
440 // Store lhs pointer to rhs
441
2/4
✓ Branch 26 → 27 taken 254 times.
✗ Branch 26 → 196 not taken.
✓ Branch 27 → 28 taken 254 times.
✗ Branch 27 → 196 not taken.
254 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
442 254 lhsEntry->updateAddress(refAddress);
443 254 insertStore(rhsAddress, refAddress);
444
445 254 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
446 }
447
448 // Reference to reference assignment (only for struct fields that are not initialized yet)
449 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
450
6/8
✓ Branch 33 → 34 taken 173 times.
✓ Branch 33 → 40 taken 77 times.
✓ Branch 35 → 36 taken 173 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 167 times.
✓ Branch 36 → 40 taken 6 times.
✓ Branch 38 → 39 taken 167 times.
✗ Branch 38 → 40 not taken.
250 const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField();
451 // Assigning the result variable
452 250 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
453
4/4
✓ Branch 42 → 43 taken 83 times.
✓ Branch 42 → 44 taken 167 times.
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 49 taken 81 times.
250 if (isInitialFieldRefAssign || isReturnValAssign) {
454 // Get address of right side
455 169 llvm::Value *referencedAddress = resolveAddress(rhs);
456
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 169 times.
169 assert(referencedAddress != nullptr);
457
458 // Store the rhs* to the lhs**
459 169 insertStore(referencedAddress, lhsAddress);
460
461 169 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
462 }
463
464 // Load referenced address
465
3/6
✓ Branch 51 → 52 taken 81 times.
✗ Branch 51 → 204 not taken.
✓ Branch 52 → 53 taken 81 times.
✗ Branch 52 → 202 not taken.
✓ Branch 53 → 54 taken 81 times.
✗ Branch 53 → 202 not taken.
162 lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress);
466 }
467
468
8/8
✓ Branch 57 → 58 taken 8074 times.
✓ Branch 57 → 63 taken 5599 times.
✓ Branch 59 → 60 taken 959 times.
✓ Branch 59 → 63 taken 7115 times.
✓ Branch 61 → 62 taken 955 times.
✓ Branch 61 → 63 taken 4 times.
✓ Branch 64 → 65 taken 955 times.
✓ Branch 64 → 70 taken 12718 times.
13673 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
469
1/2
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 955 times.
955 assert(lhsEntry != nullptr);
470 // Directly set the address to the lhs entry (temp stealing)
471 955 llvm::Value *rhsAddress = resolveAddress(rhs);
472 955 lhsEntry->updateAddress(rhsAddress);
473 955 rhs.entry = lhsEntry;
474 955 return rhs;
475 }
476
477 // Allocate new memory if the lhs address does not exist
478
2/2
✓ Branch 70 → 71 taken 7089 times.
✓ Branch 70 → 81 taken 5629 times.
12718 if (!lhsAddress) {
479
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 7089 times.
7089 assert(lhsEntry != nullptr);
480
3/6
✓ Branch 75 → 76 taken 7089 times.
✗ Branch 75 → 210 not taken.
✓ Branch 76 → 77 taken 7089 times.
✗ Branch 76 → 208 not taken.
✓ Branch 77 → 78 taken 7089 times.
✗ Branch 77 → 208 not taken.
7089 lhsAddress = insertAlloca(lhsEntry->getQualType());
481 7089 lhsEntry->updateAddress(lhsAddress);
482 }
483
484 // 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
485
10/10
✓ Branch 81 → 82 taken 11880 times.
✓ Branch 81 → 90 taken 838 times.
✓ Branch 84 → 85 taken 2282 times.
✓ Branch 84 → 90 taken 9598 times.
✓ Branch 86 → 87 taken 6 times.
✓ Branch 86 → 90 taken 2276 times.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 88 → 90 taken 4 times.
✓ Branch 91 → 92 taken 2 times.
✓ Branch 91 → 107 taken 12716 times.
12718 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
486 // Get address of right side
487
1/2
✓ Branch 92 → 93 taken 2 times.
✗ Branch 92 → 221 not taken.
2 llvm::Value *rhsAddress = resolveAddress(rhs);
488
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 2 times.
2 assert(rhsAddress != nullptr);
489
1/2
✓ Branch 95 → 96 taken 2 times.
✗ Branch 95 → 221 not taken.
2 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
490
2/4
✓ Branch 96 → 97 taken 2 times.
✗ Branch 96 → 221 not taken.
✓ Branch 97 → 98 taken 2 times.
✗ Branch 97 → 221 not taken.
2 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
491
1/2
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 214 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
492
1/2
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 221 not taken.
2 insertStore(firstItemAddress, lhsAddress);
493 2 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
494 }
495
496 // Check if we need to copy the rhs to the lhs. This happens for structs
497
2/2
✓ Branch 107 → 108 taken 182 times.
✓ Branch 107 → 163 taken 12534 times.
12716 if (needsCopy) {
498 // Get address of right side
499
1/2
✓ Branch 108 → 109 taken 182 times.
✗ Branch 108 → 264 not taken.
182 llvm::Value *rhsAddress = resolveAddress(rhs);
500
1/2
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 111 taken 182 times.
182 assert(rhsAddress != nullptr);
501
502
2/4
✓ Branch 111 → 112 taken 182 times.
✗ Branch 111 → 222 not taken.
✓ Branch 112 → 113 taken 182 times.
✗ Branch 112 → 222 not taken.
182 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
503
3/4
✓ Branch 113 → 114 taken 182 times.
✗ Branch 113 → 264 not taken.
✓ Branch 114 → 115 taken 105 times.
✓ Branch 114 → 131 taken 77 times.
182 if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
504 // Create shallow copy
505
1/2
✓ Branch 115 → 116 taken 105 times.
✗ Branch 115 → 230 not taken.
105 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
506
6/10
✓ Branch 116 → 117 taken 100 times.
✓ Branch 116 → 118 taken 5 times.
✓ Branch 117 → 121 taken 100 times.
✗ Branch 117 → 223 not taken.
✓ Branch 120 → 121 taken 5 times.
✗ Branch 120 → 223 not taken.
✓ Branch 121 → 122 taken 5 times.
✓ Branch 121 → 124 taken 100 times.
✗ Branch 223 → 224 not taken.
✗ Branch 223 → 226 not taken.
110 const std::string copyName = lhsEntry ? lhsEntry->name : "";
507
4/6
✓ Branch 124 → 125 taken 100 times.
✓ Branch 124 → 127 taken 5 times.
✗ Branch 125 → 126 not taken.
✓ Branch 125 → 127 taken 100 times.
✓ Branch 128 → 129 taken 105 times.
✗ Branch 128 → 228 not taken.
105 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
508 105 } else {
509 // Check if we have a copy ctor
510
1/2
✓ Branch 131 → 132 taken 77 times.
✗ Branch 131 → 263 not taken.
77 Scope *structScope = rhsSTypeNonRef.getBodyScope();
511
2/4
✓ Branch 132 → 133 taken 77 times.
✗ Branch 132 → 235 not taken.
✓ Branch 137 → 138 taken 77 times.
✗ Branch 137 → 231 not taken.
231 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
512
2/4
✓ Branch 141 → 142 taken 77 times.
✗ Branch 141 → 239 not taken.
✓ Branch 142 → 143 taken 77 times.
✗ Branch 142 → 237 not taken.
77 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
513
1/2
✓ Branch 145 → 146 taken 77 times.
✗ Branch 145 → 153 not taken.
77 if (copyCtor != nullptr) {
514 // Call copy ctor
515
2/4
✓ Branch 148 → 149 taken 77 times.
✗ Branch 148 → 245 not taken.
✓ Branch 149 → 150 taken 77 times.
✗ Branch 149 → 243 not taken.
231 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
516 } else {
517 const std::string structName = rhsSTypeNonRef.getName();
518 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
519 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
520 }
521 77 }
522 182 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
523 }
524
525 // Optimization: If we have the address of both sides, we can do a memcpy instead of loading and storing the value
526 12534 llvm::Value *rhsValue = nullptr;
527
8/8
✓ Branch 164 → 165 taken 253 times.
✓ Branch 164 → 168 taken 12281 times.
✓ Branch 165 → 166 taken 226 times.
✓ Branch 165 → 168 taken 27 times.
✓ Branch 166 → 167 taken 223 times.
✓ Branch 166 → 168 taken 3 times.
✓ Branch 169 → 170 taken 223 times.
✓ Branch 169 → 191 taken 12311 times.
12534 if (rhsSType.is(TY_STRUCT) && rhs.value == nullptr && rhs.constant == nullptr) {
528 // Create shallow copy
529
2/4
✓ Branch 170 → 171 taken 223 times.
✗ Branch 170 → 265 not taken.
✓ Branch 171 → 172 taken 223 times.
✗ Branch 171 → 265 not taken.
223 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
530
1/2
✓ Branch 172 → 173 taken 223 times.
✗ Branch 172 → 273 not taken.
223 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
531
1/2
✓ Branch 173 → 174 taken 223 times.
✗ Branch 173 → 273 not taken.
223 llvm::Value *rhsAddress = resolveAddress(rhs);
532
1/2
✗ Branch 174 → 175 not taken.
✓ Branch 174 → 176 taken 223 times.
223 assert(rhsAddress != nullptr);
533
6/10
✓ Branch 176 → 177 taken 222 times.
✓ Branch 176 → 178 taken 1 time.
✓ Branch 177 → 181 taken 222 times.
✗ Branch 177 → 266 not taken.
✓ Branch 180 → 181 taken 1 time.
✗ Branch 180 → 266 not taken.
✓ Branch 181 → 182 taken 1 time.
✓ Branch 181 → 184 taken 222 times.
✗ Branch 266 → 267 not taken.
✗ Branch 266 → 269 not taken.
224 const std::string copyName = lhsEntry ? lhsEntry->name : "";
534
4/6
✓ Branch 184 → 185 taken 222 times.
✓ Branch 184 → 187 taken 1 time.
✗ Branch 185 → 186 not taken.
✓ Branch 185 → 187 taken 222 times.
✓ Branch 188 → 189 taken 223 times.
✗ Branch 188 → 271 not taken.
223 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
535 223 } else {
536 // We can load the value from the right side and store it to the left side
537 // Retrieve value of the right side
538 12311 rhsValue = resolveValue(rhsSType, rhs);
539 // Store the value to the address
540 12311 insertStore(rhsValue, lhsAddress, rhsSType);
541 }
542
543 12534 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
544 }
545
546 367 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
547 bool isVolatile) const {
548 // Retrieve size to copy
549
1/2
✓ Branch 3 → 4 taken 367 times.
✗ Branch 3 → 19 not taken.
367 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
550
551 // Create values for memcpy intrinsic
552
2/4
✓ Branch 4 → 5 taken 367 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 367 times.
✗ Branch 5 → 19 not taken.
367 llvm::Value *structSize = builder.getInt64(typeSize);
553
1/2
✓ Branch 6 → 7 taken 367 times.
✗ Branch 6 → 19 not taken.
367 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
554
555 // Call memcpy intrinsic to execute the shallow copy
556
1/2
✓ Branch 7 → 8 taken 367 times.
✗ Branch 7 → 19 not taken.
367 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
557
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 367 times.
367 assert(targetAddress != nullptr);
558
3/6
✓ Branch 10 → 11 taken 367 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 367 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 367 times.
✗ Branch 13 → 15 not taken.
367 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
559 367 }
560
561 23291 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) {
562
6/6
✓ Branch 12 → 13 taken 24223 times.
✓ Branch 12 → 15 taken 17481 times.
✓ Branch 14 → 15 taken 932 times.
✓ Branch 14 → 16 taken 23291 times.
✓ Branch 17 → 3 taken 18413 times.
✓ Branch 17 → 18 taken 23291 times.
41704 while (symbolType.isPtr() || symbolType.isRef()) {
563
2/4
✓ Branch 5 → 6 taken 18413 times.
✗ Branch 5 → 21 not taken.
✓ Branch 6 → 7 taken 18413 times.
✗ Branch 6 → 19 not taken.
18413 ptr = insertLoad(symbolType, ptr);
564
1/2
✓ Branch 9 → 10 taken 18413 times.
✗ Branch 9 → 25 not taken.
18413 symbolType = symbolType.getContained();
565 }
566 23291 }
567
568 57 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
569 // Get unused name
570
1/2
✓ Branch 2 → 3 taken 57 times.
✗ Branch 2 → 19 not taken.
57 const std::string globalName = getUnusedGlobalName(baseName);
571 // Create global
572
1/2
✓ Branch 5 → 6 taken 57 times.
✗ Branch 5 → 15 not taken.
57 module->getOrInsertGlobal(globalName, constant->getType());
573
1/2
✓ Branch 7 → 8 taken 57 times.
✗ Branch 7 → 16 not taken.
57 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
574 // Set initializer to the given constant
575
1/2
✓ Branch 8 → 9 taken 57 times.
✗ Branch 8 → 17 not taken.
57 global->setInitializer(constant);
576 57 global->setConstant(true);
577
1/2
✓ Branch 10 → 11 taken 57 times.
✗ Branch 10 → 17 not taken.
57 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
578 57 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
579 57 return global;
580 57 }
581
582 2980 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
583 // Get unused name
584
1/2
✓ Branch 2 → 3 taken 2980 times.
✗ Branch 2 → 21 not taken.
2980 const std::string globalName = getUnusedGlobalName(baseName);
585 // Create global
586
2/4
✓ Branch 3 → 4 taken 2980 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 2980 times.
✗ Branch 5 → 15 not taken.
2980 builder.CreateGlobalString(value, globalName, 0, module);
587
1/2
✓ Branch 7 → 8 taken 2980 times.
✗ Branch 7 → 17 not taken.
2980 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
588 // If the output should be comparable, fix alignment to 4 bytes
589
1/2
✓ Branch 8 → 9 taken 2980 times.
✗ Branch 8 → 12 not taken.
2980 if (cliOptions.comparableOutput)
590
2/4
✓ Branch 9 → 10 taken 2980 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 2980 times.
✗ Branch 10 → 18 not taken.
2980 global->setAlignment(llvm::Align(4));
591 2980 return global;
592 2980 }
593
594 2980 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
595 const CodeLoc &codeLoc) const {
596 2980 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
597 // Create debug info
598
2/2
✓ Branch 3 → 4 taken 48 times.
✓ Branch 3 → 10 taken 2932 times.
2980 if (cliOptions.instrumentation.generateDebugInfo)
599
3/6
✓ Branch 5 → 6 taken 48 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 48 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 48 times.
✗ Branch 7 → 12 not taken.
48 diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc);
600 2980 return global;
601 }
602
603 4987 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
604 // Find an unused global name
605 4987 std::string globalName;
606 4987 unsigned int suffixNumber = 0;
607 do {
608
1/2
✓ Branch 5 → 6 taken 130560 times.
✗ Branch 5 → 15 not taken.
130560 globalName = baseName + std::to_string(suffixNumber);
609 130560 suffixNumber++;
610
3/4
✓ Branch 10 → 11 taken 130560 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 125573 times.
✓ Branch 11 → 13 taken 4987 times.
130560 } while (module->getNamedGlobal(globalName) != nullptr);
611 4987 return globalName;
612 }
613
614 19120 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
615 // Skip results, that do not contain a constant or already have a value
616
3/4
✓ Branch 2 → 3 taken 18719 times.
✓ Branch 2 → 4 taken 401 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 18719 times.
19120 if (exprResult.value != nullptr || exprResult.constant == nullptr)
617 401 return;
618
619 // Default case: the value to the constant
620 18719 exprResult.value = exprResult.constant;
621 }
622
623 13612 bool IRGenerator::isSymbolDSOLocal(bool isPublic) const {
624 (void)isPublic;
625 13612 return true;
626 }
627
628 6352 llvm::GlobalValue::LinkageTypes IRGenerator::getSymbolLinkageType(bool isPublic) const {
629
2/2
✓ Branch 2 → 3 taken 4684 times.
✓ Branch 2 → 4 taken 1668 times.
6352 return isPublic ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::PrivateLinkage;
630 }
631
632 1188 void IRGenerator::attachComdatToSymbol(llvm::GlobalVariable *global, const std::string &comdatName, bool isPublic) const {
633 // MachO does not support comdat annotations
634
6/6
✓ Branch 2 → 3 taken 1131 times.
✓ Branch 2 → 6 taken 57 times.
✓ Branch 4 → 5 taken 1116 times.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 7 → 8 taken 1116 times.
✓ Branch 7 → 12 taken 72 times.
1188 if (isPublic && cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO)
635
2/4
✓ Branch 9 → 10 taken 1116 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 1116 times.
✗ Branch 10 → 13 not taken.
1116 global->setComdat(module->getOrInsertComdat(comdatName));
636 1188 }
637
638 1907 std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) {
639
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1907 times.
1907 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
640
3/4
✓ Branch 4 → 5 taken 1907 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 1809 times.
✓ Branch 5 → 7 taken 98 times.
1907 const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget;
641
642 // Backup target triple and data layout
643
1/2
✓ Branch 9 → 10 taken 1907 times.
✗ Branch 9 → 45 not taken.
1907 const llvm::Triple targetTriple = llvmModule->getTargetTriple();
644
1/2
✓ Branch 11 → 12 taken 1907 times.
✗ Branch 11 → 43 not taken.
1907 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
645 // Remove target triple and data layout
646
2/2
✓ Branch 12 → 13 taken 1809 times.
✓ Branch 12 → 19 taken 98 times.
1907 if (eliminateTarget) {
647 1809 llvmModule->setTargetTriple(llvm::Triple());
648
2/4
✓ Branch 16 → 17 taken 1809 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 1809 times.
✗ Branch 17 → 34 not taken.
1809 llvmModule->setDataLayout("");
649 }
650
651 // Get IR string
652 1907 std::string output;
653
1/2
✓ Branch 20 → 21 taken 1907 times.
✗ Branch 20 → 39 not taken.
1907 llvm::raw_string_ostream oss(output);
654
1/2
✓ Branch 21 → 22 taken 1907 times.
✗ Branch 21 → 37 not taken.
1907 llvmModule->print(oss, nullptr);
655
656 // Restore target triple and data layout
657
2/2
✓ Branch 22 → 23 taken 1809 times.
✓ Branch 22 → 29 taken 98 times.
1907 if (eliminateTarget) {
658
1/2
✓ Branch 23 → 24 taken 1809 times.
✗ Branch 23 → 35 not taken.
1809 llvmModule->setTargetTriple(targetTriple);
659
1/2
✓ Branch 27 → 28 taken 1809 times.
✗ Branch 27 → 36 not taken.
1809 llvmModule->setDataLayout(targetDataLayout);
660 }
661
662 1907 return output;
663 1907 }
664
665 /**
666 * Returns the operator function list for the current manifestation and the given node
667 *
668 * @param node Node to retrieve the op fct pointer list from
669 * @return Op fct pointer list
670 */
671 19910 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
672
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 19910 times.
19910 assert(node->getOpFctPointers()->size() > manIdx);
673 19910 return node->getOpFctPointers()->at(manIdx);
674 }
675
676 } // namespace spice::compiler
677