GCC Code Coverage Report


Directory: ../
Coverage: low: ≥ 0% medium: ≥ 75.0% high: ≥ 90.0%
Coverage Exec / Excl / Total
Lines: 97.1% 365 / 6 / 382
Functions: 100.0% 40 / 0 / 40
Branches: 62.8% 433 / 20 / 710

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 1006 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
17 1006 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
18
1/2
✓ Branch 8 → 9 taken 1006 times.
✗ Branch 8 → 65 not taken.
1006 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
19
6/10
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 1004 times.
✓ Branch 9 → 10 taken 1006 times.
✗ Branch 9 → 65 not taken.
✓ Branch 10 → 11 taken 1006 times.
✗ Branch 10 → 65 not taken.
✓ Branch 11 → 12 taken 1006 times.
✗ Branch 11 → 63 not taken.
✓ Branch 15 → 16 taken 1006 times.
✗ Branch 15 → 59 not taken.
2012 stdFunctionManager(sourceFile, resourceManager, module) {
20 // Attach information to the module
21
1/2
✓ Branch 17 → 18 taken 1006 times.
✗ Branch 17 → 44 not taken.
1006 module->setTargetTriple(cliOptions.targetTriple);
22
2/4
✓ Branch 21 → 22 taken 1006 times.
✗ Branch 21 → 47 not taken.
✓ Branch 22 → 23 taken 1006 times.
✗ Branch 22 → 45 not taken.
1006 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
23
2/2
✓ Branch 24 → 25 taken 1 time.
✓ Branch 24 → 27 taken 1005 times.
1006 if (cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY) {
24
1/2
✓ Branch 25 → 26 taken 1 time.
✗ Branch 25 → 55 not taken.
1 module->setPICLevel(llvm::PICLevel::SmallPIC);
25
1/2
✓ Branch 26 → 29 taken 1 time.
✗ Branch 26 → 55 not taken.
1 module->setPIELevel(llvm::PIELevel::Default);
26 } else {
27
1/2
✓ Branch 27 → 28 taken 1005 times.
✗ Branch 27 → 55 not taken.
1005 module->setPICLevel(llvm::PICLevel::BigPIC);
28
1/2
✓ Branch 28 → 29 taken 1005 times.
✗ Branch 28 → 55 not taken.
1005 module->setPIELevel(llvm::PIELevel::Large);
29 }
30
1/2
✓ Branch 29 → 30 taken 1006 times.
✗ Branch 29 → 55 not taken.
1006 module->setUwtable(llvm::UWTableKind::Default);
31
1/2
✓ Branch 30 → 31 taken 1006 times.
✗ Branch 30 → 55 not taken.
1006 module->setFramePointer(llvm::FramePointerKind::All);
32
33 // Add module identifier metadata
34
2/4
✓ Branch 31 → 32 taken 1006 times.
✗ Branch 31 → 48 not taken.
✓ Branch 32 → 33 taken 1006 times.
✗ Branch 32 → 48 not taken.
1006 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
35
3/6
✓ Branch 34 → 35 taken 1006 times.
✗ Branch 34 → 49 not taken.
✓ Branch 36 → 37 taken 1006 times.
✗ Branch 36 → 49 not taken.
✓ Branch 37 → 38 taken 1006 times.
✗ Branch 37 → 49 not taken.
1006 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
36
37 // Initialize debug info generator
38
2/2
✓ Branch 38 → 39 taken 24 times.
✓ Branch 38 → 43 taken 982 times.
1006 if (cliOptions.instrumentation.generateDebugInfo)
39
2/4
✓ Branch 39 → 40 taken 24 times.
✗ Branch 39 → 54 not taken.
✓ Branch 40 → 41 taken 24 times.
✗ Branch 40 → 52 not taken.
24 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
40 1006 }
41
42 1006 std::any IRGenerator::visitEntry(const EntryNode *node) {
43 // Generate IR
44
1/2
✓ Branch 2 → 3 taken 1006 times.
✗ Branch 2 → 19 not taken.
1006 visitChildren(node);
45
46 // Generate test main if required
47
4/4
✓ Branch 4 → 5 taken 268 times.
✓ Branch 4 → 7 taken 738 times.
✓ Branch 5 → 6 taken 4 times.
✓ Branch 5 → 7 taken 264 times.
1006 if (sourceFile->isMainFile && cliOptions.generateTestMain)
48 4 generateTestMain();
49
50 // Execute deferred VTable initializations
51
2/2
✓ Branch 13 → 9 taken 399 times.
✓ Branch 13 → 14 taken 1006 times.
1405 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
52
1/2
✓ Branch 10 → 11 taken 399 times.
✗ Branch 10 → 20 not taken.
399 deferredVTableInit.execute();
53
54 // Finalize debug info generator
55 1006 diGenerator.finalize();
56
57 // Verify module
58 1006 verifyModule(node->codeLoc);
59
60
1/2
✓ Branch 16 → 17 taken 1006 times.
✗ Branch 16 → 21 not taken.
1006 return nullptr;
61 }
62
63 40673 llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) {
64
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 40673 times.
40673 if (!cliOptions.namesForIRValues)
65 varName = "";
66
67
2/2
✓ Branch 4 → 5 taken 28921 times.
✓ Branch 4 → 12 taken 11752 times.
40673 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
68
2/4
✓ Branch 5 → 6 taken 28921 times.
✗ Branch 5 → 25 not taken.
✓ Branch 6 → 7 taken 28921 times.
✗ Branch 6 → 25 not taken.
28921 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
69
1/2
✓ Branch 8 → 9 taken 28921 times.
✗ Branch 8 → 26 not taken.
28921 allocaInst->setDebugLoc(llvm::DebugLoc());
70 28921 allocaInst->moveAfter(allocaInsertInst);
71 28921 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 11752 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
75 11752 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
76
77 // Allocate the size of the given LLVM type
78
2/4
✓ Branch 15 → 16 taken 11752 times.
✗ Branch 15 → 29 not taken.
✓ Branch 16 → 17 taken 11752 times.
✗ Branch 16 → 29 not taken.
11752 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
79
1/2
✓ Branch 18 → 19 taken 11752 times.
✗ Branch 18 → 30 not taken.
11752 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
80
81 // Restore old basic block
82 11752 builder.SetInsertPoint(currentBlock);
83 }
84
85 // Insert lifetime start marker
86
2/2
✓ Branch 21 → 22 taken 59 times.
✓ Branch 21 → 23 taken 40614 times.
40673 if (cliOptions.useLifetimeMarkers)
87 59 builder.CreateLifetimeStart(allocaInsertInst);
88
89 40673 return allocaInsertInst;
90 }
91
92 35303 llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) {
93 35303 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
94
2/4
✓ Branch 3 → 4 taken 35303 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 35303 times.
✗ Branch 4 → 10 not taken.
35303 llvm::AllocaInst *alloca = insertAlloca(llvmType, varName);
95
96 // Insert type metadata
97
2/2
✓ Branch 6 → 7 taken 9 times.
✓ Branch 6 → 8 taken 35294 times.
35303 if (cliOptions.useTBAAMetadata)
98 9 mdGenerator.generateTypeMetadata(allocaInsertInst, qualType);
99
100 35303 return alloca;
101 }
102
103 78069 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 78069 times.
78069 assert(ptr->getType()->isPointerTy());
106
5/14
✓ Branch 6 → 7 taken 78069 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 11 taken 78069 times.
✗ Branch 7 → 22 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 78069 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 78069 times.
✗ Branch 12 → 20 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 78069 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 25 not taken.
78069 return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : "");
107 }
108
109 70528 llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) {
110 70528 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
111 70528 llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName);
112
2/2
✓ Branch 4 → 5 taken 6 times.
✓ Branch 4 → 6 taken 70522 times.
70528 if (cliOptions.useTBAAMetadata)
113 6 mdGenerator.generateTBAAMetadata(load, qualType);
114 70528 return load;
115 }
116
117 42003 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 42003 times.
42003 assert(ptr->getType()->isPointerTy());
119 42003 return builder.CreateStore(val, ptr, isVolatile);
120 }
121
122 12682 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) {
123 12682 llvm::StoreInst *store = insertStore(val, ptr, isVolatile);
124
2/2
✓ Branch 3 → 4 taken 9 times.
✓ Branch 3 → 5 taken 12673 times.
12682 if (cliOptions.useTBAAMetadata)
125 9 mdGenerator.generateTBAAMetadata(store, qualType);
126 12682 }
127
128 19910 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
129 std::string varName) const {
130
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 19910 times.
19910 assert(basePtr->getType()->isPointerTy());
131
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 19910 times.
19910 assert(!indices.empty());
132
4/6
✓ Branch 4 → 5 taken 19571 times.
✓ Branch 4 → 7 taken 17359 times.
✓ Branch 6 → 7 taken 19571 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 19910 times.
56840 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
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 19910 times.
19910 if (!cliOptions.namesForIRValues)
138 varName.clear();
139
140 // Insert GEP
141
2/4
✓ Branch 14 → 15 taken 19910 times.
✗ Branch 14 → 19 not taken.
✓ Branch 15 → 16 taken 19910 times.
✗ Branch 15 → 19 not taken.
19910 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
142 }
143
144 5601 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const {
145
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5601 times.
5601 assert(basePtr->getType()->isPointerTy());
146
147
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5601 times.
5601 if (!cliOptions.namesForIRValues)
148 varName.clear();
149
150 // If we use index 0 we can use the base pointer directly
151
2/2
✓ Branch 8 → 9 taken 1958 times.
✓ Branch 8 → 10 taken 3643 times.
5601 if (index == 0)
152 1958 return basePtr;
153
154 // Insert GEP
155
2/4
✓ Branch 10 → 11 taken 3643 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3643 times.
✗ Branch 11 → 15 not taken.
3643 return builder.CreateStructGEP(type, basePtr, index, varName);
156 }
157
158 47436 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
159 // Visit the given AST node
160
2/4
✓ Branch 2 → 3 taken 47436 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 47436 times.
✗ Branch 3 → 9 not taken.
47436 auto exprResult = any_cast<LLVMExprResult>(visit(node));
161
1/2
✓ Branch 5 → 6 taken 47436 times.
✗ Branch 5 → 12 not taken.
94872 return resolveValue(node, exprResult);
162 }
163
164 53118 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) {
165 53118 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
166 }
167
168 103465 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) {
169 // Check if the value is already present
170
2/2
✓ Branch 2 → 3 taken 32815 times.
✓ Branch 2 → 4 taken 70650 times.
103465 if (exprResult.value != nullptr)
171 32815 return exprResult.value;
172
173 // Check if a constant is present
174
2/2
✓ Branch 4 → 5 taken 18677 times.
✓ Branch 4 → 7 taken 51973 times.
70650 if (exprResult.constant != nullptr) {
175 18677 materializeConstant(exprResult);
176 18677 return exprResult.value;
177 }
178
179
3/4
✓ Branch 7 → 8 taken 600 times.
✓ Branch 7 → 10 taken 51373 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 600 times.
51973 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
180
181 // De-reference if reference type
182
4/4
✓ Branch 10 → 11 taken 48440 times.
✓ Branch 10 → 13 taken 3533 times.
✓ Branch 11 → 12 taken 7 times.
✓ Branch 11 → 13 taken 48433 times.
51973 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
183
4/4
✓ Branch 14 → 15 taken 610 times.
✓ Branch 14 → 24 taken 51363 times.
✓ Branch 15 → 16 taken 600 times.
✓ Branch 15 → 24 taken 10 times.
51973 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
184
3/6
✓ Branch 18 → 19 taken 600 times.
✗ Branch 18 → 36 not taken.
✓ Branch 19 → 20 taken 600 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 600 times.
✗ Branch 20 → 34 not taken.
1200 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
185
186 // Load the value from the pointer
187
1/2
✓ Branch 24 → 25 taken 51973 times.
✗ Branch 24 → 46 not taken.
51973 const QualType referencedType = qualType.removeReferenceWrapper();
188
2/4
✓ Branch 27 → 28 taken 51973 times.
✗ Branch 27 → 42 not taken.
✓ Branch 28 → 29 taken 51973 times.
✗ Branch 28 → 40 not taken.
51973 exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile);
189
190 51973 return exprResult.value;
191 }
192
193 3003 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
194 // Visit the given AST node
195
2/4
✓ Branch 2 → 3 taken 3003 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 3003 times.
✗ Branch 3 → 9 not taken.
3003 auto exprResult = any_cast<LLVMExprResult>(visit(node));
196
1/2
✓ Branch 5 → 6 taken 3003 times.
✗ Branch 5 → 12 not taken.
6006 return resolveAddress(exprResult);
197 }
198
199 28549 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
200 // Check if an address is already present
201
2/2
✓ Branch 2 → 3 taken 24740 times.
✓ Branch 2 → 4 taken 3809 times.
28549 if (exprResult.ptr != nullptr)
202 24740 return exprResult.ptr;
203
204 // Check if the reference address is already present
205
3/4
✓ Branch 4 → 5 taken 2855 times.
✓ Branch 4 → 7 taken 954 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2855 times.
3809 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
206
3/4
✓ Branch 8 → 9 taken 3047 times.
✓ Branch 8 → 18 taken 762 times.
✓ Branch 9 → 10 taken 3047 times.
✗ Branch 9 → 18 not taken.
3809 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
207
3/6
✓ Branch 12 → 13 taken 3047 times.
✗ Branch 12 → 37 not taken.
✓ Branch 13 → 14 taken 3047 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 3047 times.
✗ Branch 14 → 35 not taken.
3047 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
208 3047 return exprResult.ptr;
209 }
210
211 // If not, store the value or constant
212 762 materializeConstant(exprResult);
213
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 762 times.
762 assert(exprResult.value != nullptr);
214
4/12
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 762 times.
✗ Branch 22 → 26 not taken.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 762 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 762 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 762 times.
✗ Branch 29 → 32 not taken.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
1524 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
215 762 insertStore(exprResult.value, exprResult.ptr, isVolatile);
216
217 762 return exprResult.ptr;
218 }
219
220 2680 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
221 // Double
222
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 9 taken 2676 times.
2680 if (symbolType.is(TY_DOUBLE))
223
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));
224
225 // Int
226
2/2
✓ Branch 10 → 11 taken 365 times.
✓ Branch 10 → 13 taken 2311 times.
2676 if (symbolType.is(TY_INT))
227 365 return builder.getInt32(0);
228
229 // Short
230
2/2
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 17 taken 2299 times.
2311 if (symbolType.is(TY_SHORT))
231 12 return builder.getInt16(0);
232
233 // Long
234
2/2
✓ Branch 18 → 19 taken 1000 times.
✓ Branch 18 → 21 taken 1299 times.
2299 if (symbolType.is(TY_LONG))
235 1000 return builder.getInt64(0);
236
237 // Byte or char
238
3/4
✓ Branch 21 → 22 taken 1299 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 22 → 25 taken 1279 times.
1299 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
239 20 return builder.getInt8(0);
240
241 // String
242
2/2
✓ Branch 26 → 27 taken 396 times.
✓ Branch 26 → 35 taken 883 times.
1279 if (symbolType.is(TY_STRING)) {
243
3/6
✓ Branch 27 → 28 taken 396 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 396 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 396 times.
✗ Branch 29 → 134 not taken.
396 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
244
1/2
✓ Branch 30 → 31 taken 396 times.
✗ Branch 30 → 34 not taken.
396 if (cliOptions.comparableOutput)
245
2/4
✓ Branch 31 → 32 taken 396 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 396 times.
✗ Branch 32 → 136 not taken.
396 globalString->setAlignment(llvm::Align(4));
246 396 return globalString;
247 }
248
249 // Bool
250
2/2
✓ Branch 36 → 37 taken 33 times.
✓ Branch 36 → 39 taken 850 times.
883 if (symbolType.is(TY_BOOL))
251 33 return builder.getFalse();
252
253 // Pointer or reference
254
3/4
✓ Branch 39 → 40 taken 850 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 793 times.
✓ Branch 40 → 44 taken 57 times.
850 if (symbolType.isOneOf({TY_PTR, TY_REF}))
255 793 return llvm::Constant::getNullValue(builder.getPtrTy());
256
257 // Array
258
2/2
✓ Branch 45 → 46 taken 14 times.
✓ Branch 45 → 61 taken 43 times.
57 if (symbolType.isArray()) {
259 // Get array size
260
1/2
✓ Branch 46 → 47 taken 14 times.
✗ Branch 46 → 146 not taken.
14 const size_t arraySize = symbolType.getArraySize();
261
262 // Get default value for item
263
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());
264
265 // Retrieve array and item type
266
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);
267
1/2
✓ Branch 51 → 52 taken 14 times.
✗ Branch 51 → 146 not taken.
14 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize);
268
269 // Create a constant array with n times the default value
270
1/2
✓ Branch 54 → 55 taken 14 times.
✗ Branch 54 → 140 not taken.
14 const std::vector itemConstants(arraySize, defaultItemValue);
271
1/2
✓ Branch 57 → 58 taken 14 times.
✗ Branch 57 → 143 not taken.
14 return llvm::ConstantArray::get(arrayType, itemConstants);
272 14 }
273
274 // Function or procedure
275
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})) {
276
2/2
✓ Branch 63 → 64 taken 8 times.
✓ Branch 63 → 69 taken 8 times.
16 if (!llvmTypes.fatPtrType)
277
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()});
278
279
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));
280
1/2
✓ Branch 72 → 73 taken 16 times.
✗ Branch 72 → 151 not taken.
16 return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue});
281 }
282
283 // Struct
284
2/2
✓ Branch 76 → 77 taken 26 times.
✓ Branch 76 → 114 taken 1 time.
27 if (symbolType.is(TY_STRUCT)) {
285 // Retrieve field count
286
1/2
✓ Branch 77 → 78 taken 26 times.
✗ Branch 77 → 158 not taken.
26 Scope *structScope = symbolType.getBodyScope();
287
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 26 times.
26 assert(structScope != nullptr);
288
1/2
✓ Branch 80 → 81 taken 26 times.
✗ Branch 80 → 158 not taken.
26 const size_t fieldCount = structScope->getFieldCount();
289
290 // Get default values for all fields of the struct
291 26 std::vector<llvm::Constant *> fieldConstants;
292
1/2
✓ Branch 81 → 82 taken 26 times.
✗ Branch 81 → 156 not taken.
26 fieldConstants.reserve(fieldCount);
293
294 // Add default value for each struct field
295
2/2
✓ Branch 107 → 83 taken 63 times.
✓ Branch 107 → 108 taken 26 times.
89 for (size_t i = 0; i < fieldCount; i++) {
296 // Get entry of the field
297
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 63 times.
63 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
298
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());
299
300 // Retrieve default field value
301 llvm::Constant *defaultFieldValue;
302
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)
303
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(manIdx), fieldEntry->getQualType(), fieldNode);
304 else
305
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());
306
307
1/2
✓ Branch 105 → 106 taken 63 times.
✗ Branch 105 → 154 not taken.
63 fieldConstants.push_back(defaultFieldValue);
308 }
309
310
1/2
✓ Branch 108 → 109 taken 26 times.
✗ Branch 108 → 156 not taken.
26 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
311
1/2
✓ Branch 110 → 111 taken 26 times.
✗ Branch 110 → 155 not taken.
26 return llvm::ConstantStruct::get(structType, fieldConstants);
312 26 }
313
314 // Interface
315
1/2
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 121 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
316 1 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
317 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
318 }
319
320 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
321 }
322
323 18765 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
324
2/2
✓ Branch 3 → 4 taken 623 times.
✓ Branch 3 → 9 taken 18142 times.
18765 if (type.is(TY_DOUBLE))
325
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));
326
327
2/2
✓ Branch 10 → 11 taken 3745 times.
✓ Branch 10 → 13 taken 14397 times.
18142 if (type.is(TY_INT))
328 3745 return builder.getInt32(compileTimeValue.intValue);
329
330
2/2
✓ Branch 14 → 15 taken 879 times.
✓ Branch 14 → 17 taken 13518 times.
14397 if (type.is(TY_SHORT))
331 879 return builder.getInt16(compileTimeValue.shortValue);
332
333
2/2
✓ Branch 18 → 19 taken 6837 times.
✓ Branch 18 → 21 taken 6681 times.
13518 if (type.is(TY_LONG))
334 6837 return builder.getInt64(compileTimeValue.longValue);
335
336
3/4
✓ Branch 21 → 22 taken 6681 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2544 times.
✓ Branch 22 → 25 taken 4137 times.
6681 if (type.isOneOf({TY_BYTE, TY_CHAR}))
337 2544 return builder.getInt8(compileTimeValue.charValue);
338
339
2/2
✓ Branch 26 → 27 taken 2135 times.
✓ Branch 26 → 36 taken 2002 times.
4137 if (type.is(TY_STRING)) {
340 2135 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
341
2/4
✓ Branch 30 → 31 taken 2135 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 2135 times.
✗ Branch 31 → 58 not taken.
6405 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
342 }
343
344
1/2
✓ Branch 37 → 38 taken 2002 times.
✗ Branch 37 → 40 not taken.
2002 if (type.is(TY_BOOL))
345 2002 return builder.getInt1(compileTimeValue.boolValue);
346
347 if (type.is(TY_PTR))
348 return llvm::Constant::getNullValue(builder.getPtrTy());
349
350 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
351 }
352
353 35214 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
354
2/4
✓ Branch 2 → 3 taken 35214 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 35214 times.
✗ Branch 3 → 7 not taken.
35214 return llvm::BasicBlock::Create(context, blockName);
355 }
356
357 35214 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
358
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 35214 times.
35214 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
359 // If no parent function were passed, use the current function
360
2/2
✓ Branch 5 → 6 taken 23394 times.
✓ Branch 5 → 8 taken 11820 times.
35214 if (!parentFct)
361 23394 parentFct = builder.GetInsertBlock()->getParent();
362 // Append block to current function
363 35214 parentFct->insert(parentFct->end(), block);
364 // Set insert point to the block
365 35214 builder.SetInsertPoint(block);
366 35214 blockAlreadyTerminated = false;
367 35214 }
368
369 10476 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
370 10476 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
371 10476 generateScopeCleanup(stmtLstNode);
372 10476 blockAlreadyTerminated = true;
373 10476 }
374
375 12952 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
376
2/2
✓ Branch 2 → 3 taken 3704 times.
✓ Branch 2 → 4 taken 9248 times.
12952 if (blockAlreadyTerminated)
377 3704 return;
378 9248 builder.CreateBr(targetBlock);
379 9248 blockAlreadyTerminated = true;
380 }
381
382 9713 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
383 Likelihood likelihood /*=UNSPECIFIED*/) {
384
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 9713 times.
9713 if (blockAlreadyTerminated)
385 return;
386 9713 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
387 9713 blockAlreadyTerminated = true;
388
389
2/2
✓ Branch 5 → 6 taken 1229 times.
✓ Branch 5 → 7 taken 8484 times.
9713 if (likelihood != Likelihood::UNSPECIFIED)
390 1229 mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood);
391 }
392
393 11820 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
394 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
395
4/4
✓ Branch 2 → 3 taken 11819 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 206 times.
✓ Branch 3 → 5 taken 11613 times.
11820 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
396 207 return;
397
398 // Verify function
399 11613 std::string output;
400
1/2
✓ Branch 6 → 7 taken 11613 times.
✗ Branch 6 → 21 not taken.
11613 llvm::raw_string_ostream oss(output);
401 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
402 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
403 11613 }
404
405 1006 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
406 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
407
4/4
✓ Branch 2 → 3 taken 1005 times.
✓ Branch 2 → 4 taken 1 time.
✓ Branch 3 → 4 taken 24 times.
✓ Branch 3 → 5 taken 981 times.
1006 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
408 25 return;
409
410 // Verify module
411 981 std::string output;
412
1/2
✓ Branch 6 → 7 taken 981 times.
✗ Branch 6 → 21 not taken.
981 llvm::raw_string_ostream oss(output);
413 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
414 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
415 981 }
416
417 5815 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
418 // Get entry of left side
419
2/4
✓ Branch 2 → 3 taken 5815 times.
✗ Branch 2 → 18 not taken.
✓ Branch 3 → 4 taken 5815 times.
✗ Branch 3 → 16 not taken.
5815 auto exprResult = std::any_cast<LLVMExprResult>(visit(lhsNode));
420 5815 SymbolTableEntry *entry = exprResult.entry;
421
7/10
✓ Branch 5 → 6 taken 4963 times.
✓ Branch 5 → 10 taken 852 times.
✓ Branch 6 → 7 taken 4963 times.
✗ Branch 6 → 19 not taken.
✓ Branch 7 → 8 taken 4963 times.
✗ Branch 7 → 19 not taken.
✓ Branch 8 → 9 taken 250 times.
✓ Branch 8 → 10 taken 4713 times.
✓ Branch 10 → 11 taken 5565 times.
✗ Branch 10 → 19 not taken.
5815 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? exprResult.refPtr : resolveAddress(exprResult);
422
1/2
✓ Branch 12 → 13 taken 5815 times.
✗ Branch 12 → 19 not taken.
11630 return doAssignment(lhsAddress, entry, rhsNode, node);
423 }
424
425 14100 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
426 const ASTNode *node, bool isDecl) {
427 // Get symbol type of right side
428
1/2
✓ Branch 2 → 3 taken 14100 times.
✗ Branch 2 → 13 not taken.
14100 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
429
2/4
✓ Branch 3 → 4 taken 14100 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 14100 times.
✗ Branch 4 → 10 not taken.
14100 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
430
1/2
✓ Branch 6 → 7 taken 14100 times.
✗ Branch 6 → 13 not taken.
28200 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
431 }
432
433 14218 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
434 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
435 // Deduce some information about the assignment
436
4/4
✓ Branch 2 → 3 taken 13366 times.
✓ Branch 2 → 7 taken 852 times.
✓ Branch 5 → 6 taken 505 times.
✓ Branch 5 → 7 taken 12861 times.
14218 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
437
8/10
✓ Branch 8 → 9 taken 13713 times.
✓ Branch 8 → 15 taken 505 times.
✓ Branch 9 → 10 taken 13713 times.
✗ Branch 9 → 195 not taken.
✓ Branch 10 → 11 taken 13713 times.
✗ Branch 10 → 195 not taken.
✓ Branch 11 → 12 taken 1451 times.
✓ Branch 11 → 15 taken 12262 times.
✓ Branch 13 → 14 taken 182 times.
✓ Branch 13 → 15 taken 1269 times.
14218 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
438
439
2/2
✓ Branch 16 → 17 taken 505 times.
✓ Branch 16 → 57 taken 13713 times.
14218 if (isRefAssign) {
440
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 505 times.
505 assert(lhsEntry != nullptr);
441
2/2
✓ Branch 19 → 20 taken 255 times.
✓ Branch 19 → 33 taken 250 times.
505 if (isDecl) { // Reference gets initially assigned
442 // Get address of right side
443 255 llvm::Value *rhsAddress = resolveAddress(rhs);
444
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 255 times.
255 assert(rhsAddress != nullptr);
445
446 // Store lhs pointer to rhs
447
2/4
✓ Branch 26 → 27 taken 255 times.
✗ Branch 26 → 196 not taken.
✓ Branch 27 → 28 taken 255 times.
✗ Branch 27 → 196 not taken.
255 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
448 255 lhsEntry->updateAddress(refAddress);
449 255 insertStore(rhsAddress, refAddress);
450
451 255 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
452 }
453
454 // Reference to reference assignment (only for struct fields that are not initialized yet)
455 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
456
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();
457 // Assigning the result variable
458 250 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
459
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) {
460 // Get address of right side
461 169 llvm::Value *referencedAddress = resolveAddress(rhs);
462
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 169 times.
169 assert(referencedAddress != nullptr);
463
464 // Store the rhs* to the lhs**
465 169 insertStore(referencedAddress, lhsAddress);
466
467 169 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
468 }
469
470 // Load referenced address
471
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);
472 }
473
474
8/8
✓ Branch 57 → 58 taken 8148 times.
✓ Branch 57 → 63 taken 5646 times.
✓ Branch 59 → 60 taken 969 times.
✓ Branch 59 → 63 taken 7179 times.
✓ Branch 61 → 62 taken 966 times.
✓ Branch 61 → 63 taken 3 times.
✓ Branch 64 → 65 taken 966 times.
✓ Branch 64 → 70 taken 12828 times.
13794 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
475
1/2
✗ Branch 65 → 66 not taken.
✓ Branch 65 → 67 taken 966 times.
966 assert(lhsEntry != nullptr);
476 // Directly set the address to the lhs entry (temp stealing)
477 966 llvm::Value *rhsAddress = resolveAddress(rhs);
478 966 lhsEntry->updateAddress(rhsAddress);
479 966 rhs.entry = lhsEntry;
480 966 return rhs;
481 }
482
483 // Allocate new memory if the lhs address does not exist
484
2/2
✓ Branch 70 → 71 taken 7152 times.
✓ Branch 70 → 81 taken 5676 times.
12828 if (!lhsAddress) {
485
1/2
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 7152 times.
7152 assert(lhsEntry != nullptr);
486
3/6
✓ Branch 75 → 76 taken 7152 times.
✗ Branch 75 → 210 not taken.
✓ Branch 76 → 77 taken 7152 times.
✗ Branch 76 → 208 not taken.
✓ Branch 77 → 78 taken 7152 times.
✗ Branch 77 → 208 not taken.
7152 lhsAddress = insertAlloca(lhsEntry->getQualType());
487 7152 lhsEntry->updateAddress(lhsAddress);
488 }
489
490 // 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
491
10/10
✓ Branch 81 → 82 taken 11976 times.
✓ Branch 81 → 90 taken 852 times.
✓ Branch 84 → 85 taken 2291 times.
✓ Branch 84 → 90 taken 9685 times.
✓ Branch 86 → 87 taken 6 times.
✓ Branch 86 → 90 taken 2285 times.
✓ Branch 88 → 89 taken 2 times.
✓ Branch 88 → 90 taken 4 times.
✓ Branch 91 → 92 taken 2 times.
✓ Branch 91 → 107 taken 12826 times.
12828 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
492 // Get address of right side
493
1/2
✓ Branch 92 → 93 taken 2 times.
✗ Branch 92 → 221 not taken.
2 llvm::Value *rhsAddress = resolveAddress(rhs);
494
1/2
✗ Branch 93 → 94 not taken.
✓ Branch 93 → 95 taken 2 times.
2 assert(rhsAddress != nullptr);
495
1/2
✓ Branch 95 → 96 taken 2 times.
✗ Branch 95 → 221 not taken.
2 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
496
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)};
497
1/2
✓ Branch 102 → 103 taken 2 times.
✗ Branch 102 → 214 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
498
1/2
✓ Branch 105 → 106 taken 2 times.
✗ Branch 105 → 221 not taken.
2 insertStore(firstItemAddress, lhsAddress);
499 2 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
500 }
501
502 // Check if we need to copy the rhs to the lhs. This happens for structs
503
2/2
✓ Branch 107 → 108 taken 182 times.
✓ Branch 107 → 163 taken 12644 times.
12826 if (needsCopy) {
504 // Get address of right side
505
1/2
✓ Branch 108 → 109 taken 182 times.
✗ Branch 108 → 264 not taken.
182 llvm::Value *rhsAddress = resolveAddress(rhs);
506
1/2
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 111 taken 182 times.
182 assert(rhsAddress != nullptr);
507
508
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();
509
3/4
✓ Branch 113 → 114 taken 182 times.
✗ Branch 113 → 264 not taken.
✓ Branch 114 → 115 taken 104 times.
✓ Branch 114 → 131 taken 78 times.
182 if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
510 // Create shallow copy
511
1/2
✓ Branch 115 → 116 taken 104 times.
✗ Branch 115 → 230 not taken.
104 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
512
6/10
✓ Branch 116 → 117 taken 99 times.
✓ Branch 116 → 118 taken 5 times.
✓ Branch 117 → 121 taken 99 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 99 times.
✗ Branch 223 → 224 not taken.
✗ Branch 223 → 226 not taken.
109 const std::string copyName = lhsEntry ? lhsEntry->name : "";
513
4/6
✓ Branch 124 → 125 taken 99 times.
✓ Branch 124 → 127 taken 5 times.
✗ Branch 125 → 126 not taken.
✓ Branch 125 → 127 taken 99 times.
✓ Branch 128 → 129 taken 104 times.
✗ Branch 128 → 228 not taken.
104 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
514 104 } else {
515 // Check if we have a copy ctor
516
1/2
✓ Branch 131 → 132 taken 78 times.
✗ Branch 131 → 263 not taken.
78 Scope *structScope = rhsSTypeNonRef.getBodyScope();
517
2/4
✓ Branch 132 → 133 taken 78 times.
✗ Branch 132 → 235 not taken.
✓ Branch 137 → 138 taken 78 times.
✗ Branch 137 → 231 not taken.
234 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
518
2/4
✓ Branch 141 → 142 taken 78 times.
✗ Branch 141 → 239 not taken.
✓ Branch 142 → 143 taken 78 times.
✗ Branch 142 → 237 not taken.
78 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
519
1/2
✓ Branch 145 → 146 taken 78 times.
✗ Branch 145 → 153 not taken.
78 if (copyCtor != nullptr) {
520 // Call copy ctor
521
2/4
✓ Branch 148 → 149 taken 78 times.
✗ Branch 148 → 245 not taken.
✓ Branch 149 → 150 taken 78 times.
✗ Branch 149 → 243 not taken.
234 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
522 } else {
523 const std::string structName = rhsSTypeNonRef.getName();
524 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
525 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
526 }
527 78 }
528 182 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
529 }
530
531 // Optimization: If we have the address of both sides, we can do a memcpy instead of loading and storing the value
532 12644 llvm::Value *rhsValue = nullptr;
533
8/8
✓ Branch 164 → 165 taken 253 times.
✓ Branch 164 → 168 taken 12391 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 12421 times.
12644 if (rhsSType.is(TY_STRUCT) && rhs.value == nullptr && rhs.constant == nullptr) {
534 // Create shallow copy
535
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();
536
1/2
✓ Branch 172 → 173 taken 223 times.
✗ Branch 172 → 273 not taken.
223 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
537
1/2
✓ Branch 173 → 174 taken 223 times.
✗ Branch 173 → 273 not taken.
223 llvm::Value *rhsAddress = resolveAddress(rhs);
538
1/2
✗ Branch 174 → 175 not taken.
✓ Branch 174 → 176 taken 223 times.
223 assert(rhsAddress != nullptr);
539
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 : "";
540
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);
541 223 } else {
542 // We can load the value from the right side and store it to the left side
543 // Retrieve value of the right side
544 12421 rhsValue = resolveValue(rhsSType, rhs);
545 // Store the value to the address
546 12421 insertStore(rhsValue, lhsAddress, rhsSType);
547 }
548
549 12644 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
550 }
551
552 366 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
553 bool isVolatile) const {
554 // Retrieve size to copy
555
1/2
✓ Branch 3 → 4 taken 366 times.
✗ Branch 3 → 19 not taken.
366 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
556
557 // Create values for memcpy intrinsic
558
2/4
✓ Branch 4 → 5 taken 366 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 366 times.
✗ Branch 5 → 19 not taken.
366 llvm::Value *structSize = builder.getInt64(typeSize);
559
1/2
✓ Branch 6 → 7 taken 366 times.
✗ Branch 6 → 19 not taken.
366 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
560
561 // Call memcpy intrinsic to execute the shallow copy
562
1/2
✓ Branch 7 → 8 taken 366 times.
✗ Branch 7 → 19 not taken.
366 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
563
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 366 times.
366 assert(targetAddress != nullptr);
564
3/6
✓ Branch 10 → 11 taken 366 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 366 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 366 times.
✗ Branch 13 → 15 not taken.
366 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
565 366 }
566
567 23462 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) {
568
6/6
✓ Branch 12 → 13 taken 24397 times.
✓ Branch 12 → 15 taken 17620 times.
✓ Branch 14 → 15 taken 935 times.
✓ Branch 14 → 16 taken 23462 times.
✓ Branch 17 → 3 taken 18555 times.
✓ Branch 17 → 18 taken 23462 times.
42017 while (symbolType.isPtr() || symbolType.isRef()) {
569
2/4
✓ Branch 5 → 6 taken 18555 times.
✗ Branch 5 → 21 not taken.
✓ Branch 6 → 7 taken 18555 times.
✗ Branch 6 → 19 not taken.
18555 ptr = insertLoad(symbolType, ptr);
570
1/2
✓ Branch 9 → 10 taken 18555 times.
✗ Branch 9 → 25 not taken.
18555 symbolType = symbolType.getContained();
571 }
572 23462 }
573
574 57 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
575 // Get unused name
576
1/2
✓ Branch 2 → 3 taken 57 times.
✗ Branch 2 → 19 not taken.
57 const std::string globalName = getUnusedGlobalName(baseName);
577 // Create global
578
1/2
✓ Branch 5 → 6 taken 57 times.
✗ Branch 5 → 15 not taken.
57 module->getOrInsertGlobal(globalName, constant->getType());
579
1/2
✓ Branch 7 → 8 taken 57 times.
✗ Branch 7 → 16 not taken.
57 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
580 // Set initializer to the given constant
581
1/2
✓ Branch 8 → 9 taken 57 times.
✗ Branch 8 → 17 not taken.
57 global->setInitializer(constant);
582 57 global->setConstant(true);
583
1/2
✓ Branch 10 → 11 taken 57 times.
✗ Branch 10 → 17 not taken.
57 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
584 57 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
585 57 return global;
586 57 }
587
588 2990 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
589 // Get unused name
590
1/2
✓ Branch 2 → 3 taken 2990 times.
✗ Branch 2 → 21 not taken.
2990 const std::string globalName = getUnusedGlobalName(baseName);
591 // Create global
592
2/4
✓ Branch 3 → 4 taken 2990 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 2990 times.
✗ Branch 5 → 15 not taken.
2990 builder.CreateGlobalString(value, globalName, 0, module);
593
1/2
✓ Branch 7 → 8 taken 2990 times.
✗ Branch 7 → 17 not taken.
2990 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
594 // If the output should be comparable, fix alignment to 4 bytes
595
1/2
✓ Branch 8 → 9 taken 2990 times.
✗ Branch 8 → 12 not taken.
2990 if (cliOptions.comparableOutput)
596
2/4
✓ Branch 9 → 10 taken 2990 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 2990 times.
✗ Branch 10 → 18 not taken.
2990 global->setAlignment(llvm::Align(4));
597 2990 return global;
598 2990 }
599
600 2990 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
601 const CodeLoc &codeLoc) const {
602 2990 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
603 // Create debug info
604
2/2
✓ Branch 3 → 4 taken 48 times.
✓ Branch 3 → 10 taken 2942 times.
2990 if (cliOptions.instrumentation.generateDebugInfo)
605
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);
606 2990 return global;
607 }
608
609 5007 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
610 // Find an unused global name
611 5007 std::string globalName;
612 5007 unsigned int suffixNumber = 0;
613 do {
614
1/2
✓ Branch 5 → 6 taken 130588 times.
✗ Branch 5 → 15 not taken.
130588 globalName = baseName + std::to_string(suffixNumber);
615 130588 suffixNumber++;
616
3/4
✓ Branch 10 → 11 taken 130588 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 125581 times.
✓ Branch 11 → 13 taken 5007 times.
130588 } while (module->getNamedGlobal(globalName) != nullptr);
617 5007 return globalName;
618 }
619
620 19439 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
621 // Skip results, that do not contain a constant or already have a value
622
3/4
✓ Branch 2 → 3 taken 19034 times.
✓ Branch 2 → 4 taken 405 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 19034 times.
19439 if (exprResult.value != nullptr || exprResult.constant == nullptr)
623 405 return;
624
625 // Default case: the value to the constant
626 19034 exprResult.value = exprResult.constant;
627 }
628
629 13708 bool IRGenerator::isSymbolDSOLocal(bool isPublic) const {
630 // If we are compiling a shared library and export the global symbol, we need to drop dso_local
631 // because it may be interposed by other shared objects by the dynamic linker.
632
3/4
✓ Branch 2 → 3 taken 11829 times.
✓ Branch 2 → 4 taken 1879 times.
✓ Branch 3 → 4 taken 11829 times.
✗ Branch 3 → 5 not taken.
13708 return !(isPublic && cliOptions.outputContainer == OutputContainer::SHARED_LIBRARY);
633 }
634
635 6389 llvm::GlobalValue::LinkageTypes IRGenerator::getSymbolLinkageType(bool isPublic) const {
636
2/2
✓ Branch 2 → 3 taken 4704 times.
✓ Branch 2 → 4 taken 1685 times.
6389 return isPublic ? llvm::GlobalValue::ExternalLinkage : llvm::GlobalValue::PrivateLinkage;
637 }
638
639 1197 void IRGenerator::attachComdatToSymbol(llvm::GlobalVariable *global, const std::string &comdatName, bool isPublic) const {
640 // MachO does not support comdat annotations
641
6/6
✓ Branch 2 → 3 taken 1134 times.
✓ Branch 2 → 6 taken 63 times.
✓ Branch 4 → 5 taken 1119 times.
✓ Branch 4 → 6 taken 15 times.
✓ Branch 7 → 8 taken 1119 times.
✓ Branch 7 → 12 taken 78 times.
1197 if (isPublic && cliOptions.targetTriple.getObjectFormat() != llvm::Triple::MachO)
642
2/4
✓ Branch 9 → 10 taken 1119 times.
✗ Branch 9 → 13 not taken.
✓ Branch 10 → 11 taken 1119 times.
✗ Branch 10 → 13 not taken.
1119 global->setComdat(module->getOrInsertComdat(comdatName));
643 1197 }
644
645 1933 std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) {
646
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1933 times.
1933 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
647
3/4
✓ Branch 4 → 5 taken 1933 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 1835 times.
✓ Branch 5 → 7 taken 98 times.
1933 const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget;
648
649 // Backup target triple and data layout
650
1/2
✓ Branch 9 → 10 taken 1933 times.
✗ Branch 9 → 45 not taken.
1933 const llvm::Triple targetTriple = llvmModule->getTargetTriple();
651
1/2
✓ Branch 11 → 12 taken 1933 times.
✗ Branch 11 → 43 not taken.
1933 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
652 // Remove target triple and data layout
653
2/2
✓ Branch 12 → 13 taken 1835 times.
✓ Branch 12 → 19 taken 98 times.
1933 if (eliminateTarget) {
654 1835 llvmModule->setTargetTriple(llvm::Triple());
655
2/4
✓ Branch 16 → 17 taken 1835 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 1835 times.
✗ Branch 17 → 34 not taken.
1835 llvmModule->setDataLayout("");
656 }
657
658 // Get IR string
659 1933 std::string output;
660
1/2
✓ Branch 20 → 21 taken 1933 times.
✗ Branch 20 → 39 not taken.
1933 llvm::raw_string_ostream oss(output);
661
1/2
✓ Branch 21 → 22 taken 1933 times.
✗ Branch 21 → 37 not taken.
1933 llvmModule->print(oss, nullptr);
662
663 // Restore target triple and data layout
664
2/2
✓ Branch 22 → 23 taken 1835 times.
✓ Branch 22 → 29 taken 98 times.
1933 if (eliminateTarget) {
665
1/2
✓ Branch 23 → 24 taken 1835 times.
✗ Branch 23 → 35 not taken.
1835 llvmModule->setTargetTriple(targetTriple);
666
1/2
✓ Branch 27 → 28 taken 1835 times.
✗ Branch 27 → 36 not taken.
1835 llvmModule->setDataLayout(targetDataLayout);
667 }
668
669 1933 return output;
670 1933 }
671
672 /**
673 * Returns the operator function list for the current manifestation and the given node
674 *
675 * @param node Node to retrieve the op fct pointer list from
676 * @return Op fct pointer list
677 */
678 20082 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
679
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 20082 times.
20082 assert(node->getOpFctPointers()->size() > manIdx);
680 20082 return node->getOpFctPointers()->at(manIdx);
681 }
682
683 } // namespace spice::compiler
684