GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenStatements.cpp
Date: 2025-10-09 06:28:01
Coverage Exec Excl Total
Lines: 92.9% 104 0 112
Functions: 75.0% 9 0 12
Branches: 54.1% 106 0 196

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
7 #include <ast/ASTNodes.h>
8 #include <driver/Driver.h>
9 #include <symboltablebuilder/SymbolTableBuilder.h>
10
11 namespace spice::compiler {
12
13 18018 std::any IRGenerator::visitStmtLst(const StmtLstNode *node) {
14 // Generate instructions in the scope
15
2/2
✓ Branch 14 → 4 taken 34334 times.
✓ Branch 14 → 15 taken 18012 times.
52346 for (const StmtNode *stmt : node->statements) {
16
1/2
✗ Branch 5 → 6 not taken.
✓ Branch 5 → 7 taken 34334 times.
34334 if (!stmt)
17 continue;
18 // Check if we can cancel generating instructions for this code branch
19
4/4
✓ Branch 7 → 8 taken 34333 times.
✓ Branch 7 → 15 taken 1 time.
✓ Branch 8 → 9 taken 34328 times.
✓ Branch 8 → 15 taken 5 times.
34334 if (blockAlreadyTerminated || stmt->unreachable)
20 break;
21 // Visit child
22
1/2
✓ Branch 9 → 10 taken 34328 times.
✗ Branch 9 → 21 not taken.
34328 visit(stmt);
23 }
24
25 // Generate cleanup code of this scope, e.g. dtor calls for struct instances
26 18018 diGenerator.setSourceLocation(node->getNextOuterStmtLst()->closingBraceCodeLoc);
27 18018 generateScopeCleanup(node);
28
29
1/2
✓ Branch 18 → 19 taken 18018 times.
✗ Branch 18 → 23 not taken.
18018 return nullptr;
30 }
31
32 std::any IRGenerator::visitTypeAltsLst(const TypeAltsLstNode *node) {
33 return nullptr; // Noop
34 }
35
36 7440 std::any IRGenerator::visitDeclStmt(const DeclStmtNode *node) {
37
1/2
✓ Branch 2 → 3 taken 7440 times.
✗ Branch 2 → 88 not taken.
7440 diGenerator.setSourceLocation(node);
38
39 // Get variable entry
40
1/2
✓ Branch 3 → 4 taken 7440 times.
✗ Branch 3 → 88 not taken.
7440 SymbolTableEntry *varEntry = node->entries.at(manIdx);
41
1/2
✗ Branch 4 → 5 not taken.
✓ Branch 4 → 6 taken 7440 times.
7440 assert(varEntry != nullptr);
42
1/2
✓ Branch 6 → 7 taken 7440 times.
✗ Branch 6 → 88 not taken.
7440 const QualType varSymbolType = varEntry->getQualType();
43
44 // Get LLVM type of variable
45
1/2
✓ Branch 7 → 8 taken 7440 times.
✗ Branch 7 → 88 not taken.
7440 llvm::Type *varTy = varSymbolType.toLLVMType(sourceFile);
46
47 // Check if the declaration is with an assignment or the default value
48 7440 llvm::Value *varAddress = nullptr;
49
2/2
✓ Branch 8 → 9 taken 7102 times.
✓ Branch 8 → 33 taken 338 times.
7440 if (node->hasAssignment) { // Assignment
50
2/2
✓ Branch 9 → 10 taken 9 times.
✓ Branch 9 → 27 taken 7093 times.
7102 if (node->calledCopyCtor) {
51 // Allocate memory
52
1/2
✓ Branch 13 → 14 taken 9 times.
✗ Branch 13 → 63 not taken.
9 varAddress = insertAlloca(varTy);
53
1/2
✓ Branch 16 → 17 taken 9 times.
✗ Branch 16 → 88 not taken.
9 varEntry->updateAddress(varAddress);
54 // Call copy ctor
55
1/2
✓ Branch 17 → 18 taken 9 times.
✗ Branch 17 → 88 not taken.
9 llvm::Value *rhsAddress = resolveAddress(node->assignExpr);
56
1/2
✗ Branch 18 → 19 not taken.
✓ Branch 18 → 20 taken 9 times.
9 assert(rhsAddress != nullptr);
57
2/4
✓ Branch 22 → 23 taken 9 times.
✗ Branch 22 → 71 not taken.
✓ Branch 23 → 24 taken 9 times.
✗ Branch 23 → 69 not taken.
27 generateCtorOrDtorCall(varEntry, node->calledCopyCtor, {rhsAddress});
58 } else {
59 // Assign rhs to lhs
60
1/2
✓ Branch 27 → 28 taken 7093 times.
✗ Branch 27 → 76 not taken.
7093 [[maybe_unused]] const LLVMExprResult assignResult = doAssignment(varAddress, varEntry, node->assignExpr, node, true);
61
1/2
✗ Branch 28 → 29 not taken.
✓ Branch 28 → 30 taken 7093 times.
7093 assert(assignResult.entry == varEntry);
62
1/2
✓ Branch 30 → 31 taken 7093 times.
✗ Branch 30 → 76 not taken.
7093 varAddress = varEntry->getAddress();
63
1/2
✓ Branch 31 → 32 taken 7093 times.
✗ Branch 31 → 76 not taken.
7093 varEntry->updateAddress(varAddress);
64 }
65 } else { // Default value
66 // Allocate memory
67
1/2
✓ Branch 36 → 37 taken 338 times.
✗ Branch 36 → 77 not taken.
338 varAddress = insertAlloca(varTy);
68
1/2
✓ Branch 39 → 40 taken 338 times.
✗ Branch 39 → 88 not taken.
338 varEntry->updateAddress(varAddress);
69
70
2/2
✓ Branch 40 → 41 taken 145 times.
✓ Branch 40 → 45 taken 193 times.
338 if (node->calledInitCtor) {
71 // Call no-args constructor
72
1/2
✓ Branch 42 → 43 taken 145 times.
✗ Branch 42 → 83 not taken.
145 generateCtorOrDtorCall(varEntry, node->calledInitCtor, {});
73
3/4
✓ Branch 45 → 46 taken 83 times.
✓ Branch 45 → 54 taken 110 times.
✓ Branch 46 → 47 taken 83 times.
✗ Branch 46 → 54 not taken.
193 } else if (!node->isForEachItem && cliOptions.buildMode != RELEASE) {
74
1/2
✗ Branch 47 → 48 not taken.
✓ Branch 47 → 49 taken 83 times.
83 assert(!node->isCtorCallRequired);
75
1/4
✗ Branch 49 → 50 not taken.
✓ Branch 49 → 52 taken 83 times.
✗ Branch 50 → 51 not taken.
✗ Branch 50 → 52 not taken.
83 assert(cliOptions.buildMode == DEBUG || cliOptions.buildMode == TEST);
76 // Retrieve default value for lhs symbol type and store it
77
1/2
✓ Branch 52 → 53 taken 83 times.
✗ Branch 52 → 88 not taken.
83 llvm::Constant *defaultValue = getDefaultValueForSymbolType(varSymbolType);
78
1/2
✓ Branch 53 → 54 taken 83 times.
✗ Branch 53 → 88 not taken.
83 insertStore(defaultValue, varAddress);
79 }
80 }
81
1/2
✗ Branch 54 → 55 not taken.
✓ Branch 54 → 56 taken 7440 times.
7440 assert(varAddress != nullptr);
82
83 // Attach the variable name to the LLVM value.
84
2/4
✓ Branch 56 → 57 taken 7440 times.
✗ Branch 56 → 86 not taken.
✓ Branch 57 → 58 taken 7440 times.
✗ Branch 57 → 86 not taken.
7440 varAddress->setName(varEntry->name);
85
86 // Generate debug info for variable declaration
87
1/2
✓ Branch 58 → 59 taken 7440 times.
✗ Branch 58 → 88 not taken.
7440 diGenerator.setSourceLocation(node);
88
1/2
✓ Branch 59 → 60 taken 7440 times.
✗ Branch 59 → 88 not taken.
7440 diGenerator.generateLocalVarDebugInfo(node->varName, varAddress);
89
90
1/2
✓ Branch 60 → 61 taken 7440 times.
✗ Branch 60 → 87 not taken.
7440 return nullptr;
91 }
92
93 std::any IRGenerator::visitQualifierLst(const QualifierLstNode *node) {
94 return nullptr; // Noop
95 }
96
97 296 std::any IRGenerator::visitModAttr(const ModAttrNode *node) {
98
1/2
✓ Branch 2 → 3 taken 296 times.
✗ Branch 2 → 5 not taken.
296 return nullptr; // Noop
99 }
100
101 std::any IRGenerator::visitTopLevelDefinitionAttr(const TopLevelDefinitionAttrNode *node) {
102 return nullptr; // Noop
103 }
104
105 66 std::any IRGenerator::visitCaseConstant(const CaseConstantNode *node) {
106
2/2
✓ Branch 2 → 3 taken 15 times.
✓ Branch 2 → 4 taken 51 times.
66 if (node->constant)
107 15 return visit(node->constant);
108
109 51 const SymbolTableEntry *constantEntry = node->entry;
110
4/8
✓ Branch 4 → 5 taken 51 times.
✗ Branch 4 → 12 not taken.
✓ Branch 5 → 6 taken 51 times.
✗ Branch 5 → 11 not taken.
✓ Branch 6 → 7 taken 51 times.
✗ Branch 6 → 11 not taken.
✓ Branch 7 → 8 taken 51 times.
✗ Branch 7 → 11 not taken.
51 return getConst(constantEntry->declNode->getCompileTimeValue(), node->getEvaluatedSymbolType(manIdx), node);
111 }
112
113 8834 std::any IRGenerator::visitReturnStmt(const ReturnStmtNode *node) {
114 8834 diGenerator.setSourceLocation(node);
115
116 8834 llvm::Value *returnValue = nullptr;
117
2/2
✓ Branch 3 → 4 taken 8769 times.
✓ Branch 3 → 33 taken 65 times.
8834 if (node->hasReturnValue) { // Return value is attached to the return statement
118 8769 const AssignExprNode *returnExpr = node->assignExpr;
119
2/2
✓ Branch 4 → 5 taken 3 times.
✓ Branch 4 → 26 taken 8766 times.
8769 if (node->calledCopyCtor) {
120 // Perform a copy
121 3 llvm::Value *originalAddress = resolveAddress(returnExpr);
122 3 llvm::Type *returnTy = node->returnType.toLLVMType(sourceFile);
123
1/2
✓ Branch 10 → 11 taken 3 times.
✗ Branch 10 → 60 not taken.
3 llvm::Value *newAddress = insertAlloca(returnTy);
124
2/4
✓ Branch 15 → 16 taken 3 times.
✗ Branch 15 → 68 not taken.
✓ Branch 16 → 17 taken 3 times.
✗ Branch 16 → 66 not taken.
9 generateCtorOrDtorCall(newAddress, node->calledCopyCtor, {originalAddress});
125
2/4
✓ Branch 21 → 22 taken 3 times.
✗ Branch 21 → 75 not taken.
✓ Branch 22 → 23 taken 3 times.
✗ Branch 22 → 73 not taken.
6 returnValue = insertLoad(returnTy, newAddress);
126 } else {
127
2/2
✓ Branch 27 → 28 taken 473 times.
✓ Branch 27 → 30 taken 8293 times.
8766 returnValue = node->returnType.isRef() ? resolveAddress(returnExpr) : resolveValue(returnExpr);
128 }
129 } else { // Try to load result variable value
130
1/2
✓ Branch 35 → 36 taken 65 times.
✗ Branch 35 → 81 not taken.
195 const SymbolTableEntry *resultEntry = currentScope->lookup(RETURN_VARIABLE_NAME);
131
2/2
✓ Branch 41 → 42 taken 4 times.
✓ Branch 41 → 52 taken 61 times.
65 if (resultEntry != nullptr) {
132 4 llvm::Type *resultSTy = resultEntry->getQualType().toLLVMType(sourceFile);
133 4 llvm::Value *returnValueAddr = resultEntry->getAddress();
134
2/4
✓ Branch 47 → 48 taken 4 times.
✗ Branch 47 → 87 not taken.
✓ Branch 48 → 49 taken 4 times.
✗ Branch 48 → 85 not taken.
8 returnValue = insertLoad(resultSTy, returnValueAddr);
135 }
136 }
137
138 // Terminate the block (with scope cleanup)
139 8834 terminateBlock(node->getParentScopeNode());
140
141 // Create return instruction
142
2/2
✓ Branch 54 → 55 taken 8773 times.
✓ Branch 54 → 56 taken 61 times.
8834 if (returnValue != nullptr) {
143 // Return with value
144 8773 builder.CreateRet(returnValue);
145 } else {
146 // Return without value
147 61 builder.CreateRetVoid();
148 }
149
150
1/2
✓ Branch 57 → 58 taken 8834 times.
✗ Branch 57 → 91 not taken.
8834 return nullptr;
151 }
152
153 102 std::any IRGenerator::visitBreakStmt(const BreakStmtNode *node) {
154 102 diGenerator.setSourceLocation(node);
155
156 // Jump to destination block
157 102 const size_t blockIdx = breakBlocks.size() - node->breakTimes;
158 102 insertJump(breakBlocks.at(blockIdx));
159
160
1/2
✓ Branch 6 → 7 taken 102 times.
✗ Branch 6 → 9 not taken.
102 return nullptr;
161 }
162
163 341 std::any IRGenerator::visitContinueStmt(const ContinueStmtNode *node) {
164 341 diGenerator.setSourceLocation(node);
165
166 // Jump to destination block
167 341 const size_t blockIdx = continueBlocks.size() - node->continueTimes;
168 341 insertJump(continueBlocks.at(blockIdx));
169
170
1/2
✓ Branch 6 → 7 taken 341 times.
✗ Branch 6 → 9 not taken.
341 return nullptr;
171 }
172
173 4 std::any IRGenerator::visitFallthroughStmt(const FallthroughStmtNode *node) {
174 4 diGenerator.setSourceLocation(node);
175
176 // Jump to destination block
177 4 insertJump(fallthroughBlocks.top());
178
179
1/2
✓ Branch 5 → 6 taken 4 times.
✗ Branch 5 → 8 not taken.
4 return nullptr;
180 }
181
182 761 std::any IRGenerator::visitAssertStmt(const AssertStmtNode *node) {
183 // Do not generate assertions in release mode
184
1/2
✗ Branch 2 → 3 not taken.
✓ Branch 2 → 5 taken 761 times.
761 if (cliOptions.buildMode == RELEASE)
185 return nullptr;
186
187
1/2
✓ Branch 5 → 6 taken 761 times.
✗ Branch 5 → 86 not taken.
761 diGenerator.setSourceLocation(node);
188
189 // Create blocks
190
1/2
✓ Branch 6 → 7 taken 761 times.
✗ Branch 6 → 86 not taken.
761 const std::string &codeLine = node->codeLoc.toPrettyLine();
191
2/4
✓ Branch 7 → 8 taken 761 times.
✗ Branch 7 → 54 not taken.
✓ Branch 8 → 9 taken 761 times.
✗ Branch 8 → 52 not taken.
761 llvm::BasicBlock *bThen = createBlock("assert.then." + codeLine);
192
2/4
✓ Branch 10 → 11 taken 761 times.
✗ Branch 10 → 57 not taken.
✓ Branch 11 → 12 taken 761 times.
✗ Branch 11 → 55 not taken.
761 llvm::BasicBlock *bExit = createBlock("assert.exit." + codeLine);
193
194 // Visit the assignExpr
195
1/2
✓ Branch 13 → 14 taken 761 times.
✗ Branch 13 → 84 not taken.
761 llvm::Value *condValue = resolveValue(node->assignExpr);
196
197 // Create condition check
198
1/2
✓ Branch 14 → 15 taken 761 times.
✗ Branch 14 → 84 not taken.
761 insertCondJump(condValue, bExit, bThen, LIKELY);
199
200 // Switch to then block
201
1/2
✓ Branch 15 → 16 taken 761 times.
✗ Branch 15 → 84 not taken.
761 switchToBlock(bThen);
202 // Create constant for error message
203
2/4
✓ Branch 16 → 17 taken 761 times.
✗ Branch 16 → 60 not taken.
✓ Branch 17 → 18 taken 761 times.
✗ Branch 17 → 58 not taken.
761 const std::string errorMsg = "Assertion failed: Condition '" + node->expressionString + "' evaluated to false.\n";
204
4/8
✓ Branch 21 → 22 taken 761 times.
✗ Branch 21 → 66 not taken.
✓ Branch 22 → 23 taken 761 times.
✗ Branch 22 → 64 not taken.
✓ Branch 23 → 24 taken 761 times.
✗ Branch 23 → 62 not taken.
✓ Branch 25 → 26 taken 761 times.
✗ Branch 25 → 61 not taken.
1522 llvm::GlobalVariable *globalString = builder.CreateGlobalString(errorMsg, getUnusedGlobalName(ANON_GLOBAL_STRING_NAME));
205 // If the output should be comparable, fix alignment to 4 bytes
206
1/2
✓ Branch 29 → 30 taken 761 times.
✗ Branch 29 → 33 not taken.
761 if (cliOptions.comparableOutput)
207
2/4
✓ Branch 30 → 31 taken 761 times.
✗ Branch 30 → 72 not taken.
✓ Branch 31 → 32 taken 761 times.
✗ Branch 31 → 72 not taken.
761 globalString->setAlignment(llvm::Align(4));
208 // Print the error message
209
1/2
✓ Branch 33 → 34 taken 761 times.
✗ Branch 33 → 82 not taken.
761 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
210
3/6
✓ Branch 34 → 35 taken 761 times.
✗ Branch 34 → 76 not taken.
✓ Branch 36 → 37 taken 761 times.
✗ Branch 36 → 73 not taken.
✓ Branch 37 → 38 taken 761 times.
✗ Branch 37 → 73 not taken.
761 builder.CreateCall(printfFct, globalString);
211 // Generate call to exit()
212
1/2
✓ Branch 38 → 39 taken 761 times.
✗ Branch 38 → 82 not taken.
761 llvm::Function *exitFct = stdFunctionManager.getExitFct();
213
4/8
✓ Branch 39 → 40 taken 761 times.
✗ Branch 39 → 80 not taken.
✓ Branch 40 → 41 taken 761 times.
✗ Branch 40 → 78 not taken.
✓ Branch 42 → 43 taken 761 times.
✗ Branch 42 → 77 not taken.
✓ Branch 43 → 44 taken 761 times.
✗ Branch 43 → 77 not taken.
761 builder.CreateCall(exitFct, builder.getInt32(EXIT_FAILURE));
214 // Create unreachable instruction
215
1/2
✓ Branch 44 → 45 taken 761 times.
✗ Branch 44 → 82 not taken.
761 builder.CreateUnreachable();
216
217 // Switch to exit block
218
1/2
✓ Branch 45 → 46 taken 761 times.
✗ Branch 45 → 82 not taken.
761 switchToBlock(bExit);
219
220
1/2
✓ Branch 46 → 47 taken 761 times.
✗ Branch 46 → 81 not taken.
761 return nullptr;
221 761 }
222
223 } // namespace spice::compiler
224