GCC Code Coverage Report


Directory: ../
File: src/irgenerator/IRGenerator.cpp
Date: 2025-10-09 06:28:01
Coverage Exec Excl Total
Lines: 96.3% 334 6 353
Functions: 100.0% 34 0 34
Branches: 60.7% 396 20 672

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 892 IRGenerator::IRGenerator(GlobalResourceManager &resourceManager, SourceFile *sourceFile)
16 892 : CompilerPass(resourceManager, sourceFile), context(cliOptions.useLTO ? resourceManager.ltoContext : sourceFile->context),
17
1/2
✓ Branch 8 → 9 taken 892 times.
✗ Branch 8 → 61 not taken.
892 builder(sourceFile->builder), module(sourceFile->llvmModule.get()), conversionManager(sourceFile, this),
18
5/8
✓ Branch 4 → 5 taken 2 times.
✓ Branch 4 → 6 taken 890 times.
✓ Branch 9 → 10 taken 892 times.
✗ Branch 9 → 61 not taken.
✓ Branch 10 → 11 taken 892 times.
✗ Branch 10 → 61 not taken.
✓ Branch 14 → 15 taken 892 times.
✗ Branch 14 → 55 not taken.
1784 stdFunctionManager(sourceFile, resourceManager, module) {
19 // Attach information to the module
20
1/2
✓ Branch 16 → 17 taken 892 times.
✗ Branch 16 → 40 not taken.
892 module->setTargetTriple(cliOptions.targetTriple);
21
2/4
✓ Branch 20 → 21 taken 892 times.
✗ Branch 20 → 43 not taken.
✓ Branch 21 → 22 taken 892 times.
✗ Branch 21 → 41 not taken.
892 module->setDataLayout(sourceFile->targetMachine->createDataLayout());
22
1/2
✓ Branch 23 → 24 taken 892 times.
✗ Branch 23 → 51 not taken.
892 module->setPICLevel(llvm::PICLevel::BigPIC);
23
1/2
✓ Branch 24 → 25 taken 892 times.
✗ Branch 24 → 51 not taken.
892 module->setPIELevel(llvm::PIELevel::Large);
24
1/2
✓ Branch 25 → 26 taken 892 times.
✗ Branch 25 → 51 not taken.
892 module->setUwtable(llvm::UWTableKind::Default);
25
1/2
✓ Branch 26 → 27 taken 892 times.
✗ Branch 26 → 51 not taken.
892 module->setFramePointer(llvm::FramePointerKind::All);
26
27 // Add module identifier metadata
28
2/4
✓ Branch 27 → 28 taken 892 times.
✗ Branch 27 → 44 not taken.
✓ Branch 28 → 29 taken 892 times.
✗ Branch 28 → 44 not taken.
892 llvm::NamedMDNode *identifierMetadata = module->getOrInsertNamedMetadata("llvm.ident");
29
3/6
✓ Branch 30 → 31 taken 892 times.
✗ Branch 30 → 45 not taken.
✓ Branch 32 → 33 taken 892 times.
✗ Branch 32 → 45 not taken.
✓ Branch 33 → 34 taken 892 times.
✗ Branch 33 → 45 not taken.
892 identifierMetadata->addOperand(llvm::MDNode::get(context, llvm::MDString::get(context, PRODUCER_STRING)));
30
31 // Initialize debug info generator
32
2/2
✓ Branch 34 → 35 taken 15 times.
✓ Branch 34 → 39 taken 877 times.
892 if (cliOptions.generateDebugInfo)
33
2/4
✓ Branch 35 → 36 taken 15 times.
✗ Branch 35 → 50 not taken.
✓ Branch 36 → 37 taken 15 times.
✗ Branch 36 → 48 not taken.
15 diGenerator.initialize(sourceFile->fileName, sourceFile->fileDir);
34 892 }
35
36 892 std::any IRGenerator::visitEntry(const EntryNode *node) {
37 // Generate IR
38
1/2
✓ Branch 2 → 3 taken 892 times.
✗ Branch 2 → 19 not taken.
892 visitChildren(node);
39
40 // Generate test main if required
41
4/4
✓ Branch 4 → 5 taken 236 times.
✓ Branch 4 → 7 taken 656 times.
✓ Branch 5 → 6 taken 2 times.
✓ Branch 5 → 7 taken 234 times.
892 if (sourceFile->isMainFile && cliOptions.generateTestMain)
42 2 generateTestMain();
43
44 // Execute deferred VTable initializations
45
2/2
✓ Branch 13 → 9 taken 355 times.
✓ Branch 13 → 14 taken 892 times.
1247 for (DeferredLogic &deferredVTableInit : deferredVTableInitializations)
46
1/2
✓ Branch 10 → 11 taken 355 times.
✗ Branch 10 → 20 not taken.
355 deferredVTableInit.execute();
47
48 // Finalize debug info generator
49 892 diGenerator.finalize();
50
51 // Verify module
52 892 verifyModule(node->codeLoc);
53
54
1/2
✓ Branch 16 → 17 taken 892 times.
✗ Branch 16 → 21 not taken.
892 return nullptr;
55 }
56
57 33279 llvm::Value *IRGenerator::insertAlloca(llvm::Type *llvmType, std::string varName) {
58
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 33279 times.
33279 if (!cliOptions.namesForIRValues)
59 varName = "";
60
61
2/2
✓ Branch 4 → 5 taken 23281 times.
✓ Branch 4 → 12 taken 9998 times.
33279 if (allocaInsertInst != nullptr) { // If there is already an alloca inst, insert right after that
62
2/4
✓ Branch 5 → 6 taken 23281 times.
✗ Branch 5 → 29 not taken.
✓ Branch 6 → 7 taken 23281 times.
✗ Branch 6 → 29 not taken.
23281 llvm::AllocaInst *allocaInst = builder.CreateAlloca(llvmType, nullptr, varName);
63
1/2
✓ Branch 8 → 9 taken 23281 times.
✗ Branch 8 → 30 not taken.
23281 allocaInst->setDebugLoc(llvm::DebugLoc());
64 23281 allocaInst->moveAfter(allocaInsertInst);
65 23281 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 9998 llvm::BasicBlock *currentBlock = builder.GetInsertBlock();
69 9998 builder.SetInsertPoint(allocaInsertBlock, allocaInsertBlock->begin());
70
71 // Allocate the size of the given LLVM type
72
2/4
✓ Branch 15 → 16 taken 9998 times.
✗ Branch 15 → 33 not taken.
✓ Branch 16 → 17 taken 9998 times.
✗ Branch 16 → 33 not taken.
9998 allocaInsertInst = builder.CreateAlloca(llvmType, nullptr, varName);
73
1/2
✓ Branch 18 → 19 taken 9998 times.
✗ Branch 18 → 34 not taken.
9998 allocaInsertInst->setDebugLoc(llvm::DebugLoc());
74
75 // Restore old basic block
76 9998 builder.SetInsertPoint(currentBlock);
77 }
78
79 // Insert lifetime start marker
80
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 27 taken 33279 times.
33279 if (cliOptions.useLifetimeMarkers) {
81 const uint64_t sizeInBytes = module->getDataLayout().getTypeAllocSize(llvmType);
82 builder.CreateLifetimeStart(allocaInsertInst, builder.getInt64(sizeInBytes));
83 }
84
85 33279 return allocaInsertInst;
86 }
87
88 66899 llvm::Value *IRGenerator::insertLoad(llvm::Type *llvmType, llvm::Value *ptr, bool isVolatile, const std::string &varName) const {
89
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 66899 times.
66899 assert(ptr->getType()->isPointerTy());
90
5/14
✓ Branch 6 → 7 taken 66899 times.
✗ Branch 6 → 8 not taken.
✓ Branch 7 → 11 taken 66899 times.
✗ Branch 7 → 22 not taken.
✗ Branch 10 → 11 not taken.
✗ Branch 10 → 22 not taken.
✓ Branch 11 → 12 taken 66899 times.
✗ Branch 11 → 20 not taken.
✓ Branch 12 → 13 taken 66899 times.
✗ Branch 12 → 20 not taken.
✗ Branch 15 → 16 not taken.
✓ Branch 15 → 18 taken 66899 times.
✗ Branch 22 → 23 not taken.
✗ Branch 22 → 25 not taken.
66899 return builder.CreateLoad(llvmType, ptr, isVolatile, cliOptions.namesForIRValues ? varName : "");
91 }
92
93 34512 void IRGenerator::insertStore(llvm::Value *val, llvm::Value *ptr, bool isVolatile) const {
94
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 34512 times.
34512 assert(ptr->getType()->isPointerTy());
95 34512 builder.CreateStore(val, ptr, isVolatile);
96 34512 }
97
98 17963 llvm::Value *IRGenerator::insertInBoundsGEP(llvm::Type *type, llvm::Value *basePtr, llvm::ArrayRef<llvm::Value *> indices,
99 std::string varName) const {
100
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 17963 times.
17963 assert(basePtr->getType()->isPointerTy());
101
1/2
✗ Branch 7 → 8 not taken.
✓ Branch 7 → 9 taken 17963 times.
17963 assert(!indices.empty());
102
4/6
✓ Branch 4 → 5 taken 17654 times.
✓ Branch 4 → 7 taken 15713 times.
✓ Branch 6 → 7 taken 17654 times.
✗ Branch 6 → 8 not taken.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 17963 times.
51330 assert(std::ranges::all_of(indices, [](const llvm::Value *index) {
103 const llvm::Type *indexType = index->getType();
104 return indexType->isIntegerTy(32) || indexType->isIntegerTy(64);
105 }));
106
107
1/2
✗ Branch 12 → 13 not taken.
✓ Branch 12 → 14 taken 17963 times.
17963 if (!cliOptions.namesForIRValues)
108 varName = "";
109
110 // Insert GEP
111
2/4
✓ Branch 14 → 15 taken 17963 times.
✗ Branch 14 → 19 not taken.
✓ Branch 15 → 16 taken 17963 times.
✗ Branch 15 → 19 not taken.
17963 return builder.CreateInBoundsGEP(type, basePtr, indices, varName);
112 }
113
114 5155 llvm::Value *IRGenerator::insertStructGEP(llvm::Type *type, llvm::Value *basePtr, unsigned int index, std::string varName) const {
115
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 5155 times.
5155 assert(basePtr->getType()->isPointerTy());
116
117
1/2
✗ Branch 6 → 7 not taken.
✓ Branch 6 → 8 taken 5155 times.
5155 if (!cliOptions.namesForIRValues)
118 varName = "";
119
120 // If we use index 0 we can use the base pointer directly
121
2/2
✓ Branch 8 → 9 taken 1798 times.
✓ Branch 8 → 10 taken 3357 times.
5155 if (index == 0)
122 1798 return basePtr;
123
124 // Insert GEP
125
2/4
✓ Branch 10 → 11 taken 3357 times.
✗ Branch 10 → 15 not taken.
✓ Branch 11 → 12 taken 3357 times.
✗ Branch 11 → 15 not taken.
3357 return builder.CreateStructGEP(type, basePtr, index, varName);
126 }
127
128 38316 llvm::Value *IRGenerator::resolveValue(const ExprNode *node) {
129 // Visit the given AST node
130
2/4
✓ Branch 2 → 3 taken 38316 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 38316 times.
✗ Branch 3 → 9 not taken.
38316 auto exprResult = any_cast<LLVMExprResult>(visit(node));
131
1/2
✓ Branch 5 → 6 taken 38316 times.
✗ Branch 5 → 12 not taken.
76632 return resolveValue(node, exprResult);
132 }
133
134 44284 llvm::Value *IRGenerator::resolveValue(const ExprNode *node, LLVMExprResult &exprResult) const {
135 44284 return resolveValue(node->getEvaluatedSymbolType(manIdx), exprResult);
136 }
137
138 87370 llvm::Value *IRGenerator::resolveValue(const QualType &qualType, LLVMExprResult &exprResult) const {
139 // Check if the value is already present
140
2/2
✓ Branch 2 → 3 taken 28914 times.
✓ Branch 2 → 4 taken 58456 times.
87370 if (exprResult.value != nullptr)
141 28914 return exprResult.value;
142
143 // Check if a constant is present
144
2/2
✓ Branch 4 → 5 taken 15092 times.
✓ Branch 4 → 7 taken 43364 times.
58456 if (exprResult.constant != nullptr) {
145 15092 materializeConstant(exprResult);
146 15092 return exprResult.value;
147 }
148
149
3/4
✓ Branch 7 → 8 taken 529 times.
✓ Branch 7 → 10 taken 42835 times.
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 529 times.
43364 assert(exprResult.ptr != nullptr || exprResult.refPtr != nullptr);
150
151 // De-reference if reference type
152
1/2
✓ Branch 10 → 11 taken 43364 times.
✗ Branch 10 → 51 not taken.
43364 const QualType referencedType = qualType.removeReferenceWrapper();
153
4/4
✓ Branch 11 → 12 taken 533 times.
✓ Branch 11 → 25 taken 42831 times.
✓ Branch 12 → 13 taken 529 times.
✓ Branch 12 → 25 taken 4 times.
43364 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr)
154
6/10
✓ Branch 15 → 16 taken 529 times.
✗ Branch 15 → 41 not taken.
✓ Branch 16 → 17 taken 529 times.
✗ Branch 16 → 19 not taken.
✓ Branch 17 → 18 taken 5 times.
✓ Branch 17 → 19 taken 524 times.
✓ Branch 20 → 21 taken 529 times.
✗ Branch 20 → 39 not taken.
✓ Branch 21 → 22 taken 529 times.
✗ Branch 21 → 39 not taken.
1058 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile);
155
156 // Load the value from the pointer
157
1/2
✓ Branch 25 → 26 taken 43364 times.
✗ Branch 25 → 51 not taken.
43364 llvm::Type *valueTy = referencedType.toLLVMType(sourceFile);
158
6/8
✓ Branch 28 → 29 taken 43364 times.
✗ Branch 28 → 47 not taken.
✓ Branch 29 → 30 taken 39991 times.
✓ Branch 29 → 32 taken 3373 times.
✓ Branch 30 → 31 taken 10 times.
✓ Branch 30 → 32 taken 39981 times.
✓ Branch 33 → 34 taken 43364 times.
✗ Branch 33 → 45 not taken.
43364 exprResult.value = insertLoad(valueTy, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile);
159
160 43364 return exprResult.value;
161 }
162
163 2772 llvm::Value *IRGenerator::resolveAddress(const ASTNode *node) {
164 // Visit the given AST node
165
2/4
✓ Branch 2 → 3 taken 2772 times.
✗ Branch 2 → 11 not taken.
✓ Branch 3 → 4 taken 2772 times.
✗ Branch 3 → 9 not taken.
2772 auto exprResult = any_cast<LLVMExprResult>(visit(node));
166
1/2
✓ Branch 5 → 6 taken 2772 times.
✗ Branch 5 → 12 not taken.
5544 return resolveAddress(exprResult);
167 }
168
169 20504 llvm::Value *IRGenerator::resolveAddress(LLVMExprResult &exprResult) {
170 // Check if an address is already present
171
2/2
✓ Branch 2 → 3 taken 17177 times.
✓ Branch 2 → 4 taken 3327 times.
20504 if (exprResult.ptr != nullptr)
172 17177 return exprResult.ptr;
173
174 // Check if the reference address is already present
175
3/4
✓ Branch 4 → 5 taken 2602 times.
✓ Branch 4 → 18 taken 725 times.
✓ Branch 5 → 6 taken 2602 times.
✗ Branch 5 → 18 not taken.
3327 if (exprResult.refPtr != nullptr && exprResult.ptr == nullptr) {
176
6/10
✓ Branch 8 → 9 taken 2602 times.
✗ Branch 8 → 41 not taken.
✓ Branch 9 → 10 taken 2597 times.
✓ Branch 9 → 12 taken 5 times.
✗ Branch 10 → 11 not taken.
✓ Branch 10 → 12 taken 2597 times.
✓ Branch 13 → 14 taken 2602 times.
✗ Branch 13 → 39 not taken.
✓ Branch 14 → 15 taken 2602 times.
✗ Branch 14 → 39 not taken.
2602 exprResult.ptr = insertLoad(builder.getPtrTy(), exprResult.refPtr, exprResult.entry && exprResult.entry->isVolatile);
177 2602 return exprResult.ptr;
178 }
179
180 // If not, store the value or constant
181 725 materializeConstant(exprResult);
182
1/2
✗ Branch 19 → 20 not taken.
✓ Branch 19 → 21 taken 725 times.
725 assert(exprResult.value != nullptr);
183
7/12
✓ Branch 21 → 22 taken 6 times.
✓ Branch 21 → 23 taken 719 times.
✓ Branch 22 → 26 taken 6 times.
✗ Branch 22 → 47 not taken.
✓ Branch 25 → 26 taken 719 times.
✗ Branch 25 → 47 not taken.
✓ Branch 27 → 28 taken 725 times.
✗ Branch 27 → 45 not taken.
✓ Branch 29 → 30 taken 719 times.
✓ Branch 29 → 32 taken 6 times.
✗ Branch 47 → 48 not taken.
✗ Branch 47 → 50 not taken.
1444 exprResult.ptr = insertAlloca(exprResult.value->getType(), exprResult.entry ? exprResult.entry->name : "");
184
3/4
✓ Branch 32 → 33 taken 6 times.
✓ Branch 32 → 35 taken 719 times.
✗ Branch 33 → 34 not taken.
✓ Branch 33 → 35 taken 6 times.
725 insertStore(exprResult.value, exprResult.ptr, exprResult.entry && exprResult.entry->isVolatile);
185
186 725 return exprResult.ptr;
187 }
188
189 2422 llvm::Constant *IRGenerator::getDefaultValueForSymbolType(const QualType &symbolType) { // NOLINT(misc-no-recursion)
190 // Double
191
2/2
✓ Branch 3 → 4 taken 4 times.
✓ Branch 3 → 9 taken 2418 times.
2422 if (symbolType.is(TY_DOUBLE))
192
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));
193
194 // Int
195
2/2
✓ Branch 10 → 11 taken 326 times.
✓ Branch 10 → 13 taken 2092 times.
2418 if (symbolType.is(TY_INT))
196 326 return builder.getInt32(0);
197
198 // Short
199
2/2
✓ Branch 14 → 15 taken 12 times.
✓ Branch 14 → 17 taken 2080 times.
2092 if (symbolType.is(TY_SHORT))
200 12 return builder.getInt16(0);
201
202 // Long
203
2/2
✓ Branch 18 → 19 taken 906 times.
✓ Branch 18 → 21 taken 1174 times.
2080 if (symbolType.is(TY_LONG))
204 906 return builder.getInt64(0);
205
206 // Byte or char
207
3/4
✓ Branch 21 → 22 taken 1174 times.
✗ Branch 21 → 133 not taken.
✓ Branch 22 → 23 taken 20 times.
✓ Branch 22 → 25 taken 1154 times.
1174 if (symbolType.isOneOf({TY_BYTE, TY_CHAR}))
208 20 return builder.getInt8(0);
209
210 // String
211
2/2
✓ Branch 26 → 27 taken 340 times.
✓ Branch 26 → 35 taken 814 times.
1154 if (symbolType.is(TY_STRING)) {
212
3/6
✓ Branch 27 → 28 taken 340 times.
✗ Branch 27 → 135 not taken.
✓ Branch 28 → 29 taken 340 times.
✗ Branch 28 → 134 not taken.
✓ Branch 29 → 30 taken 340 times.
✗ Branch 29 → 134 not taken.
340 llvm::GlobalVariable *globalString = builder.CreateGlobalString("", "");
213
1/2
✓ Branch 30 → 31 taken 340 times.
✗ Branch 30 → 34 not taken.
340 if (cliOptions.comparableOutput)
214
2/4
✓ Branch 31 → 32 taken 340 times.
✗ Branch 31 → 136 not taken.
✓ Branch 32 → 33 taken 340 times.
✗ Branch 32 → 136 not taken.
340 globalString->setAlignment(llvm::Align(4));
215 340 return globalString;
216 }
217
218 // Bool
219
2/2
✓ Branch 36 → 37 taken 33 times.
✓ Branch 36 → 39 taken 781 times.
814 if (symbolType.is(TY_BOOL))
220 33 return builder.getFalse();
221
222 // Pointer or reference
223
3/4
✓ Branch 39 → 40 taken 781 times.
✗ Branch 39 → 137 not taken.
✓ Branch 40 → 41 taken 722 times.
✓ Branch 40 → 44 taken 59 times.
781 if (symbolType.isOneOf({TY_PTR, TY_REF}))
224 722 return llvm::Constant::getNullValue(builder.getPtrTy());
225
226 // Array
227
2/2
✓ Branch 45 → 46 taken 15 times.
✓ Branch 45 → 61 taken 44 times.
59 if (symbolType.isArray()) {
228 // Get array size
229
1/2
✓ Branch 46 → 47 taken 15 times.
✗ Branch 46 → 146 not taken.
15 const size_t arraySize = symbolType.getArraySize();
230
231 // Get default value for item
232
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());
233
234 // Retrieve array and item type
235
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);
236
1/2
✓ Branch 51 → 52 taken 15 times.
✗ Branch 51 → 146 not taken.
15 llvm::ArrayType *arrayType = llvm::ArrayType::get(itemType, arraySize);
237
238 // Create a constant array with n times the default value
239
1/2
✓ Branch 54 → 55 taken 15 times.
✗ Branch 54 → 140 not taken.
15 const std::vector itemConstants(arraySize, defaultItemValue);
240
1/2
✓ Branch 57 → 58 taken 15 times.
✗ Branch 57 → 143 not taken.
15 return llvm::ConstantArray::get(arrayType, itemConstants);
241 15 }
242
243 // Function or procedure
244
3/4
✓ Branch 61 → 62 taken 44 times.
✗ Branch 61 → 147 not taken.
✓ Branch 62 → 63 taken 14 times.
✓ Branch 62 → 75 taken 30 times.
44 if (symbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
245
2/2
✓ Branch 63 → 64 taken 7 times.
✓ Branch 63 → 69 taken 7 times.
14 if (!llvmTypes.fatPtrType)
246
3/6
✓ Branch 64 → 65 taken 7 times.
✗ Branch 64 → 148 not taken.
✓ Branch 65 → 66 taken 7 times.
✗ Branch 65 → 148 not taken.
✓ Branch 67 → 68 taken 7 times.
✗ Branch 67 → 148 not taken.
7 llvmTypes.fatPtrType = llvm::StructType::get(context, {builder.getPtrTy(), builder.getPtrTy()});
247
248
2/4
✓ Branch 69 → 70 taken 14 times.
✗ Branch 69 → 150 not taken.
✓ Branch 70 → 71 taken 14 times.
✗ Branch 70 → 150 not taken.
14 llvm::Constant *ptrDefaultValue = getDefaultValueForSymbolType(QualType(TY_PTR));
249
1/2
✓ Branch 72 → 73 taken 14 times.
✗ Branch 72 → 151 not taken.
14 return llvm::ConstantStruct::get(llvmTypes.fatPtrType, {ptrDefaultValue, ptrDefaultValue});
250 }
251
252 // Struct
253
2/2
✓ Branch 76 → 77 taken 29 times.
✓ Branch 76 → 114 taken 1 time.
30 if (symbolType.is(TY_STRUCT)) {
254 // Retrieve field count
255
1/2
✓ Branch 77 → 78 taken 29 times.
✗ Branch 77 → 158 not taken.
29 Scope *structScope = symbolType.getBodyScope();
256
1/2
✗ Branch 78 → 79 not taken.
✓ Branch 78 → 80 taken 29 times.
29 assert(structScope != nullptr);
257
1/2
✓ Branch 80 → 81 taken 29 times.
✗ Branch 80 → 158 not taken.
29 const size_t fieldCount = structScope->getFieldCount();
258
259 // Get default values for all fields of the struct
260 29 std::vector<llvm::Constant *> fieldConstants;
261
1/2
✓ Branch 81 → 82 taken 29 times.
✗ Branch 81 → 156 not taken.
29 fieldConstants.reserve(fieldCount);
262
263 // Add default value for each struct field
264
2/2
✓ Branch 107 → 83 taken 66 times.
✓ Branch 107 → 108 taken 29 times.
95 for (size_t i = 0; i < fieldCount; i++) {
265 // Get entry of the field
266
1/2
✗ Branch 83 → 84 not taken.
✓ Branch 83 → 85 taken 66 times.
66 const SymbolTableEntry *fieldEntry = structScope->lookupField(i);
267
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());
268
269 // Retrieve default field value
270 llvm::Constant *defaultFieldValue;
271
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)
272
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);
273 else
274
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());
275
276
1/2
✓ Branch 105 → 106 taken 66 times.
✗ Branch 105 → 154 not taken.
66 fieldConstants.push_back(defaultFieldValue);
277 }
278
279
1/2
✓ Branch 108 → 109 taken 29 times.
✗ Branch 108 → 156 not taken.
29 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
280
1/2
✓ Branch 110 → 111 taken 29 times.
✗ Branch 110 → 155 not taken.
29 return llvm::ConstantStruct::get(structType, fieldConstants);
281 29 }
282
283 // Interface
284
1/2
✓ Branch 115 → 116 taken 1 time.
✗ Branch 115 → 121 not taken.
1 if (symbolType.is(TY_INTERFACE)) {
285 1 const auto structType = reinterpret_cast<llvm::StructType *>(symbolType.toLLVMType(sourceFile));
286 1 return llvm::ConstantStruct::get(structType, llvm::Constant::getNullValue(builder.getPtrTy()));
287 }
288
289 throw CompilerError(INTERNAL_ERROR, "Cannot determine default value for symbol type"); // GCOV_EXCL_LINE
290 }
291
292 15274 llvm::Constant *IRGenerator::getConst(const CompileTimeValue &compileTimeValue, const QualType &type, const ASTNode *node) const {
293
2/2
✓ Branch 3 → 4 taken 383 times.
✓ Branch 3 → 9 taken 14891 times.
15274 if (type.is(TY_DOUBLE))
294
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));
295
296
2/2
✓ Branch 10 → 11 taken 3034 times.
✓ Branch 10 → 13 taken 11857 times.
14891 if (type.is(TY_INT))
297 3034 return builder.getInt32(compileTimeValue.intValue);
298
299
2/2
✓ Branch 14 → 15 taken 576 times.
✓ Branch 14 → 17 taken 11281 times.
11857 if (type.is(TY_SHORT))
300 576 return builder.getInt16(compileTimeValue.shortValue);
301
302
2/2
✓ Branch 18 → 19 taken 5606 times.
✓ Branch 18 → 21 taken 5675 times.
11281 if (type.is(TY_LONG))
303 5606 return builder.getInt64(compileTimeValue.longValue);
304
305
3/4
✓ Branch 21 → 22 taken 5675 times.
✗ Branch 21 → 57 not taken.
✓ Branch 22 → 23 taken 2247 times.
✓ Branch 22 → 25 taken 3428 times.
5675 if (type.isOneOf({TY_BYTE, TY_CHAR}))
306 2247 return builder.getInt8(compileTimeValue.charValue);
307
308
2/2
✓ Branch 26 → 27 taken 2097 times.
✓ Branch 26 → 36 taken 1331 times.
3428 if (type.is(TY_STRING)) {
309 2097 const std::string &stringValue = resourceManager.compileTimeStringValues.at(compileTimeValue.stringValueOffset);
310
2/4
✓ Branch 30 → 31 taken 2097 times.
✗ Branch 30 → 60 not taken.
✓ Branch 31 → 32 taken 2097 times.
✗ Branch 31 → 58 not taken.
6291 return createGlobalStringConst(ANON_GLOBAL_STRING_NAME, stringValue, node->codeLoc);
311 }
312
313
1/2
✓ Branch 37 → 38 taken 1331 times.
✗ Branch 37 → 40 not taken.
1331 if (type.is(TY_BOOL))
314 1331 return builder.getInt1(compileTimeValue.boolValue);
315
316 if (type.is(TY_PTR))
317 return llvm::Constant::getNullValue(builder.getPtrTy());
318
319 throw CompilerError(UNHANDLED_BRANCH, "Constant fall-through"); // GCOV_EXCL_LINE
320 }
321
322 30313 llvm::BasicBlock *IRGenerator::createBlock(const std::string &blockName /*=""*/) const {
323
2/4
✓ Branch 2 → 3 taken 30313 times.
✗ Branch 2 → 7 not taken.
✓ Branch 3 → 4 taken 30313 times.
✗ Branch 3 → 7 not taken.
30313 return llvm::BasicBlock::Create(context, blockName);
324 }
325
326 30313 void IRGenerator::switchToBlock(llvm::BasicBlock *block, llvm::Function *parentFct /*=nullptr*/) {
327
1/2
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 30313 times.
30313 assert(block->getParent() == nullptr); // Ensure that the block was not added to a function already
328 // If no parent function were passed, use the current function
329
2/2
✓ Branch 5 → 6 taken 20277 times.
✓ Branch 5 → 8 taken 10036 times.
30313 if (!parentFct)
330 20277 parentFct = builder.GetInsertBlock()->getParent();
331 // Append block to current function
332 30313 parentFct->insert(parentFct->end(), block);
333 // Set insert point to the block
334 30313 builder.SetInsertPoint(block);
335 30313 blockAlreadyTerminated = false;
336 30313 }
337
338 9480 void IRGenerator::terminateBlock(const StmtLstNode *stmtLstNode) {
339 9480 diGenerator.setSourceLocation(stmtLstNode->closingBraceCodeLoc);
340 9480 generateScopeCleanup(stmtLstNode);
341 9480 blockAlreadyTerminated = true;
342 9480 }
343
344 11585 void IRGenerator::insertJump(llvm::BasicBlock *targetBlock) {
345
2/2
✓ Branch 2 → 3 taken 3317 times.
✓ Branch 2 → 4 taken 8268 times.
11585 if (blockAlreadyTerminated)
346 3317 return;
347 8268 builder.CreateBr(targetBlock);
348 8268 blockAlreadyTerminated = true;
349 }
350
351 8370 void IRGenerator::insertCondJump(llvm::Value *condition, llvm::BasicBlock *trueBlock, llvm::BasicBlock *falseBlock,
352 Likeliness likeliness /*=UNSPECIFIED*/) {
353
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 8370 times.
8370 if (blockAlreadyTerminated)
354 return;
355 8370 llvm::BranchInst *jumpInst = builder.CreateCondBr(condition, trueBlock, falseBlock);
356 8370 blockAlreadyTerminated = true;
357
358
2/2
✓ Branch 5 → 6 taken 761 times.
✓ Branch 5 → 22 taken 7609 times.
8370 if (likeliness != UNSPECIFIED) {
359 761 const bool likely = likeliness == LIKELY;
360 761 llvm::Metadata *name = llvm::MDString::get(context, "branch_weights");
361
1/2
✓ Branch 7 → 8 taken 761 times.
✗ Branch 7 → 9 not taken.
761 llvm::Metadata *trueBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 2000 : 1));
362
1/2
✓ Branch 12 → 13 taken 761 times.
✗ Branch 12 → 14 not taken.
761 llvm::Metadata *falseBranchWeight = llvm::ConstantAsMetadata::get(builder.getInt32(likely ? 1 : 2000));
363
1/2
✓ Branch 18 → 19 taken 761 times.
✗ Branch 18 → 23 not taken.
761 const auto profMetadata = llvm::MDNode::get(context, {name, trueBranchWeight, falseBranchWeight});
364
2/4
✓ Branch 19 → 20 taken 761 times.
✗ Branch 19 → 25 not taken.
✓ Branch 20 → 21 taken 761 times.
✗ Branch 20 → 25 not taken.
761 jumpInst->setMetadata("prof", profMetadata);
365 }
366 }
367
368 10036 void IRGenerator::verifyFunction(const llvm::Function *fct, const CodeLoc &codeLoc) const {
369 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
370
3/4
✓ Branch 2 → 3 taken 10036 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 173 times.
✓ Branch 3 → 5 taken 9863 times.
10036 if (cliOptions.disableVerifier || cliOptions.generateDebugInfo)
371 173 return;
372
373 // Verify function
374 9863 std::string output;
375
1/2
✓ Branch 6 → 7 taken 9863 times.
✗ Branch 6 → 21 not taken.
9863 llvm::raw_string_ostream oss(output);
376 if (llvm::verifyFunction(*fct, &oss)) // LCOV_EXCL_LINE
377 throw CompilerError(codeLoc, INVALID_FUNCTION, output); // LCOV_EXCL_LINE
378 9863 }
379
380 892 void IRGenerator::verifyModule(const CodeLoc &codeLoc) const {
381 // Skip the verifying step if the verifier was disabled manually or debug info is emitted
382
3/4
✓ Branch 2 → 3 taken 892 times.
✗ Branch 2 → 4 not taken.
✓ Branch 3 → 4 taken 15 times.
✓ Branch 3 → 5 taken 877 times.
892 if (cliOptions.disableVerifier || cliOptions.generateDebugInfo)
383 15 return;
384
385 // Verify module
386 877 std::string output;
387
1/2
✓ Branch 6 → 7 taken 877 times.
✗ Branch 6 → 21 not taken.
877 llvm::raw_string_ostream oss(output);
388 if (llvm::verifyModule(*module, &oss)) // LCOV_EXCL_LINE
389 throw CompilerError(codeLoc, INVALID_MODULE, output); // LCOV_EXCL_LINE
390 877 }
391
392 5282 LLVMExprResult IRGenerator::doAssignment(const ASTNode *lhsNode, const ExprNode *rhsNode, const ASTNode *node) {
393 // Get entry of left side
394
2/4
✓ Branch 2 → 3 taken 5282 times.
✗ Branch 2 → 17 not taken.
✓ Branch 3 → 4 taken 5282 times.
✗ Branch 3 → 15 not taken.
5282 auto [value, constant, ptr, refPtr, entry, _] = std::any_cast<LLVMExprResult>(visit(lhsNode));
395
6/8
✓ Branch 5 → 6 taken 4522 times.
✓ Branch 5 → 10 taken 760 times.
✓ Branch 6 → 7 taken 4522 times.
✗ Branch 6 → 18 not taken.
✓ Branch 7 → 8 taken 4522 times.
✗ Branch 7 → 18 not taken.
✓ Branch 8 → 9 taken 231 times.
✓ Branch 8 → 10 taken 4291 times.
5282 llvm::Value *lhsAddress = entry != nullptr && entry->getQualType().isRef() ? refPtr : ptr;
396
1/2
✓ Branch 11 → 12 taken 5282 times.
✗ Branch 11 → 18 not taken.
10564 return doAssignment(lhsAddress, entry, rhsNode, node);
397 }
398
399 12375 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, const ExprNode *rhsNode,
400 const ASTNode *node, bool isDecl) {
401 // Get symbol type of right side
402
1/2
✓ Branch 2 → 3 taken 12375 times.
✗ Branch 2 → 13 not taken.
12375 const QualType &rhsSType = rhsNode->getEvaluatedSymbolType(manIdx);
403
2/4
✓ Branch 3 → 4 taken 12375 times.
✗ Branch 3 → 12 not taken.
✓ Branch 4 → 5 taken 12375 times.
✗ Branch 4 → 10 not taken.
12375 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
404
1/2
✓ Branch 6 → 7 taken 12375 times.
✗ Branch 6 → 13 not taken.
24750 return doAssignment(lhsAddress, lhsEntry, rhs, rhsSType, node, isDecl);
405 }
406
407 12490 LLVMExprResult IRGenerator::doAssignment(llvm::Value *lhsAddress, SymbolTableEntry *lhsEntry, LLVMExprResult &rhs,
408 const QualType &rhsSType, const ASTNode *node, bool isDecl) {
409 // Deduce some information about the assignment
410
4/4
✓ Branch 2 → 3 taken 11730 times.
✓ Branch 2 → 7 taken 760 times.
✓ Branch 5 → 6 taken 470 times.
✓ Branch 5 → 7 taken 11260 times.
12490 const bool isRefAssign = lhsEntry != nullptr && lhsEntry->getQualType().isRef();
411
8/10
✓ Branch 8 → 9 taken 12020 times.
✓ Branch 8 → 15 taken 470 times.
✓ Branch 9 → 10 taken 12020 times.
✗ Branch 9 → 179 not taken.
✓ Branch 10 → 11 taken 12020 times.
✗ Branch 10 → 179 not taken.
✓ Branch 11 → 12 taken 1334 times.
✓ Branch 11 → 15 taken 10686 times.
✓ Branch 13 → 14 taken 169 times.
✓ Branch 13 → 15 taken 1165 times.
12490 const bool needsCopy = !isRefAssign && rhsSType.removeReferenceWrapper().is(TY_STRUCT) && !rhs.isTemporary();
412
413
2/2
✓ Branch 16 → 17 taken 470 times.
✓ Branch 16 → 57 taken 12020 times.
12490 if (isRefAssign) {
414
1/2
✗ Branch 17 → 18 not taken.
✓ Branch 17 → 19 taken 470 times.
470 assert(lhsEntry != nullptr);
415
2/2
✓ Branch 19 → 20 taken 239 times.
✓ Branch 19 → 33 taken 231 times.
470 if (isDecl) { // Reference gets initially assigned
416 // Get address of right side
417 239 llvm::Value *rhsAddress = resolveAddress(rhs);
418
1/2
✗ Branch 21 → 22 not taken.
✓ Branch 21 → 23 taken 239 times.
239 assert(rhsAddress != nullptr);
419
420 // Store lhs pointer to rhs
421
2/4
✓ Branch 26 → 27 taken 239 times.
✗ Branch 26 → 180 not taken.
✓ Branch 27 → 28 taken 239 times.
✗ Branch 27 → 180 not taken.
239 llvm::Value *refAddress = insertAlloca(builder.getPtrTy());
422 239 lhsEntry->updateAddress(refAddress);
423 239 insertStore(rhsAddress, refAddress);
424
425 239 return LLVMExprResult{.value = rhsAddress, .ptr = refAddress, .entry = lhsEntry};
426 }
427
428 // Reference to reference assignment (only for struct fields that are not initialized yet)
429 // These are only allowed inside a ctor body. In other cases, the value of the reference gets assigned, not the ref itself.
430
6/8
✓ Branch 33 → 34 taken 159 times.
✓ Branch 33 → 40 taken 72 times.
✓ Branch 35 → 36 taken 159 times.
✗ Branch 35 → 40 not taken.
✓ Branch 36 → 37 taken 153 times.
✓ Branch 36 → 40 taken 6 times.
✓ Branch 38 → 39 taken 153 times.
✗ Branch 38 → 40 not taken.
231 const bool isInitialFieldRefAssign = isInCtorBody && rhsSType.isRef() && rhs.entry && lhsEntry->isField();
431 // Assigning the result variable
432 231 const bool isReturnValAssign = lhsEntry->name == RETURN_VARIABLE_NAME;
433
4/4
✓ Branch 42 → 43 taken 78 times.
✓ Branch 42 → 44 taken 153 times.
✓ Branch 43 → 44 taken 2 times.
✓ Branch 43 → 49 taken 76 times.
231 if (isInitialFieldRefAssign || isReturnValAssign) {
434 // Get address of right side
435 155 llvm::Value *referencedAddress = resolveAddress(rhs);
436
1/2
✗ Branch 45 → 46 not taken.
✓ Branch 45 → 47 taken 155 times.
155 assert(referencedAddress != nullptr);
437
438 // Store the rhs* to the lhs**
439 155 insertStore(referencedAddress, lhsAddress);
440
441 155 return LLVMExprResult{.value = referencedAddress, .ptr = lhsAddress, .entry = lhsEntry};
442 }
443
444 // Load referenced address
445
3/6
✓ Branch 51 → 52 taken 76 times.
✗ Branch 51 → 188 not taken.
✓ Branch 52 → 53 taken 76 times.
✗ Branch 52 → 186 not taken.
✓ Branch 53 → 54 taken 76 times.
✗ Branch 53 → 186 not taken.
152 lhsAddress = insertLoad(builder.getPtrTy(), lhsAddress);
446 }
447
448 // Check if we need to copy the rhs to the lhs. This happens for structs
449
2/2
✓ Branch 57 → 58 taken 169 times.
✓ Branch 57 → 124 taken 11927 times.
12096 if (needsCopy) {
450 // Get address of right side
451
1/2
✓ Branch 58 → 59 taken 169 times.
✗ Branch 58 → 239 not taken.
169 llvm::Value *rhsAddress = resolveAddress(rhs);
452
1/2
✗ Branch 59 → 60 not taken.
✓ Branch 59 → 61 taken 169 times.
169 assert(rhsAddress != nullptr);
453
454 // Allocate new memory if the lhs address does not exist
455
2/2
✓ Branch 61 → 62 taken 4 times.
✓ Branch 61 → 73 taken 165 times.
169 if (!lhsAddress) {
456
1/2
✗ Branch 62 → 63 not taken.
✓ Branch 62 → 64 taken 4 times.
4 assert(lhsEntry != nullptr);
457
3/6
✓ Branch 67 → 68 taken 4 times.
✗ Branch 67 → 192 not taken.
✓ Branch 68 → 69 taken 4 times.
✗ Branch 68 → 192 not taken.
✓ Branch 69 → 70 taken 4 times.
✗ Branch 69 → 192 not taken.
4 lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile));
458
1/2
✓ Branch 72 → 73 taken 4 times.
✗ Branch 72 → 239 not taken.
4 lhsEntry->updateAddress(lhsAddress);
459 }
460
461 // Check if we have a copy ctor
462
2/4
✓ Branch 73 → 74 taken 169 times.
✗ Branch 73 → 198 not taken.
✓ Branch 74 → 75 taken 169 times.
✗ Branch 74 → 198 not taken.
169 const QualType rhsSTypeNonRef = rhsSType.removeReferenceWrapper().toNonConst();
463
1/2
✓ Branch 75 → 76 taken 169 times.
✗ Branch 75 → 239 not taken.
169 Scope *structScope = rhsSTypeNonRef.getBodyScope();
464
2/4
✓ Branch 76 → 77 taken 169 times.
✗ Branch 76 → 203 not taken.
✓ Branch 81 → 82 taken 169 times.
✗ Branch 81 → 199 not taken.
507 const ArgList args = {{rhsSTypeNonRef.toConstRef(node), rhs.isTemporary()}};
465
2/4
✓ Branch 85 → 86 taken 169 times.
✗ Branch 85 → 207 not taken.
✓ Branch 86 → 87 taken 169 times.
✗ Branch 86 → 205 not taken.
169 const Function *copyCtor = FunctionManager::lookup(structScope, CTOR_FUNCTION_NAME, rhsSTypeNonRef, args, true);
466
2/2
✓ Branch 89 → 90 taken 73 times.
✓ Branch 89 → 97 taken 96 times.
169 if (copyCtor != nullptr) {
467 // Call copy ctor
468
2/4
✓ Branch 92 → 93 taken 73 times.
✗ Branch 92 → 213 not taken.
✓ Branch 93 → 94 taken 73 times.
✗ Branch 93 → 211 not taken.
219 generateCtorOrDtorCall(lhsAddress, copyCtor, {rhsAddress});
469
2/4
✓ Branch 97 → 98 taken 96 times.
✗ Branch 97 → 237 not taken.
✓ Branch 98 → 99 taken 96 times.
✗ Branch 98 → 115 not taken.
96 } else if (rhsSTypeNonRef.isTriviallyCopyable(node)) {
470 // Create shallow copy
471
1/2
✓ Branch 99 → 100 taken 96 times.
✗ Branch 99 → 225 not taken.
96 llvm::Type *rhsType = rhsSTypeNonRef.toLLVMType(sourceFile);
472
6/10
✓ Branch 100 → 101 taken 91 times.
✓ Branch 100 → 102 taken 5 times.
✓ Branch 101 → 105 taken 91 times.
✗ Branch 101 → 218 not taken.
✓ Branch 104 → 105 taken 5 times.
✗ Branch 104 → 218 not taken.
✓ Branch 105 → 106 taken 5 times.
✓ Branch 105 → 108 taken 91 times.
✗ Branch 218 → 219 not taken.
✗ Branch 218 → 221 not taken.
101 const std::string copyName = lhsEntry ? lhsEntry->name : "";
473
4/6
✓ Branch 108 → 109 taken 91 times.
✓ Branch 108 → 111 taken 5 times.
✗ Branch 109 → 110 not taken.
✓ Branch 109 → 111 taken 91 times.
✓ Branch 112 → 113 taken 96 times.
✗ Branch 112 → 223 not taken.
96 generateShallowCopy(rhsAddress, rhsType, lhsAddress, lhsEntry && lhsEntry->isVolatile);
474 96 } else {
475 const std::string structName = rhsSTypeNonRef.getName();
476 const std::string msg = "Cannot copy struct '" + structName + "', as it is not trivially copyable and has no copy ctor";
477 throw SemanticError(node, COPY_CTOR_REQUIRED, msg);
478 }
479 169 return LLVMExprResult{.ptr = lhsAddress, .entry = lhsEntry};
480 169 }
481
482
7/8
✓ Branch 124 → 125 taken 6965 times.
✓ Branch 124 → 130 taken 4962 times.
✓ Branch 126 → 127 taken 868 times.
✓ Branch 126 → 130 taken 6097 times.
✓ Branch 128 → 129 taken 868 times.
✗ Branch 128 → 130 not taken.
✓ Branch 131 → 132 taken 868 times.
✓ Branch 131 → 137 taken 11059 times.
11927 if (isDecl && rhsSType.is(TY_STRUCT) && rhs.isTemporary()) {
483
1/2
✗ Branch 132 → 133 not taken.
✓ Branch 132 → 134 taken 868 times.
868 assert(lhsEntry != nullptr);
484 // Directly set the address to the lhs entry (temp stealing)
485 868 llvm::Value *rhsAddress = resolveAddress(rhs);
486 868 lhsEntry->updateAddress(rhsAddress);
487 868 rhs.entry = lhsEntry;
488 868 return rhs;
489 }
490
491 // Allocate new memory if the lhs address does not exist
492
2/2
✓ Branch 137 → 138 taken 6066 times.
✓ Branch 137 → 149 taken 4993 times.
11059 if (!lhsAddress) {
493
1/2
✗ Branch 138 → 139 not taken.
✓ Branch 138 → 140 taken 6066 times.
6066 assert(lhsEntry != nullptr);
494
3/6
✓ Branch 143 → 144 taken 6066 times.
✗ Branch 143 → 240 not taken.
✓ Branch 144 → 145 taken 6066 times.
✗ Branch 144 → 240 not taken.
✓ Branch 145 → 146 taken 6066 times.
✗ Branch 145 → 240 not taken.
6066 lhsAddress = insertAlloca(lhsEntry->getQualType().toLLVMType(sourceFile));
495 6066 lhsEntry->updateAddress(lhsAddress);
496 }
497
498 // 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
499
10/10
✓ Branch 149 → 150 taken 10319 times.
✓ Branch 149 → 158 taken 740 times.
✓ Branch 152 → 153 taken 2092 times.
✓ Branch 152 → 158 taken 8227 times.
✓ Branch 154 → 155 taken 5 times.
✓ Branch 154 → 158 taken 2087 times.
✓ Branch 156 → 157 taken 1 time.
✓ Branch 156 → 158 taken 4 times.
✓ Branch 159 → 160 taken 1 time.
✓ Branch 159 → 175 taken 11058 times.
11059 if (lhsEntry && lhsEntry->getQualType().isPtr() && rhsSType.isArray() && rhsSType.getArraySize() != ARRAY_SIZE_UNKNOWN) {
500 // Get address of right side
501
1/2
✓ Branch 160 → 161 taken 1 time.
✗ Branch 160 → 253 not taken.
1 llvm::Value *rhsAddress = resolveAddress(rhs);
502
1/2
✗ Branch 161 → 162 not taken.
✓ Branch 161 → 163 taken 1 time.
1 assert(rhsAddress != nullptr);
503
1/2
✓ Branch 163 → 164 taken 1 time.
✗ Branch 163 → 253 not taken.
1 llvm::Type *elementTy = rhsSType.toLLVMType(sourceFile);
504
2/4
✓ Branch 164 → 165 taken 1 time.
✗ Branch 164 → 253 not taken.
✓ Branch 165 → 166 taken 1 time.
✗ Branch 165 → 253 not taken.
1 llvm::Value *indices[2] = {builder.getInt64(0), builder.getInt32(0)};
505
1/2
✓ Branch 170 → 171 taken 1 time.
✗ Branch 170 → 246 not taken.
1 llvm::Value *firstItemAddress = insertInBoundsGEP(elementTy, rhsAddress, indices);
506
1/2
✓ Branch 173 → 174 taken 1 time.
✗ Branch 173 → 253 not taken.
1 insertStore(firstItemAddress, lhsAddress);
507 1 return LLVMExprResult{.value = rhsAddress, .ptr = lhsAddress, .entry = lhsEntry};
508 }
509
510 // We can load the value from the right side and store it to the left side
511 // Retrieve value of the right side
512 11058 llvm::Value *rhsValue = resolveValue(rhsSType, rhs);
513 // Store the value to the address
514 11058 insertStore(rhsValue, lhsAddress);
515 11058 return LLVMExprResult{.value = rhsValue, .ptr = lhsAddress, .entry = lhsEntry};
516 }
517
518 133 void IRGenerator::generateShallowCopy(llvm::Value *oldAddress, llvm::Type *varType, llvm::Value *targetAddress,
519 bool isVolatile) const {
520 // Retrieve size to copy
521
1/2
✓ Branch 3 → 4 taken 133 times.
✗ Branch 3 → 19 not taken.
133 const llvm::TypeSize typeSize = module->getDataLayout().getTypeAllocSize(varType);
522
523 // Create values for memcpy intrinsic
524
2/4
✓ Branch 4 → 5 taken 133 times.
✗ Branch 4 → 19 not taken.
✓ Branch 5 → 6 taken 133 times.
✗ Branch 5 → 19 not taken.
133 llvm::Value *structSize = builder.getInt64(typeSize);
525
1/2
✓ Branch 6 → 7 taken 133 times.
✗ Branch 6 → 19 not taken.
133 llvm::Value *copyVolatile = builder.getInt1(isVolatile);
526
527 // Call memcpy intrinsic to execute the shallow copy
528
1/2
✓ Branch 7 → 8 taken 133 times.
✗ Branch 7 → 19 not taken.
133 llvm::Function *memcpyFct = stdFunctionManager.getMemcpyIntrinsic();
529
1/2
✗ Branch 8 → 9 not taken.
✓ Branch 8 → 10 taken 133 times.
133 assert(targetAddress != nullptr);
530
3/6
✓ Branch 10 → 11 taken 133 times.
✗ Branch 10 → 18 not taken.
✓ Branch 12 → 13 taken 133 times.
✗ Branch 12 → 15 not taken.
✓ Branch 13 → 14 taken 133 times.
✗ Branch 13 → 15 not taken.
133 builder.CreateCall(memcpyFct, {targetAddress, oldAddress, structSize, copyVolatile});
531 133 }
532
533 21456 void IRGenerator::autoDeReferencePtr(llvm::Value *&ptr, QualType &symbolType) const {
534
6/6
✓ Branch 13 → 14 taken 22320 times.
✓ Branch 13 → 16 taken 16007 times.
✓ Branch 15 → 16 taken 864 times.
✓ Branch 15 → 17 taken 21456 times.
✓ Branch 18 → 3 taken 16871 times.
✓ Branch 18 → 19 taken 21456 times.
38327 while (symbolType.isPtr() || symbolType.isRef()) {
535
3/6
✓ Branch 5 → 6 taken 16871 times.
✗ Branch 5 → 22 not taken.
✓ Branch 6 → 7 taken 16871 times.
✗ Branch 6 → 20 not taken.
✓ Branch 7 → 8 taken 16871 times.
✗ Branch 7 → 20 not taken.
16871 ptr = insertLoad(symbolType.toLLVMType(sourceFile), ptr);
536
1/2
✓ Branch 10 → 11 taken 16871 times.
✗ Branch 10 → 26 not taken.
16871 symbolType = symbolType.getContained();
537 }
538 21456 }
539
540 52 llvm::GlobalVariable *IRGenerator::createGlobalConst(const std::string &baseName, llvm::Constant *constant) const {
541 // Get unused name
542
1/2
✓ Branch 2 → 3 taken 52 times.
✗ Branch 2 → 19 not taken.
52 const std::string globalName = getUnusedGlobalName(baseName);
543 // Create global
544
1/2
✓ Branch 5 → 6 taken 52 times.
✗ Branch 5 → 15 not taken.
52 module->getOrInsertGlobal(globalName, constant->getType());
545
1/2
✓ Branch 7 → 8 taken 52 times.
✗ Branch 7 → 16 not taken.
52 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
546 // Set initializer to the given constant
547
1/2
✓ Branch 8 → 9 taken 52 times.
✗ Branch 8 → 17 not taken.
52 global->setInitializer(constant);
548 52 global->setConstant(true);
549
1/2
✓ Branch 10 → 11 taken 52 times.
✗ Branch 10 → 17 not taken.
52 global->setLinkage(llvm::GlobalValue::PrivateLinkage);
550 52 global->setUnnamedAddr(llvm::GlobalValue::UnnamedAddr::Global);
551 52 return global;
552 52 }
553
554 2851 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value) const {
555 // Get unused name
556
1/2
✓ Branch 2 → 3 taken 2851 times.
✗ Branch 2 → 21 not taken.
2851 const std::string globalName = getUnusedGlobalName(baseName);
557 // Create global
558
2/4
✓ Branch 3 → 4 taken 2851 times.
✗ Branch 3 → 16 not taken.
✓ Branch 5 → 6 taken 2851 times.
✗ Branch 5 → 15 not taken.
2851 builder.CreateGlobalString(value, globalName, 0, module);
559
1/2
✓ Branch 7 → 8 taken 2851 times.
✗ Branch 7 → 17 not taken.
2851 llvm::GlobalVariable *global = module->getNamedGlobal(globalName);
560 // If the output should be comparable, fix alignment to 4 bytes
561
1/2
✓ Branch 8 → 9 taken 2851 times.
✗ Branch 8 → 12 not taken.
2851 if (cliOptions.comparableOutput)
562
2/4
✓ Branch 9 → 10 taken 2851 times.
✗ Branch 9 → 18 not taken.
✓ Branch 10 → 11 taken 2851 times.
✗ Branch 10 → 18 not taken.
2851 global->setAlignment(llvm::Align(4));
563 2851 return global;
564 2851 }
565
566 2851 llvm::GlobalVariable *IRGenerator::createGlobalStringConst(const std::string &baseName, const std::string &value,
567 const CodeLoc &codeLoc) const {
568 2851 llvm::GlobalVariable *global = createGlobalStringConst(baseName, value);
569 // Create debug info
570
2/2
✓ Branch 3 → 4 taken 33 times.
✓ Branch 3 → 10 taken 2818 times.
2851 if (cliOptions.generateDebugInfo)
571
3/6
✓ Branch 5 → 6 taken 33 times.
✗ Branch 5 → 14 not taken.
✓ Branch 6 → 7 taken 33 times.
✗ Branch 6 → 14 not taken.
✓ Branch 7 → 8 taken 33 times.
✗ Branch 7 → 12 not taken.
33 diGenerator.generateGlobalStringDebugInfo(global, global->getName().str(), value.length(), codeLoc);
572 2851 return global;
573 }
574
575 4310 std::string IRGenerator::getUnusedGlobalName(const std::string &baseName) const {
576 // Find an unused global name
577 4310 std::string globalName;
578 4310 unsigned int suffixNumber = 0;
579 do {
580
1/2
✓ Branch 5 → 6 taken 48749 times.
✗ Branch 5 → 15 not taken.
48749 globalName = baseName + std::to_string(suffixNumber);
581 48749 suffixNumber++;
582
3/4
✓ Branch 10 → 11 taken 48749 times.
✗ Branch 10 → 19 not taken.
✓ Branch 11 → 12 taken 44439 times.
✓ Branch 11 → 13 taken 4310 times.
48749 } while (module->getNamedGlobal(globalName) != nullptr);
583 4310 return globalName;
584 }
585
586 15817 void IRGenerator::materializeConstant(LLVMExprResult &exprResult) {
587 // Skip results, that do not contain a constant or already have a value
588
3/4
✓ Branch 2 → 3 taken 15443 times.
✓ Branch 2 → 4 taken 374 times.
✗ Branch 3 → 4 not taken.
✓ Branch 3 → 5 taken 15443 times.
15817 if (exprResult.value != nullptr || exprResult.constant == nullptr)
589 374 return;
590
591 // Default case: the value to the constant
592 15443 exprResult.value = exprResult.constant;
593 }
594
595 924 std::string IRGenerator::getIRString(llvm::Module *llvmModule, bool comparableOutput) {
596
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 4 taken 924 times.
924 assert(llvmModule != nullptr); // Make sure the module hasn't been moved away
597
598 // Backup target triple and data layout
599 924 const llvm::Triple &targetTriple = llvmModule->getTargetTriple();
600
1/2
✓ Branch 6 → 7 taken 924 times.
✗ Branch 6 → 37 not taken.
924 const std::string targetDataLayout = llvmModule->getDataLayoutStr();
601 // Remove target triple and data layout
602
1/2
✓ Branch 7 → 8 taken 924 times.
✗ Branch 7 → 14 not taken.
924 if (comparableOutput) {
603 924 llvmModule->setTargetTriple(llvm::Triple());
604
2/4
✓ Branch 11 → 12 taken 924 times.
✗ Branch 11 → 28 not taken.
✓ Branch 12 → 13 taken 924 times.
✗ Branch 12 → 28 not taken.
924 llvmModule->setDataLayout("");
605 }
606
607 // Get IR string
608 924 std::string output;
609
1/2
✓ Branch 15 → 16 taken 924 times.
✗ Branch 15 → 33 not taken.
924 llvm::raw_string_ostream oss(output);
610
1/2
✓ Branch 16 → 17 taken 924 times.
✗ Branch 16 → 31 not taken.
924 llvmModule->print(oss, nullptr);
611
612 // Restore target triple and data layout
613
1/2
✓ Branch 17 → 18 taken 924 times.
✗ Branch 17 → 24 not taken.
924 if (comparableOutput) {
614
1/2
✓ Branch 18 → 19 taken 924 times.
✗ Branch 18 → 29 not taken.
924 llvmModule->setTargetTriple(targetTriple);
615
1/2
✓ Branch 22 → 23 taken 924 times.
✗ Branch 22 → 30 not taken.
924 llvmModule->setDataLayout(targetDataLayout);
616 }
617
618 924 return output;
619 924 }
620
621 /**
622 * Returns the operator function list for the current manifestation and the given node
623 *
624 * @param node Node to retrieve the op fct pointer list from
625 * @return Op fct pointer list
626 */
627 17388 const std::vector<const Function *> &IRGenerator::getOpFctPointers(const ASTNode *node) const {
628
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 17388 times.
17388 assert(node->getOpFctPointers()->size() > manIdx);
629 17388 return node->getOpFctPointers()->at(manIdx);
630 }
631
632 } // namespace spice::compiler
633