GCC Code Coverage Report


Directory: ../
File: src/irgenerator/IRGenerator.cpp
Date: 2025-11-14 16:08:18
Coverage Exec Excl Total
Lines: 96.9% 349 6 366
Functions: 100.0% 37 0 37
Branches: 61.9% 401 20 668

Line Branch Exec Source
1 // Copyright (c) 2021-2025 ChilliBits. All rights reserved.
2
3 #include "IRGenerator.h"
4
5 #include <llvm/IR/Module.h>
6 #include <llvm/IR/Verifier.h>
7
8 #include <SourceFile.h>
9 #include <global/GlobalResourceManager.h>
10 #include <irgenerator/NameMangling.h>
11 #include <symboltablebuilder/SymbolTableBuilder.h>
12
13 namespace spice::compiler {
14
15 957 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
16 957 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
17
1/2
✓ Branch 8 → 9 taken 957 times.
✗ Branch 8 → 62 not taken.
957 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
18
6/10
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 955 times.
✓ Branch 9 → 10 taken 957 times.
✗ Branch 9 → 62 not taken.
✓ Branch 10 → 11 taken 957 times.
✗ Branch 10 → 62 not taken.
✓ Branch 11 → 12 taken 957 times.
✗ Branch 11 → 60 not taken.
✓ Branch 15 → 16 taken 957 times.
✗ Branch 15 → 56 not taken.
1914 stdFunctionManager(sourceFile, resourceManager, module) {
19 // Attach information to the module
20
1/2
✓ Branch 17 → 18 taken 957 times.
✗ Branch 17 → 41 not taken.
957 module->setTargetTriple(cliOptions.targetTriple);
21
2/4
✓ Branch 21 → 22 taken 957 times.
✗ Branch 21 → 44 not taken.
✓ Branch 22 → 23 taken 957 times.
✗ Branch 22 → 42 not taken.
957 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
22
1/2
✓ Branch 24 → 25 taken 957 times.
✗ Branch 24 → 52 not taken.
957 module->setPICLevel(llvm::PICLevel::BigPIC);
23
1/2
✓ Branch 25 → 26 taken 957 times.
✗ Branch 25 → 52 not taken.
957 module->setPIELevel(llvm::PIELevel::Large);
24
1/2
✓ Branch 26 → 27 taken 957 times.
✗ Branch 26 → 52 not taken.
957 module->setUwtable(llvm::UWTableKind::Default);
25
1/2
✓ Branch 27 → 28 taken 957 times.
✗ Branch 27 → 52 not taken.
957 module->setFramePointer(llvm::FramePointerKind::All);
26
27 // Add module identifier metadata
28
2/4
✓ Branch 28 → 29 taken 957 times.
✗ Branch 28 → 45 not taken.
✓ Branch 29 → 30 taken 957 times.
✗ Branch 29 → 45 not taken.
957 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
29
3/6
✓ Branch 31 → 32 taken 957 times.
✗ Branch 31 → 46 not taken.
✓ Branch 33 → 34 taken 957 times.
✗ Branch 33 → 46 not taken.
✓ Branch 34 → 35 taken 957 times.
✗ Branch 34 → 46 not taken.
957 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
30
31 // Initialize debug info generator
32
2/2
✓ Branch 35 → 36 taken 23 times.
✓ Branch 35 → 40 taken 934 times.
957 if (cliOptions.instrumentation.generateDebugInfo)
33
2/4
✓ Branch 36 → 37 taken 23 times.
✗ Branch 36 → 51 not taken.
✓ Branch 37 → 38 taken 23 times.
✗ Branch 37 → 49 not taken.
23 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
34 957 }
35
36 957 std::any IRGenerator::visitEntry(const EntryNode *node) {
37 // Generate IR
38
1/2
✓ Branch 2 → 3 taken 957 times.
✗ Branch 2 → 19 not taken.
957 visitChildren(node);
39
40 // Generate test main if required
41
4/4
✓ Branch 4 → 5 taken 247 times.
✓ Branch 4 → 7 taken 710 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 245 times.
957 if (sourceFile->isMainFile && cliOptions.generateTestMain)
42 2 generateTestMain();
43
44 // Execute deferred VTable initializations
45
2/2
✓ Branch 13 → 9 taken 383 times.
✓ Branch 13 → 14 taken 957 times.
1340 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
46
1/2
✓ Branch 10 → 11 taken 383 times.
✗ Branch 10 → 20 not taken.
383 deferredVTableInit.execute();
47
48 // Finalize debug info generator
49 957 diGenerator.finalize();
50
51 // Verify module
52 957 verifyModule(node->codeLoc);
53
54
1/2
✓ Branch 16 → 17 taken 957 times.
✗ Branch 16 → 21 not taken.
957 return nullptr;
55 }
56
57 35119 llvm::AllocaInst *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) {
58
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 35119 times.
35119 if (!cliOptions.namesForIRValues)
59 varName = "";
60
61
2/2
✓ Branch 4 → 5 taken 24554 times.
✓ Branch 4 → 12 taken 10565 times.
35119 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
62
2/4
✓ Branch 5 → 6 taken 24554 times.
✗ Branch 5 → 29 not taken.
✓ Branch 6 → 7 taken 24554 times.
✗ Branch 6 → 29 not taken.
24554 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
63
1/2
✓ Branch 8 → 9 taken 24554 times.
✗ Branch 8 → 30 not taken.
24554 allocaInst->setDebugLoc(llvm::DebugLoc());
64 24554 allocaInst->moveAfter(allocaInsertInst);
65 24554 allocaInsertInst = allocaInst;
66 } else { // This is the first alloca inst in the current function -> insert at the entry block
67 // Save current basic block and move insert cursor to entry block of the current function
68 10565 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
69 10565 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
70
71 // Allocate the size of the given LLVM type
72
2/4
✓ Branch 15 → 16 taken 10565 times.
✗ Branch 15 → 33 not taken.
✓ Branch 16 → 17 taken 10565 times.
✗ Branch 16 → 33 not taken.
10565 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
73
1/2
✓ Branch 18 → 19 taken 10565 times.
✗ Branch 18 → 34 not taken.
10565 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
74
75 // Restore old basic block
76 10565 builder.SetInsertPoint(currentBlock);
77 }
78
79 // Insert lifetime start marker
80
2/2
✓ Branch 21 → 22 taken 59 times.
✓ Branch 21 → 27 taken 35060 times.
35119 if (cliOptions.useLifetimeMarkers) {
81
2/4
✓ Branch 23 → 24 taken 59 times.
✗ Branch 23 → 37 not taken.
✓ Branch 24 → 25 taken 59 times.
✗ Branch 24 → 37 not taken.
59 const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(llvmType);
82 59 builder.CreateLifetimeStart(allocaInsertInst, builder.getInt64(sizeInBytes));
83 }
84
85 35119 return allocaInsertInst;
86 }
87
88 30752 llvm::AllocaInst *IRGenerator::insertAlloca(const QualType &qualType, const std::string &varName) {
89 30752 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
90
2/4
✓ Branch 3 → 4 taken 30752 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 30752 times.
✗ Branch 4 → 10 not taken.
30752 llvm::AllocaInst *alloca = insertAlloca(llvmType, varName);
91
92 // Insert type metadata
93
2/2
✓ Branch 6 → 7 taken 3 times.
✓ Branch 6 → 8 taken 30749 times.
30752 if (cliOptions.useTBAAMetadata)
94 3 mdGenerator.generateTypeMetadata(allocaInsertInst, qualType);
95
96 30752 return alloca;
97 }
98
99 70565 llvm::LoadInst *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile,
100 const std::string &varName) const {
101
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 70565 times.
70565 assert(ptr->getType()->isPointerTy());
102
5/14
✓ Branch 6 → 7 taken 70565 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 11 taken 70565 times.
✗ Branch 7 → 22 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 70565 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 70565 times.
✗ Branch 12 → 20 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 70565 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 25 not taken.
70565 return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : "");
103 }
104
105 63478 llvm::LoadInst *IRGenerator::insertLoad(const QualType &qualType, llvm::Value *ptr, bool isVolatile, const std::string &varName) {
106 63478 llvm::Type *llvmType = qualType.toLLVMType(sourceFile);
107 63478 llvm::LoadInst *load = insertLoad(llvmType, ptr, isVolatile, varName);
108
2/2
✓ Branch 4 → 5 taken 4 times.
✓ Branch 4 → 6 taken 63474 times.
63478 if (cliOptions.useTBAAMetadata)
109 4 mdGenerator.generateTBAAMetadata(load, qualType);
110 63478 return load;
111 }
112
113 36410 llvm::StoreInst *IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const {
114
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 36410 times.
36410 assert(ptr->getType()->isPointerTy());
115 36410 return builder.CreateStore(val, ptr, isVolatile);
116 }
117
118 11894 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, const QualType &qualType, bool isVolatile) {
119 11894 llvm::StoreInst *store = insertStore(val, ptr, isVolatile);
120
2/2
✓ Branch 3 → 4 taken 3 times.
✓ Branch 3 → 5 taken 11891 times.
11894 if (cliOptions.useTBAAMetadata)
121 3 mdGenerator.generateTBAAMetadata(store, qualType);
122 11894 }
123
124 18884 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
125 std::string varName) const {
126
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 18884 times.
18884 assert(basePtr->getType()->isPointerTy());
127
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 18884 times.
18884 assert(!indices.empty());
128
4/6
✓ Branch 4 → 5 taken 18563 times.
✓ Branch 4 → 7 taken 16499 times.
✓ Branch 6 → 7 taken 18563 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 18884 times.
53946 assert(std::ranges::all_of(indices, [](const llvm::Value *index) {
129 const llvm::Type *indexType = index->getType();
130 return indexType->isIntegerTy(32) || indexType->isIntegerTy(64);
131 }));
132
133
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 18884 times.
18884 if (!cliOptions.namesForIRValues)
134 varName = "";
135
136 // Insert GEP
137
2/4
✓ Branch 14 → 15 taken 18884 times.
✗ Branch 14 → 19 not taken.
✓ Branch 15 → 16 taken 18884 times.
✗ Branch 15 → 19 not taken.
18884 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
138 }
139
140 5436 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const {
141
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5436 times.
5436 assert(basePtr->getType()->isPointerTy());
142
143
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5436 times.
5436 if (!cliOptions.namesForIRValues)
144 varName = "";
145
146 // If we use index 0 we can use the base pointer directly
147
2/2
✓ Branch 8 → 9 taken 1881 times.
✓ Branch 8 → 10 taken 3555 times.
5436 if (index == 0)
148 1881 return basePtr;
149
150 // Insert GEP
151
2/4
✓ Branch 10 → 11 taken 3555 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3555 times.
✗ Branch 11 → 15 not taken.
3555 return builder.CreateStructGEP(type, basePtr, index, varName);
152 }
153
154 40218 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
155 // Visit the given AST node
156
2/4
✓ Branch 2 → 3 taken 40218 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 40218 times.
✗ Branch 3 → 9 not taken.
40218 auto exprResult = any_cast<LLVMExprResult>(visit(node));
157
1/2
✓ Branch 5 → 6 taken 40218 times.
✗ Branch 5 → 12 not taken.
80436 return resolveValue(node, exprResult);
158 }
159
160 46534 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) {
161 46534 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
162 }
163
164 91968 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) {
165 // Check if the value is already present
166
2/2
✓ Branch 2 → 3 taken 30440 times.
✓ Branch 2 → 4 taken 61528 times.
91968 if (exprResult.value != nullptr)
167 30440 return exprResult.value;
168
169 // Check if a constant is present
170
2/2
✓ Branch 4 → 5 taken 15758 times.
✓ Branch 4 → 7 taken 45770 times.
61528 if (exprResult.constant != nullptr) {
171 15758 materializeConstant(exprResult);
172 15758 return exprResult.value;
173 }
174
175
3/4
✓ Branch 7 → 8 taken 566 times.
✓ Branch 7 → 10 taken 45204 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 566 times.
45770 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
176
177 // De-reference if reference type
178
4/4
✓ Branch 10 → 11 taken 42217 times.
✓ Branch 10 → 13 taken 3553 times.
✓ Branch 11 → 12 taken 10 times.
✓ Branch 11 → 13 taken 42207 times.
45770 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
179
4/4
✓ Branch 14 → 15 taken 570 times.
✓ Branch 14 → 24 taken 45200 times.
✓ Branch 15 → 16 taken 566 times.
✓ Branch 15 → 24 taken 4 times.
45770 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
180
3/6
✓ Branch 18 → 19 taken 566 times.
✗ Branch 18 → 36 not taken.
✓ Branch 19 → 20 taken 566 times.
✗ Branch 19 → 34 not taken.
✓ Branch 20 → 21 taken 566 times.
✗ Branch 20 → 34 not taken.
1132 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
181
182 // Load the value from the pointer
183
1/2
✓ Branch 24 → 25 taken 45770 times.
✗ Branch 24 → 46 not taken.
45770 const QualType referencedType = qualType.removeReferenceWrapper();
184
2/4
✓ Branch 27 → 28 taken 45770 times.
✗ Branch 27 → 42 not taken.
✓ Branch 28 → 29 taken 45770 times.
✗ Branch 28 → 40 not taken.
45770 exprResult.value = insertLoad(referencedType, exprResult.ptr, isVolatile);
185
186 45770 return exprResult.value;
187 }
188
189 2958 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
190 // Visit the given AST node
191
2/4
✓ Branch 2 → 3 taken 2958 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2958 times.
✗ Branch 3 → 9 not taken.
2958 auto exprResult = any_cast<LLVMExprResult>(visit(node));
192
1/2
✓ Branch 5 → 6 taken 2958 times.
✗ Branch 5 → 12 not taken.
5916 return resolveAddress(exprResult);
193 }
194
195 21577 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
196 // Check if an address is already present
197
2/2
✓ Branch 2 → 3 taken 18075 times.
✓ Branch 2 → 4 taken 3502 times.
21577 if (exprResult.ptr != nullptr)
198 18075 return exprResult.ptr;
199
200 // Check if the reference address is already present
201
3/4
✓ Branch 4 → 5 taken 2747 times.
✓ Branch 4 → 7 taken 755 times.
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 2747 times.
3502 const bool isVolatile = exprResult.entry && exprResult.entry->isVolatile;
202
3/4
✓ Branch 8 → 9 taken 2746 times.
✓ Branch 8 → 18 taken 756 times.
✓ Branch 9 → 10 taken 2746 times.
✗ Branch 9 → 18 not taken.
3502 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
203
3/6
✓ Branch 12 → 13 taken 2746 times.
✗ Branch 12 → 37 not taken.
✓ Branch 13 → 14 taken 2746 times.
✗ Branch 13 → 35 not taken.
✓ Branch 14 → 15 taken 2746 times.
✗ Branch 14 → 35 not taken.
2746 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, isVolatile);
204 2746 return exprResult.ptr;
205 }
206
207 // If not, store the value or constant
208 756 materializeConstant(exprResult);
209
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 756 times.
756 assert(exprResult.value != nullptr);
210
7/12
✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 750 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 43 not taken.
✓ Branch 25 → 26 taken 750 times.
✗ Branch 25 → 43 not taken.
✓ Branch 27 → 28 taken 756 times.
✗ Branch 27 → 41 not taken.
✓ Branch 29 → 30 taken 750 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 43 → 44 not taken.
✗ Branch 43 → 46 not taken.
1506 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
211 756 insertStore(exprResult.value, exprResult.ptr, isVolatile);
212
213 756 return exprResult.ptr;
214 }
215
216 2566 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
217 // Double
218
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 9 taken 2562 times.
2566 if (symbolType.is(TY_DOUBLE))
219
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));
220
221 // Int
222
2/2
✓ Branch 10 → 11 taken 347 times.
✓ Branch 10 → 13 taken 2215 times.
2562 if (symbolType.is(TY_INT))
223 347 return builder.getInt32(0);
224
225 // Short
226
2/2
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 17 taken 2203 times.
2215 if (symbolType.is(TY_SHORT))
227 12 return builder.getInt16(0);
228
229 // Long
230
2/2
✓ Branch 18 → 19 taken 948 times.
✓ Branch 18 → 21 taken 1255 times.
2203 if (symbolType.is(TY_LONG))
231 948 return builder.getInt64(0);
232
233 // Byte or char
234
3/4
✓ Branch 21 → 22 taken 1255 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 22 → 25 taken 1235 times.
1255 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
235 20 return builder.getInt8(0);
236
237 // String
238
2/2
✓ Branch 26 → 27 taken 375 times.
✓ Branch 26 → 35 taken 860 times.
1235 if (symbolType.is(TY_STRING)) {
239
3/6
✓ Branch 27 → 28 taken 375 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 375 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 375 times.
✗ Branch 29 → 134 not taken.
375 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
240
1/2
✓ Branch 30 → 31 taken 375 times.
✗ Branch 30 → 34 not taken.
375 if (cliOptions.comparableOutput)
241
2/4
✓ Branch 31 → 32 taken 375 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 375 times.
✗ Branch 32 → 136 not taken.
375 globalString->setAlignment(llvm::Align(4));
242 375 return globalString;
243 }
244
245 // Bool
246
2/2
✓ Branch 36 → 37 taken 33 times.
✓ Branch 36 → 39 taken 827 times.
860 if (symbolType.is(TY_BOOL))
247 33 return builder.getFalse();
248
249 // Pointer or reference
250
3/4
✓ Branch 39 → 40 taken 827 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 766 times.
✓ Branch 40 → 44 taken 61 times.
827 if (symbolType.isOneOf({TY_PTR, TY_REF}))
251 766 return llvm::Constant::getNullValue(builder.getPtrTy());
252
253 // Array
254
2/2
✓ Branch 45 → 46 taken 15 times.
✓ Branch 45 → 61 taken 46 times.
61 if (symbolType.isArray()) {
255 // Get array size
256
1/2
✓ Branch 46 → 47 taken 15 times.
✗ Branch 46 → 146 not taken.
15 const size_t arraySize = symbolType.getArraySize();
257
258 // Get default value for item
259
2/4
✓ Branch 47 → 48 taken 15 times.
✗ Branch 47 → 138 not taken.
✓ Branch 48 → 49 taken 15 times.
✗ Branch 48 → 138 not taken.
15 llvm::Constant *defaultItemValue = getDefaultValueForSymbolType(symbolType.getContained());
260
261 // Retrieve array and item type
262
2/4
✓ Branch 49 → 50 taken 15 times.
✗ Branch 49 → 139 not taken.
✓ Branch 50 → 51 taken 15 times.
✗ Branch 50 → 139 not taken.
15 llvm::Type *itemType = symbolType.getContained().toLLVMType(sourceFile);
263
1/2
✓ Branch 51 → 52 taken 15 times.
✗ Branch 51 → 146 not taken.
15 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize);
264
265 // Create a constant array with n times the default value
266
1/2
✓ Branch 54 → 55 taken 15 times.
✗ Branch 54 → 140 not taken.
15 const std::vector itemConstants(arraySize, defaultItemValue);
267
1/2
✓ Branch 57 → 58 taken 15 times.
✗ Branch 57 → 143 not taken.
15 return llvm::ConstantArray::get(arrayType, itemConstants);
268 15 }
269
270 // Function or procedure
271
3/4
✓ Branch 61 → 62 taken 46 times.
✗ Branch 61 → 147 not taken.
✓ Branch 62 → 63 taken 16 times.
✓ Branch 62 → 75 taken 30 times.
46 if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
272
2/2
✓ Branch 63 → 64 taken 8 times.
✓ Branch 63 → 69 taken 8 times.
16 if (!llvmTypes.fatPtrType)
273
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()});
274
275
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));
276
1/2
✓ Branch 72 → 73 taken 16 times.
✗ Branch 72 → 151 not taken.
16 return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue});
277 }
278
279 // Struct
280
2/2
✓ Branch 76 → 77 taken 29 times.
✓ Branch 76 → 114 taken 1 time.
30 if (symbolType.is(TY_STRUCT)) {
281 // Retrieve field count
282
1/2
✓ Branch 77 → 78 taken 29 times.
✗ Branch 77 → 158 not taken.
29 Scope *structScope = symbolType.getBodyScope();
283
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 29 times.
29 assert(structScope != nullptr);
284
1/2
✓ Branch 80 → 81 taken 29 times.
✗ Branch 80 → 158 not taken.
29 const size_t fieldCount = structScope->getFieldCount();
285
286 // Get default values for all fields of the struct
287 29 std::vector<llvm::Constant *> fieldConstants;
288
1/2
✓ Branch 81 → 82 taken 29 times.
✗ Branch 81 → 156 not taken.
29 fieldConstants.reserve(fieldCount);
289
290 // Add default value for each struct field
291
2/2
✓ Branch 107 → 83 taken 66 times.
✓ Branch 107 → 108 taken 29 times.
95 for (size_t i = 0; i < fieldCount; i++) {
292 // Get entry of the field
293
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 66 times.
66 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
294
3/6
✓ Branch 88 → 89 taken 66 times.
✗ Branch 88 → 92 not taken.
✓ Branch 89 → 90 taken 66 times.
✗ Branch 89 → 154 not taken.
✓ Branch 90 → 91 taken 66 times.
✗ Branch 90 → 92 not taken.
66 assert(fieldEntry != nullptr && fieldEntry->isField());
295
296 // Retrieve default field value
297 llvm::Constant *defaultFieldValue;
298
4/6
✓ Branch 93 → 94 taken 66 times.
✗ Branch 93 → 95 not taken.
✓ Branch 96 → 97 taken 66 times.
✗ Branch 96 → 102 not taken.
✓ Branch 97 → 98 taken 5 times.
✓ Branch 97 → 102 taken 61 times.
66 if (const auto fieldNode = dynamic_cast<FieldNode *>(fieldEntry->declNode); fieldNode && fieldNode->defaultValue)
299
3/6
✓ Branch 98 → 99 taken 5 times.
✗ Branch 98 → 154 not taken.
✓ Branch 99 → 100 taken 5 times.
✗ Branch 99 → 153 not taken.
✓ Branch 100 → 101 taken 5 times.
✗ Branch 100 → 153 not taken.
5 defaultFieldValue = getConst(fieldNode->defaultValue->getCompileTimeValue(), fieldEntry->getQualType(), fieldNode);
300 else
301
2/4
✓ Branch 102 → 103 taken 61 times.
✗ Branch 102 → 154 not taken.
✓ Branch 103 → 104 taken 61 times.
✗ Branch 103 → 154 not taken.
61 defaultFieldValue = getDefaultValueForSymbolType(fieldEntry->getQualType());
302
303
1/2
✓ Branch 105 → 106 taken 66 times.
✗ Branch 105 → 154 not taken.
66 fieldConstants.push_back(defaultFieldValue);
304 }
305
306
1/2
✓ Branch 108 → 109 taken 29 times.
✗ Branch 108 → 156 not taken.
29 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
307
1/2
✓ Branch 110 → 111 taken 29 times.
✗ Branch 110 → 155 not taken.
29 return llvm::ConstantStruct::get(structType, fieldConstants);
308 29 }
309
310 // Interface
311
1/2
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 121 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
312 1 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
313 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
314 }
315
316 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
317 }
318
319 15867 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
320
2/2
✓ Branch 3 → 4 taken 383 times.
✓ Branch 3 → 9 taken 15484 times.
15867 if (type.is(TY_DOUBLE))
321
2/4
✓ Branch 4 → 5 taken 383 times.
✗ Branch 4 → 56 not taken.
✓ Branch 5 → 6 taken 383 times.
✗ Branch 5 → 54 not taken.
383 return llvm::ConstantFP::get(context, llvm::APFloat(compileTimeValue.doubleValue));
322
323
2/2
✓ Branch 10 → 11 taken 3144 times.
✓ Branch 10 → 13 taken 12340 times.
15484 if (type.is(TY_INT))
324 3144 return builder.getInt32(compileTimeValue.intValue);
325
326
2/2
✓ Branch 14 → 15 taken 576 times.
✓ Branch 14 → 17 taken 11764 times.
12340 if (type.is(TY_SHORT))
327 576 return builder.getInt16(compileTimeValue.shortValue);
328
329
2/2
✓ Branch 18 → 19 taken 5903 times.
✓ Branch 18 → 21 taken 5861 times.
11764 if (type.is(TY_LONG))
330 5903 return builder.getInt64(compileTimeValue.longValue);
331
332
3/4
✓ Branch 21 → 22 taken 5861 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2354 times.
✓ Branch 22 → 25 taken 3507 times.
5861 if (type.isOneOf({TY_BYTE, TY_CHAR}))
333 2354 return builder.getInt8(compileTimeValue.charValue);
334
335
2/2
✓ Branch 26 → 27 taken 2099 times.
✓ Branch 26 → 36 taken 1408 times.
3507 if (type.is(TY_STRING)) {
336 2099 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
337
2/4
✓ Branch 30 → 31 taken 2099 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 2099 times.
✗ Branch 31 → 58 not taken.
6297 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
338 }
339
340
1/2
✓ Branch 37 → 38 taken 1408 times.
✗ Branch 37 → 40 not taken.
1408 if (type.is(TY_BOOL))
341 1408 return builder.getInt1(compileTimeValue.boolValue);
342
343 if (type.is(TY_PTR))
344 return llvm::Constant::getNullValue(builder.getPtrTy());
345
346 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
347 }
348
349 32060 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
350
2/4
✓ Branch 2 → 3 taken 32060 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 32060 times.
✗ Branch 3 → 7 not taken.
32060 return llvm::BasicBlock::Create(context, blockName);
351 }
352
353 32060 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
354
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 32060 times.
32060 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
355 // If no parent function were passed, use the current function
356
2/2
✓ Branch 5 → 6 taken 21453 times.
✓ Branch 5 → 8 taken 10607 times.
32060 if (!parentFct)
357 21453 parentFct = builder.GetInsertBlock()->getParent();
358 // Append block to current function
359 32060 parentFct->insert(parentFct->end(), block);
360 // Set insert point to the block
361 32060 builder.SetInsertPoint(block);
362 32060 blockAlreadyTerminated = false;
363 32060 }
364
365 10001 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
366 10001 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
367 10001 generateScopeCleanup(stmtLstNode);
368 10001 blockAlreadyTerminated = true;
369 10001 }
370
371 12306 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
372
2/2
✓ Branch 2 → 3 taken 3520 times.
✓ Branch 2 → 4 taken 8786 times.
12306 if (blockAlreadyTerminated)
373 3520 return;
374 8786 builder.CreateBr(targetBlock);
375 8786 blockAlreadyTerminated = true;
376 }
377
378 8840 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
379 Likelihood likelihood /*=UNSPECIFIED*/) {
380
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8840 times.
8840 if (blockAlreadyTerminated)
381 return;
382 8840 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
383 8840 blockAlreadyTerminated = true;
384
385
2/2
✓ Branch 5 → 6 taken 776 times.
✓ Branch 5 → 7 taken 8064 times.
8840 if (likelihood != Likelihood::UNSPECIFIED)
386 776 mdGenerator.generateBranchWeightsMetadata(jumpInst, likelihood);
387 }
388
389 10607 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
390 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
391
3/4
✓ Branch 2 → 3 taken 10607 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 205 times.
✓ Branch 3 → 5 taken 10402 times.
10607 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
392 205 return;
393
394 // Verify function
395 10402 std::string output;
396
1/2
✓ Branch 6 → 7 taken 10402 times.
✗ Branch 6 → 21 not taken.
10402 llvm::raw_string_ostream oss(output);
397 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
398 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
399 10402 }
400
401 957 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
402 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
403
3/4
✓ Branch 2 → 3 taken 957 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 23 times.
✓ Branch 3 → 5 taken 934 times.
957 if (cliOptions.disableVerifier || cliOptions.instrumentation.generateDebugInfo)
404 23 return;
405
406 // Verify module
407 934 std::string output;
408
1/2
✓ Branch 6 → 7 taken 934 times.
✗ Branch 6 → 21 not taken.
934 llvm::raw_string_ostream oss(output);
409 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
410 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
411 934 }
412
413 5549 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
414 // Get entry of left side
415
2/4
✓ Branch 2 → 3 taken 5549 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 5549 times.
✗ Branch 3 → 15 not taken.
5549 auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode));
416
6/8
✓ Branch 5 → 6 taken 4751 times.
✓ Branch 5 → 10 taken 798 times.
✓ Branch 6 → 7 taken 4751 times.
✗ Branch 6 → 18 not taken.
✓ Branch 7 → 8 taken 4751 times.
✗ Branch 7 → 18 not taken.
✓ Branch 8 → 9 taken 248 times.
✓ Branch 8 → 10 taken 4503 times.
5549 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr;
417
1/2
✓ Branch 11 → 12 taken 5549 times.
✗ Branch 11 → 18 not taken.
11098 return doAssignment(lhsAddress, entry, rhsNode, node);
418 }
419
420 13054 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
421 const ASTNode *node, bool isDecl) {
422 // Get symbol type of right side
423
1/2
✓ Branch 2 → 3 taken 13054 times.
✗ Branch 2 → 13 not taken.
13054 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
424
2/4
✓ Branch 3 → 4 taken 13054 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 13054 times.
✗ Branch 4 → 10 not taken.
13054 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
425
1/2
✓ Branch 6 → 7 taken 13054 times.
✗ Branch 6 → 13 not taken.
26108 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
426 }
427
428 13173 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
429 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
430 // Deduce some information about the assignment
431
4/4
✓ Branch 2 → 3 taken 12375 times.
✓ Branch 2 → 7 taken 798 times.
✓ Branch 5 → 6 taken 501 times.
✓ Branch 5 → 7 taken 11874 times.
13173 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
432
8/10
✓ Branch 8 → 9 taken 12672 times.
✓ Branch 8 → 15 taken 501 times.
✓ Branch 9 → 10 taken 12672 times.
✗ Branch 9 → 177 not taken.
✓ Branch 10 → 11 taken 12672 times.
✗ Branch 10 → 177 not taken.
✓ Branch 11 → 12 taken 1405 times.
✓ Branch 11 → 15 taken 11267 times.
✓ Branch 13 → 14 taken 182 times.
✓ Branch 13 → 15 taken 1223 times.
13173 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
433
434
2/2
✓ Branch 16 → 17 taken 501 times.
✓ Branch 16 → 57 taken 12672 times.
13173 if (isRefAssign) {
435
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 501 times.
501 assert(lhsEntry != nullptr);
436
2/2
✓ Branch 19 → 20 taken 253 times.
✓ Branch 19 → 33 taken 248 times.
501 if (isDecl) { // Reference gets initially assigned
437 // Get address of right side
438 253 llvm::Value *rhsAddress = resolveAddress(rhs);
439
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 253 times.
253 assert(rhsAddress != nullptr);
440
441 // Store lhs pointer to rhs
442
2/4
✓ Branch 26 → 27 taken 253 times.
✗ Branch 26 → 178 not taken.
✓ Branch 27 → 28 taken 253 times.
✗ Branch 27 → 178 not taken.
253 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
443 253 lhsEntry->updateAddress(refAddress);
444 253 insertStore(rhsAddress, refAddress);
445
446 253 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
447 }
448
449 // Reference to reference assignment (only for struct fields that are not initialized yet)
450 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
451
6/8
✓ Branch 33 → 34 taken 171 times.
✓ Branch 33 → 40 taken 77 times.
✓ Branch 35 → 36 taken 171 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 165 times.
✓ Branch 36 → 40 taken 6 times.
✓ Branch 38 → 39 taken 165 times.
✗ Branch 38 → 40 not taken.
248 const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField();
452 // Assigning the result variable
453 248 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
454
4/4
✓ Branch 42 → 43 taken 83 times.
✓ Branch 42 → 44 taken 165 times.
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 49 taken 81 times.
248 if (isInitialFieldRefAssign || isReturnValAssign) {
455 // Get address of right side
456 167 llvm::Value *referencedAddress = resolveAddress(rhs);
457
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 167 times.
167 assert(referencedAddress != nullptr);
458
459 // Store the rhs* to the lhs**
460 167 insertStore(referencedAddress, lhsAddress);
461
462 167 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
463 }
464
465 // Load referenced address
466
3/6
✓ Branch 51 → 52 taken 81 times.
✗ Branch 51 → 186 not taken.
✓ Branch 52 → 53 taken 81 times.
✗ Branch 52 → 184 not taken.
✓ Branch 53 → 54 taken 81 times.
✗ Branch 53 → 184 not taken.
162 lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress);
467 }
468
469 // Check if we need to copy the rhs to the lhs. This happens for structs
470
2/2
✓ Branch 57 → 58 taken 182 times.
✓ Branch 57 → 123 taken 12571 times.
12753 if (needsCopy) {
471 // Get address of right side
472
1/2
✓ Branch 58 → 59 taken 182 times.
✗ Branch 58 → 237 not taken.
182 llvm::Value *rhsAddress = resolveAddress(rhs);
473
1/2
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 182 times.
182 assert(rhsAddress != nullptr);
474
475 // Allocate new memory if the lhs address does not exist
476
2/2
✓ Branch 61 → 62 taken 4 times.
✓ Branch 61 → 72 taken 178 times.
182 if (!lhsAddress) {
477
1/2
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 4 times.
4 assert(lhsEntry != nullptr);
478
3/6
✓ Branch 66 → 67 taken 4 times.
✗ Branch 66 → 192 not taken.
✓ Branch 67 → 68 taken 4 times.
✗ Branch 67 → 190 not taken.
✓ Branch 68 → 69 taken 4 times.
✗ Branch 68 → 190 not taken.
4 lhsAddress = insertAlloca(lhsEntry->getQualType());
479
1/2
✓ Branch 71 → 72 taken 4 times.
✗ Branch 71 → 237 not taken.
4 lhsEntry->updateAddress(lhsAddress);
480 }
481
482 // Check if we have a copy ctor
483
2/4
✓ Branch 72 → 73 taken 182 times.
✗ Branch 72 → 196 not taken.
✓ Branch 73 → 74 taken 182 times.
✗ Branch 73 → 196 not taken.
182 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
484
1/2
✓ Branch 74 → 75 taken 182 times.
✗ Branch 74 → 237 not taken.
182 Scope *structScope = rhsSTypeNonRef.getBodyScope();
485
2/4
✓ Branch 75 → 76 taken 182 times.
✗ Branch 75 → 201 not taken.
✓ Branch 80 → 81 taken 182 times.
✗ Branch 80 → 197 not taken.
546 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
486
2/4
✓ Branch 84 → 85 taken 182 times.
✗ Branch 84 → 205 not taken.
✓ Branch 85 → 86 taken 182 times.
✗ Branch 85 → 203 not taken.
182 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
487
2/2
✓ Branch 88 → 89 taken 77 times.
✓ Branch 88 → 96 taken 105 times.
182 if (copyCtor != nullptr) {
488 // Call copy ctor
489
2/4
✓ Branch 91 → 92 taken 77 times.
✗ Branch 91 → 211 not taken.
✓ Branch 92 → 93 taken 77 times.
✗ Branch 92 → 209 not taken.
231 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
490
2/4
✓ Branch 96 → 97 taken 105 times.
✗ Branch 96 → 235 not taken.
✓ Branch 97 → 98 taken 105 times.
✗ Branch 97 → 114 not taken.
105 } else if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
491 // Create shallow copy
492
1/2
✓ Branch 98 → 99 taken 105 times.
✗ Branch 98 → 223 not taken.
105 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
493
6/10
✓ Branch 99 → 100 taken 100 times.
✓ Branch 99 → 101 taken 5 times.
✓ Branch 100 → 104 taken 100 times.
✗ Branch 100 → 216 not taken.
✓ Branch 103 → 104 taken 5 times.
✗ Branch 103 → 216 not taken.
✓ Branch 104 → 105 taken 5 times.
✓ Branch 104 → 107 taken 100 times.
✗ Branch 216 → 217 not taken.
✗ Branch 216 → 219 not taken.
110 const std::string copyName = lhsEntry ? lhsEntry->name : "";
494
4/6
✓ Branch 107 → 108 taken 100 times.
✓ Branch 107 → 110 taken 5 times.
✗ Branch 108 → 109 not taken.
✓ Branch 108 → 110 taken 100 times.
✓ Branch 111 → 112 taken 105 times.
✗ Branch 111 → 221 not taken.
105 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
495 105 } else {
496 const std::string structName = rhsSTypeNonRef.getName();
497 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
498 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
499 }
500 182 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
501 182 }
502
503
7/8
✓ Branch 123 → 124 taken 7367 times.
✓ Branch 123 → 129 taken 5204 times.
✓ Branch 125 → 126 taken 920 times.
✓ Branch 125 → 129 taken 6447 times.
✓ Branch 127 → 128 taken 920 times.
✗ Branch 127 → 129 not taken.
✓ Branch 130 → 131 taken 920 times.
✓ Branch 130 → 136 taken 11651 times.
12571 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
504
1/2
✗ Branch 131 → 132 not taken.
✓ Branch 131 → 133 taken 920 times.
920 assert(lhsEntry != nullptr);
505 // Directly set the address to the lhs entry (temp stealing)
506 920 llvm::Value *rhsAddress = resolveAddress(rhs);
507 920 lhsEntry->updateAddress(rhsAddress);
508 920 rhs.entry = lhsEntry;
509 920 return rhs;
510 }
511
512 // Allocate new memory if the lhs address does not exist
513
2/2
✓ Branch 136 → 137 taken 6416 times.
✓ Branch 136 → 147 taken 5235 times.
11651 if (!lhsAddress) {
514
1/2
✗ Branch 137 → 138 not taken.
✓ Branch 137 → 139 taken 6416 times.
6416 assert(lhsEntry != nullptr);
515
3/6
✓ Branch 141 → 142 taken 6416 times.
✗ Branch 141 → 240 not taken.
✓ Branch 142 → 143 taken 6416 times.
✗ Branch 142 → 238 not taken.
✓ Branch 143 → 144 taken 6416 times.
✗ Branch 143 → 238 not taken.
6416 lhsAddress = insertAlloca(lhsEntry->getQualType());
516 6416 lhsEntry->updateAddress(lhsAddress);
517 }
518
519 // 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
520
10/10
✓ Branch 147 → 148 taken 10877 times.
✓ Branch 147 → 156 taken 774 times.
✓ Branch 150 → 151 taken 2195 times.
✓ Branch 150 → 156 taken 8682 times.
✓ Branch 152 → 153 taken 6 times.
✓ Branch 152 → 156 taken 2189 times.
✓ Branch 154 → 155 taken 2 times.
✓ Branch 154 → 156 taken 4 times.
✓ Branch 157 → 158 taken 2 times.
✓ Branch 157 → 173 taken 11649 times.
11651 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
521 // Get address of right side
522
1/2
✓ Branch 158 → 159 taken 2 times.
✗ Branch 158 → 251 not taken.
2 llvm::Value *rhsAddress = resolveAddress(rhs);
523
1/2
✗ Branch 159 → 160 not taken.
✓ Branch 159 → 161 taken 2 times.
2 assert(rhsAddress != nullptr);
524
1/2
✓ Branch 161 → 162 taken 2 times.
✗ Branch 161 → 251 not taken.
2 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
525
2/4
✓ Branch 162 → 163 taken 2 times.
✗ Branch 162 → 251 not taken.
✓ Branch 163 → 164 taken 2 times.
✗ Branch 163 → 251 not taken.
2 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
526
1/2
✓ Branch 168 → 169 taken 2 times.
✗ Branch 168 → 244 not taken.
2 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
527
1/2
✓ Branch 171 → 172 taken 2 times.
✗ Branch 171 → 251 not taken.
2 insertStore(firstItemAddress, lhsAddress);
528 2 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
529 }
530
531 // We can load the value from the right side and store it to the left side
532 // Retrieve value of the right side
533 11649 llvm::Value *rhsValue = resolveValue(rhsSType, rhs);
534 // Store the value to the address
535 11649 insertStore(rhsValue, lhsAddress, rhsSType);
536 11649 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
537 }
538
539 142 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
540 bool isVolatile) const {
541 // Retrieve size to copy
542
1/2
✓ Branch 3 → 4 taken 142 times.
✗ Branch 3 → 19 not taken.
142 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
543
544 // Create values for memcpy intrinsic
545
2/4
✓ Branch 4 → 5 taken 142 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 142 times.
✗ Branch 5 → 19 not taken.
142 llvm::Value *structSize = builder.getInt64(typeSize);
546
1/2
✓ Branch 6 → 7 taken 142 times.
✗ Branch 6 → 19 not taken.
142 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
547
548 // Call memcpy intrinsic to execute the shallow copy
549
1/2
✓ Branch 7 → 8 taken 142 times.
✗ Branch 7 → 19 not taken.
142 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
550
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 142 times.
142 assert(targetAddress != nullptr);
551
3/6
✓ Branch 10 → 11 taken 142 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 142 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 142 times.
✗ Branch 13 → 15 not taken.
142 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
552 142 }
553
554 22470 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) {
555
6/6
✓ Branch 12 → 13 taken 23386 times.
✓ Branch 12 → 15 taken 16792 times.
✓ Branch 14 → 15 taken 916 times.
✓ Branch 14 → 16 taken 22470 times.
✓ Branch 17 → 3 taken 17708 times.
✓ Branch 17 → 18 taken 22470 times.
40178 while (symbolType.isPtr() || symbolType.isRef()) {
556
2/4
✓ Branch 5 → 6 taken 17708 times.
✗ Branch 5 → 21 not taken.
✓ Branch 6 → 7 taken 17708 times.
✗ Branch 6 → 19 not taken.
17708 ptr = insertLoad(symbolType, ptr);
557
1/2
✓ Branch 9 → 10 taken 17708 times.
✗ Branch 9 → 25 not taken.
17708 symbolType = symbolType.getContained();
558 }
559 22470 }
560
561 53 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
562 // Get unused name
563
1/2
✓ Branch 2 → 3 taken 53 times.
✗ Branch 2 → 19 not taken.
53 const std::string globalName = getUnusedGlobalName(baseName);
564 // Create global
565
1/2
✓ Branch 5 → 6 taken 53 times.
✗ Branch 5 → 15 not taken.
53 module->getOrInsertGlobal(globalName, constant->getType());
566
1/2
✓ Branch 7 → 8 taken 53 times.
✗ Branch 7 → 16 not taken.
53 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
567 // Set initializer to the given constant
568
1/2
✓ Branch 8 → 9 taken 53 times.
✗ Branch 8 → 17 not taken.
53 global->setInitializer(constant);
569 53 global->setConstant(true);
570
1/2
✓ Branch 10 → 11 taken 53 times.
✗ Branch 10 → 17 not taken.
53 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
571 53 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
572 53 return global;
573 53 }
574
575 2910 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
576 // Get unused name
577
1/2
✓ Branch 2 → 3 taken 2910 times.
✗ Branch 2 → 21 not taken.
2910 const std::string globalName = getUnusedGlobalName(baseName);
578 // Create global
579
2/4
✓ Branch 3 → 4 taken 2910 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 2910 times.
✗ Branch 5 → 15 not taken.
2910 builder.CreateGlobalString(value, globalName, 0, module);
580
1/2
✓ Branch 7 → 8 taken 2910 times.
✗ Branch 7 → 17 not taken.
2910 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
581 // If the output should be comparable, fix alignment to 4 bytes
582
1/2
✓ Branch 8 → 9 taken 2910 times.
✗ Branch 8 → 12 not taken.
2910 if (cliOptions.comparableOutput)
583
2/4
✓ Branch 9 → 10 taken 2910 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 2910 times.
✗ Branch 10 → 18 not taken.
2910 global->setAlignment(llvm::Align(4));
584 2910 return global;
585 2910 }
586
587 2910 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
588 const CodeLoc &codeLoc) const {
589 2910 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
590 // Create debug info
591
2/2
✓ Branch 3 → 4 taken 48 times.
✓ Branch 3 → 10 taken 2862 times.
2910 if (cliOptions.instrumentation.generateDebugInfo)
592
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);
593 2910 return global;
594 }
595
596 4452 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
597 // Find an unused global name
598 4452 std::string globalName;
599 4452 unsigned int suffixNumber = 0;
600 do {
601
1/2
✓ Branch 5 → 6 taken 49673 times.
✗ Branch 5 → 15 not taken.
49673 globalName = baseName + std::to_string(suffixNumber);
602 49673 suffixNumber++;
603
3/4
✓ Branch 10 → 11 taken 49673 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 45221 times.
✓ Branch 11 → 13 taken 4452 times.
49673 } while (module->getNamedGlobal(globalName) != nullptr);
604 4452 return globalName;
605 }
606
607 16514 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
608 // Skip results, that do not contain a constant or already have a value
609
3/4
✓ Branch 2 → 3 taken 16114 times.
✓ Branch 2 → 4 taken 400 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 16114 times.
16514 if (exprResult.value != nullptr || exprResult.constant == nullptr)
610 400 return;
611
612 // Default case: the value to the constant
613 16114 exprResult.value = exprResult.constant;
614 }
615
616 1840 std::string IRGenerator::getIRString(llvm::Module *llvmModule, const CliOptions &cliOptions) {
617
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 1840 times.
1840 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
618
3/4
✓ Branch 4 → 5 taken 1840 times.
✗ Branch 4 → 7 not taken.
✓ Branch 5 → 6 taken 1744 times.
✓ Branch 5 → 7 taken 96 times.
1840 const bool eliminateTarget = cliOptions.comparableOutput && cliOptions.isNativeTarget;
619
620 // Backup target triple and data layout
621
1/2
✓ Branch 9 → 10 taken 1840 times.
✗ Branch 9 → 45 not taken.
1840 const llvm::Triple targetTriple = llvmModule->getTargetTriple();
622
1/2
✓ Branch 11 → 12 taken 1840 times.
✗ Branch 11 → 43 not taken.
1840 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
623 // Remove target triple and data layout
624
2/2
✓ Branch 12 → 13 taken 1744 times.
✓ Branch 12 → 19 taken 96 times.
1840 if (eliminateTarget) {
625 1744 llvmModule->setTargetTriple(llvm::Triple());
626
2/4
✓ Branch 16 → 17 taken 1744 times.
✗ Branch 16 → 34 not taken.
✓ Branch 17 → 18 taken 1744 times.
✗ Branch 17 → 34 not taken.
1744 llvmModule->setDataLayout("");
627 }
628
629 // Get IR string
630 1840 std::string output;
631
1/2
✓ Branch 20 → 21 taken 1840 times.
✗ Branch 20 → 39 not taken.
1840 llvm::raw_string_ostream oss(output);
632
1/2
✓ Branch 21 → 22 taken 1840 times.
✗ Branch 21 → 37 not taken.
1840 llvmModule->print(oss, nullptr);
633
634 // Restore target triple and data layout
635
2/2
✓ Branch 22 → 23 taken 1744 times.
✓ Branch 22 → 29 taken 96 times.
1840 if (eliminateTarget) {
636
1/2
✓ Branch 23 → 24 taken 1744 times.
✗ Branch 23 → 35 not taken.
1744 llvmModule->setTargetTriple(targetTriple);
637
1/2
✓ Branch 27 → 28 taken 1744 times.
✗ Branch 27 → 36 not taken.
1744 llvmModule->setDataLayout(targetDataLayout);
638 }
639
640 1840 return output;
641 1840 }
642
643 /**
644 * Returns the operator function list for the current manifestation and the given node
645 *
646 * @param node Node to retrieve the op fct pointer list from
647 * @return Op fct pointer list
648 */
649 18346 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
650
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 18346 times.
18346 assert(node->getOpFctPointers()->size() > manIdx);
651 18346 return node->getOpFctPointers()->at(manIdx);
652 }
653
654 } // namespace spice::compiler
655