GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenStatements.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 100 108 92.6%
Functions: 9 12 75.0%
Branches: 107 194 55.2%

Line Branch Exec Source
1 // Copyright (c) 2021-2024 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 12124 std::any IRGenerator::visitStmtLst(const StmtLstNode *node) {
13 // Generate instructions in the scope
14
2/2
✓ Branch 5 taken 24326 times.
✓ Branch 6 taken 12120 times.
36446 for (const ASTNode *stmt : node->children) {
15
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 24326 times.
24326 if (!stmt)
16 continue;
17 // Check if we can cancel generating instructions for this code branch
18
4/4
✓ Branch 0 taken 24325 times.
✓ Branch 1 taken 1 times.
✓ Branch 2 taken 24322 times.
✓ Branch 3 taken 3 times.
24326 if (blockAlreadyTerminated || stmt->unreachable)
19 break;
20 // Visit child
21
1/2
✓ Branch 1 taken 24322 times.
✗ Branch 2 not taken.
24322 visit(stmt);
22 }
23
24 // Generate cleanup code of this scope, e.g. dtor calls for struct instances
25 12124 diGenerator.setSourceLocation(node->getNextOuterStmtLst()->closingBraceCodeLoc);
26 12124 generateScopeCleanup(node);
27
28
1/2
✓ Branch 1 taken 12124 times.
✗ Branch 2 not taken.
12124 return nullptr;
29 }
30
31 std::any IRGenerator::visitTypeAltsLst(const TypeAltsLstNode *node) {
32 return nullptr; // Noop
33 }
34
35 5747 std::any IRGenerator::visitDeclStmt(const DeclStmtNode *node) {
36
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 diGenerator.setSourceLocation(node);
37
38 // Get variable entry
39
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 SymbolTableEntry *varEntry = node->entries.at(manIdx);
40
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5747 times.
5747 assert(varEntry != nullptr);
41
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 const QualType varSymbolType = varEntry->getQualType();
42
43 // Get LLVM type of variable
44
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 llvm::Type *varTy = varSymbolType.toLLVMType(sourceFile);
45
46 // Check if right side is dyn array. If this is the case we have an empty array initializer and need the default value
47
6/8
✓ Branch 0 taken 5560 times.
✓ Branch 1 taken 187 times.
✓ Branch 3 taken 5560 times.
✗ Branch 4 not taken.
✓ Branch 6 taken 5560 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 2 times.
✓ Branch 9 taken 5558 times.
5747 const bool rhsIsDynArray = node->hasAssignment && node->assignExpr->getEvaluatedSymbolType(manIdx).isArrayOf(TY_DYN);
48
49 // Check if the declaration is with an assignment or the default value
50 5747 llvm::Value *varAddress = nullptr;
51
4/4
✓ Branch 0 taken 5560 times.
✓ Branch 1 taken 187 times.
✓ Branch 2 taken 5558 times.
✓ Branch 3 taken 2 times.
5747 if (node->hasAssignment && !rhsIsDynArray) { // Assignment
52
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 5557 times.
5558 if (node->calledCopyCtor) {
53 // Allocate memory
54
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
1 varAddress = insertAlloca(varTy);
55
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 varEntry->updateAddress(varAddress);
56 // Call copy ctor
57
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 llvm::Value *rhsAddress = resolveAddress(node->assignExpr);
58
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
1 assert(rhsAddress != nullptr);
59
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 not taken.
3 generateCtorOrDtorCall(varEntry, node->calledCopyCtor, {rhsAddress});
60 } else {
61 // Assign rhs to lhs
62
1/2
✓ Branch 1 taken 5557 times.
✗ Branch 2 not taken.
5557 [[maybe_unused]] const LLVMExprResult assignResult = doAssignment(varAddress, varEntry, node->assignExpr, node, true);
63
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5557 times.
5557 assert(assignResult.entry == varEntry);
64
1/2
✓ Branch 1 taken 5557 times.
✗ Branch 2 not taken.
5557 varAddress = varEntry->getAddress();
65
1/2
✓ Branch 1 taken 5557 times.
✗ Branch 2 not taken.
5557 varEntry->updateAddress(varAddress);
66 }
67 5558 } else { // Default value
68 // Allocate memory
69
2/4
✓ Branch 1 taken 189 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 189 times.
✗ Branch 5 not taken.
189 varAddress = insertAlloca(varTy);
70
1/2
✓ Branch 1 taken 189 times.
✗ Branch 2 not taken.
189 varEntry->updateAddress(varAddress);
71
72
2/2
✓ Branch 0 taken 31 times.
✓ Branch 1 taken 158 times.
189 if (node->calledInitCtor) {
73 // Call no-args constructor
74
1/2
✓ Branch 2 taken 31 times.
✗ Branch 3 not taken.
31 generateCtorOrDtorCall(varEntry, node->calledInitCtor, {});
75
3/4
✓ Branch 0 taken 73 times.
✓ Branch 1 taken 85 times.
✓ Branch 2 taken 73 times.
✗ Branch 3 not taken.
158 } else if (!node->isForEachItem && cliOptions.buildMode == DEBUG) {
76
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 73 times.
73 assert(!node->isCtorCallRequired);
77 // Retrieve default value for lhs symbol type and store it
78
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 llvm::Constant *defaultValue = getDefaultValueForSymbolType(varSymbolType);
79
1/2
✓ Branch 1 taken 73 times.
✗ Branch 2 not taken.
73 insertStore(defaultValue, varAddress);
80 }
81 }
82
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 5747 times.
5747 assert(varAddress != nullptr);
83
84 // Attach the variable name to the LLVM value.
85
2/4
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5747 times.
✗ Branch 5 not taken.
5747 varAddress->setName(varEntry->name);
86
87 // Generate debug info for variable declaration
88
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 diGenerator.setSourceLocation(node);
89
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 diGenerator.generateLocalVarDebugInfo(node->varName, varAddress);
90
91
1/2
✓ Branch 1 taken 5747 times.
✗ Branch 2 not taken.
5747 return nullptr;
92 }
93
94 std::any IRGenerator::visitSpecifierLst(const SpecifierLstNode *node) {
95 return nullptr; // Noop
96 }
97
98 246 std::any IRGenerator::visitModAttr(const ModAttrNode *node) {
99
1/2
✓ Branch 1 taken 246 times.
✗ Branch 2 not taken.
246 return nullptr; // Noop
100 }
101
102 std::any IRGenerator::visitTopLevelDefinitionAttr(const TopLevelDefinitionAttrNode *node) {
103 return nullptr; // Noop
104 }
105
106 24 std::any IRGenerator::visitCaseConstant(const CaseConstantNode *node) {
107
2/2
✓ Branch 0 taken 15 times.
✓ Branch 1 taken 9 times.
24 if (node->constant)
108
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 return visit(node->constant);
109
110 // Get constant for enum item
111
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 9 times.
9 assert(node->enumItemEntry->scope->type == ScopeType::ENUM);
112
1/2
✓ Branch 0 taken 9 times.
✗ Branch 1 not taken.
9 const auto itemNode = spice_pointer_cast<const EnumItemNode *>(node->enumItemEntry->declNode);
113
2/4
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 9 times.
✗ Branch 5 not taken.
9 llvm::Constant *constant = llvm::ConstantInt::get(builder.getInt32Ty(), itemNode->itemValue);
114
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 return constant;
115 }
116
117 5398 std::any IRGenerator::visitReturnStmt(const ReturnStmtNode *node) {
118 5398 diGenerator.setSourceLocation(node);
119
120 5398 llvm::Value *returnValue = nullptr;
121
2/2
✓ Branch 0 taken 5352 times.
✓ Branch 1 taken 46 times.
5398 if (node->hasReturnValue) { // Return value is attached to the return statement
122
2/2
✓ Branch 2 taken 198 times.
✓ Branch 3 taken 5154 times.
5352 if (node->getEvaluatedSymbolType(manIdx).isRef())
123 198 returnValue = resolveAddress(node->assignExpr);
124 else
125 5154 returnValue = resolveValue(node->assignExpr);
126 } else { // Try to load return variable value
127
1/2
✓ Branch 1 taken 46 times.
✗ Branch 2 not taken.
138 const SymbolTableEntry *resultEntry = currentScope->lookup(RETURN_VARIABLE_NAME);
128
2/2
✓ Branch 0 taken 4 times.
✓ Branch 1 taken 42 times.
46 if (resultEntry != nullptr) {
129 4 llvm::Type *resultSTy = resultEntry->getQualType().toLLVMType(sourceFile);
130 4 llvm::Value *returnValueAddr = resultEntry->getAddress();
131
2/4
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 4 times.
✗ Branch 5 not taken.
8 returnValue = insertLoad(resultSTy, returnValueAddr);
132 }
133 }
134
135 // Terminate the block (with scope cleanup)
136 5398 terminateBlock(node->getParentScopeNode());
137
138 // Create return instruction
139
2/2
✓ Branch 0 taken 5356 times.
✓ Branch 1 taken 42 times.
5398 if (returnValue != nullptr) {
140 // Return with value
141 5356 builder.CreateRet(returnValue);
142 } else {
143 // Return without value
144 42 builder.CreateRetVoid();
145 }
146
147
1/2
✓ Branch 1 taken 5398 times.
✗ Branch 2 not taken.
5398 return nullptr;
148 }
149
150 91 std::any IRGenerator::visitBreakStmt(const BreakStmtNode *node) {
151 91 diGenerator.setSourceLocation(node);
152
153 // Jump to destination block
154 91 const size_t blockIdx = breakBlocks.size() - node->breakTimes;
155 91 insertJump(breakBlocks.at(blockIdx));
156
157
1/2
✓ Branch 1 taken 91 times.
✗ Branch 2 not taken.
91 return nullptr;
158 }
159
160 301 std::any IRGenerator::visitContinueStmt(const ContinueStmtNode *node) {
161 301 diGenerator.setSourceLocation(node);
162
163 // Jump to destination block
164 301 const size_t blockIdx = continueBlocks.size() - node->continueTimes;
165 301 insertJump(continueBlocks.at(blockIdx));
166
167
1/2
✓ Branch 1 taken 301 times.
✗ Branch 2 not taken.
301 return nullptr;
168 }
169
170 4 std::any IRGenerator::visitFallthroughStmt(const FallthroughStmtNode *node) {
171 4 diGenerator.setSourceLocation(node);
172
173 // Jump to destination block
174 4 insertJump(fallthroughBlocks.top());
175
176
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 return nullptr;
177 }
178
179 653 std::any IRGenerator::visitAssertStmt(const AssertStmtNode *node) {
180 // Only generate assertions in debug build mode or in test mode
181
1/4
✗ Branch 0 not taken.
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
653 if (cliOptions.buildMode != DEBUG && !cliOptions.testMode)
182 return nullptr;
183
184
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 diGenerator.setSourceLocation(node);
185
186 // Create blocks
187
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 const std::string &codeLine = node->codeLoc.toPrettyLine();
188
2/4
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
653 llvm::BasicBlock *bThen = createBlock("assert.then." + codeLine);
189
2/4
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
653 llvm::BasicBlock *bExit = createBlock("assert.exit." + codeLine);
190
191 // Visit the assignExpr
192
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 llvm::Value *condValue = resolveValue(node->assignExpr);
193
194 // Create condition check
195
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 insertCondJump(condValue, bExit, bThen, LIKELY);
196
197 // Switch to then block
198
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 switchToBlock(bThen);
199 // Create constant for error message
200
2/4
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
653 const std::string errorMsg = "Assertion failed: Condition '" + node->expressionString + "' evaluated to false.";
201
4/8
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 653 times.
✗ Branch 8 not taken.
✓ Branch 11 taken 653 times.
✗ Branch 12 not taken.
1306 llvm::Constant *globalString = builder.CreateGlobalStringPtr(errorMsg, getUnusedGlobalName(ANON_GLOBAL_STRING_NAME));
202 // Print the error message
203
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 llvm::Function *printfFct = stdFunctionManager.getPrintfFct();
204
3/6
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 653 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 653 times.
✗ Branch 9 not taken.
653 builder.CreateCall(printfFct, globalString);
205 // Generate call to exit()
206
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 llvm::Function *exitFct = stdFunctionManager.getExitFct();
207
4/8
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 not taken.
✓ Branch 8 taken 653 times.
✗ Branch 9 not taken.
✓ Branch 11 taken 653 times.
✗ Branch 12 not taken.
653 builder.CreateCall(exitFct, builder.getInt32(EXIT_FAILURE));
208 // Create unreachable instruction
209
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 builder.CreateUnreachable();
210
211 // Switch to exit block
212
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 switchToBlock(bExit);
213
214
1/2
✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
653 return nullptr;
215 653 }
216
217 } // namespace spice::compiler
218