GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenStatements.cpp
Date: 2025-03-05 01:50:32
Exec Total Coverage
Lines: 102 110 92.7%
Functions: 9 12 75.0%
Branches: 103 190 54.2%

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