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 |
7/10✓ 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 9 taken 5560 times.
✗ Branch 10 not taken.
✓ Branch 11 taken 2 times.
✓ Branch 12 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 |
2/4✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 1 times.
✗ Branch 5 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 |
2/4✓ Branch 1 taken 5557 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5557 times.
✗ Branch 5 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 |
3/4✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 15 times.
✓ Branch 4 taken 9 times.
|
24 | if (node->constant()) |
108 |
2/4✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 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 |
2/4✓ Branch 1 taken 653 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 653 times.
✗ Branch 5 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 |