GCC Code Coverage Report


Directory: ../
File: src/irgenerator/GenExpressions.cpp
Date: 2024-12-24 01:17:15
Exec Total Coverage
Lines: 436 440 99.1%
Functions: 16 16 100.0%
Branches: 465 788 59.0%

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
7 #include <llvm/IR/Module.h>
8
9 namespace spice::compiler {
10
11 43019 std::any IRGenerator::visitAssignExpr(const AssignExprNode *node) {
12 43019 diGenerator.setSourceLocation(node);
13
14 // Visit ternary expression
15
2/2
✓ Branch 0 taken 38571 times.
✓ Branch 1 taken 4448 times.
43019 if (node->ternaryExpr)
16 38571 return visit(node->ternaryExpr);
17
18 // Assign or compound assign operation
19
1/2
✓ Branch 0 taken 4448 times.
✗ Branch 1 not taken.
4448 if (node->op != AssignExprNode::OP_NONE) {
20 4448 const PrefixUnaryExprNode *lhsNode = node->lhs;
21 4448 const AssignExprNode *rhsNode = node->rhs;
22
23 // Normal assignment
24
2/2
✓ Branch 0 taken 3949 times.
✓ Branch 1 taken 499 times.
4448 if (node->op == AssignExprNode::OP_ASSIGN)
25
2/4
✓ Branch 1 taken 3949 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3949 times.
✗ Branch 5 not taken.
3949 return doAssignment(lhsNode, rhsNode, node);
26
27 // Compound assignment
28 // Get symbol types of left and right side
29
1/2
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
499 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
30
1/2
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
499 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
31
32 // Retrieve rhs
33
2/4
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 499 times.
✗ Branch 5 not taken.
499 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
34 // Retrieve lhs
35
2/4
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 499 times.
✗ Branch 5 not taken.
499 auto lhs = std::any_cast<LLVMExprResult>(visit(lhsNode));
36
37 499 LLVMExprResult result;
38
10/11
✓ Branch 0 taken 205 times.
✓ Branch 1 taken 27 times.
✓ Branch 2 taken 15 times.
✓ Branch 3 taken 35 times.
✓ Branch 4 taken 5 times.
✓ Branch 5 taken 1 times.
✓ Branch 6 taken 2 times.
✓ Branch 7 taken 1 times.
✓ Branch 8 taken 1 times.
✓ Branch 9 taken 207 times.
✗ Branch 10 not taken.
499 switch (node->op) {
39 205 case AssignExprNode::OP_PLUS_EQUAL:
40
1/2
✓ Branch 1 taken 205 times.
✗ Branch 2 not taken.
205 result = conversionManager.getPlusEqualInst(node, lhs, lhsSTy, rhs, rhsSTy, 0);
41 205 break;
42 27 case AssignExprNode::OP_MINUS_EQUAL:
43
1/2
✓ Branch 1 taken 27 times.
✗ Branch 2 not taken.
27 result = conversionManager.getMinusEqualInst(node, lhs, lhsSTy, rhs, rhsSTy, 0);
44 27 break;
45 15 case AssignExprNode::OP_MUL_EQUAL:
46
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 result = conversionManager.getMulEqualInst(node, lhs, lhsSTy, rhs, rhsSTy, 0);
47 15 break;
48 35 case AssignExprNode::OP_DIV_EQUAL:
49
1/2
✓ Branch 1 taken 35 times.
✗ Branch 2 not taken.
35 result = conversionManager.getDivEqualInst(node, lhs, lhsSTy, rhs, rhsSTy, 0);
50 35 break;
51 5 case AssignExprNode::OP_REM_EQUAL:
52
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 result = conversionManager.getRemEqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
53 5 break;
54 1 case AssignExprNode::OP_SHL_EQUAL:
55
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 result = conversionManager.getSHLEqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
56 1 break;
57 2 case AssignExprNode::OP_SHR_EQUAL:
58
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 result = conversionManager.getSHREqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
59 2 break;
60 1 case AssignExprNode::OP_AND_EQUAL:
61
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 result = conversionManager.getAndEqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
62 1 break;
63 1 case AssignExprNode::OP_OR_EQUAL:
64
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 result = conversionManager.getOrEqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
65 1 break;
66 207 case AssignExprNode::OP_XOR_EQUAL:
67
1/2
✓ Branch 1 taken 207 times.
✗ Branch 2 not taken.
207 result = conversionManager.getXorEqualInst(node, lhs, lhsSTy, rhs, rhsSTy);
68 207 break;
69 default: // GCOV_EXCL_LINE
70 throw CompilerError(UNHANDLED_BRANCH, "Assign op fall-through"); // GCOV_EXCL_LINE
71 }
72
73
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 499 times.
499 if (result.ptr) { // The operation allocated more memory
74 if (lhs.entry)
75 lhs.entry->updateAddress(result.ptr);
76
2/2
✓ Branch 0 taken 379 times.
✓ Branch 1 taken 120 times.
499 } else if (result.value) { // The operation only updated the value
77 // Store the result
78 379 lhs.value = result.value;
79
5/6
✓ Branch 0 taken 171 times.
✓ Branch 1 taken 208 times.
✓ Branch 2 taken 2 times.
✓ Branch 3 taken 169 times.
✓ Branch 5 taken 379 times.
✗ Branch 6 not taken.
379 insertStore(lhs.value, lhs.ptr, lhs.entry && lhs.entry->isVolatile);
80 }
81
1/2
✓ Branch 1 taken 499 times.
✗ Branch 2 not taken.
998 return LLVMExprResult{.value = lhs.value, .ptr = lhs.ptr, .refPtr = lhs.refPtr, .entry = lhs.entry};
82 }
83
84 // This is a fallthrough case -> throw an error
85 throw CompilerError(UNHANDLED_BRANCH, "AssignStmt fall-through"); // GCOV_EXCL_LINE
86 }
87
88 38789 std::any IRGenerator::visitTernaryExpr(const TernaryExprNode *node) {
89 38789 diGenerator.setSourceLocation(node);
90
91 // Check if only one operand is present -> loop through
92
2/2
✓ Branch 0 taken 38526 times.
✓ Branch 1 taken 263 times.
38789 if (!node->falseExpr)
93 38526 return visit(node->condition);
94
95 // It is a ternary
96 // Retrieve the condition value
97 263 llvm::Value *condValue = resolveValue(node->condition);
98
99 // Get the values of true and false
100 llvm::Value *trueValue;
101 llvm::Value *falseValue;
102
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 262 times.
263 if (node->isShortened) {
103 1 trueValue = condValue;
104 1 falseValue = resolveValue(node->falseExpr);
105 } else {
106 262 trueValue = resolveValue(node->trueExpr);
107 262 falseValue = resolveValue(node->falseExpr);
108 }
109
110
2/4
✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 263 times.
✗ Branch 5 not taken.
263 llvm::Value *resultValue = builder.CreateSelect(condValue, trueValue, falseValue);
111
1/2
✓ Branch 1 taken 263 times.
✗ Branch 2 not taken.
526 return LLVMExprResult{.value = resultValue};
112 }
113
114 39314 std::any IRGenerator::visitLogicalOrExpr(const LogicalOrExprNode *node) {
115
1/2
✓ Branch 1 taken 39314 times.
✗ Branch 2 not taken.
39314 diGenerator.setSourceLocation(node);
116
117 // Check if only one operand is present -> loop through
118
2/2
✓ Branch 1 taken 39073 times.
✓ Branch 2 taken 241 times.
39314 if (node->operands.size() == 1)
119
1/2
✓ Branch 2 taken 39073 times.
✗ Branch 3 not taken.
39073 return visit(node->operands.front());
120
121 // It is a logical or expression
122 // Create exit block for short-circuiting
123
1/2
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
241 const std::string codeLoc = node->codeLoc.toPrettyLineAndColumn();
124
2/4
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 241 times.
✗ Branch 5 not taken.
241 llvm::BasicBlock *bExit = createBlock("lor.exit." + codeLoc);
125
126 // Visit the first operand
127
1/2
✓ Branch 2 taken 241 times.
✗ Branch 3 not taken.
241 llvm::Value *firstOperandValue = resolveValue(node->operands.front());
128
129 // Prepare an array for value-to-block-mapping
130 241 std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> shortCircuitBlocks;
131
1/2
✓ Branch 2 taken 241 times.
✗ Branch 3 not taken.
241 shortCircuitBlocks.reserve(node->operands.size());
132 // The first element is the first operand value with the original block
133
1/2
✓ Branch 2 taken 241 times.
✗ Branch 3 not taken.
241 shortCircuitBlocks.emplace_back(builder.GetInsertBlock(), firstOperandValue);
134 // Create a block for each additional operand and save it to the mapping
135
2/2
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 241 times.
506 for (size_t i = 1; i < node->operands.size(); i++)
136
6/12
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 265 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 265 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 265 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 265 times.
✗ Branch 17 not taken.
265 shortCircuitBlocks.emplace_back(createBlock("lor." + std::to_string(i) + "." + codeLoc), nullptr);
137 // Create conditional jump to the exit block if the first operand was true, otherwise to the next block
138
2/4
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 241 times.
✗ Branch 5 not taken.
241 insertCondJump(firstOperandValue, bExit, shortCircuitBlocks.at(1).first);
139
140 // Create block for each operand
141
2/2
✓ Branch 1 taken 265 times.
✓ Branch 2 taken 241 times.
506 for (size_t i = 1; i < node->operands.size(); i++) {
142 // Switch to the next block
143
2/4
✓ Branch 1 taken 265 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 265 times.
✗ Branch 5 not taken.
265 switchToBlock(shortCircuitBlocks.at(i).first);
144 // Evaluate operand and save the result in the mapping
145
2/4
✓ Branch 2 taken 265 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 265 times.
✗ Branch 6 not taken.
265 shortCircuitBlocks.at(i).second = resolveValue(node->operands[i]);
146 // Replace the array entry with the current insert block, since the insert block could have changed in the meantime
147
1/2
✓ Branch 2 taken 265 times.
✗ Branch 3 not taken.
265 shortCircuitBlocks.at(i).first = builder.GetInsertBlock();
148 // Check if there are more blocks to process
149
2/2
✓ Branch 1 taken 241 times.
✓ Branch 2 taken 24 times.
265 if (i == node->operands.size() - 1) {
150 // Insert a simple jump to the exit block for the last block
151
1/2
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
241 insertJump(bExit);
152 } else {
153 // Create conditional jump to the exit block if the first operand was true, otherwise to the next block
154
3/6
✓ Branch 1 taken 24 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 24 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 24 times.
✗ Branch 8 not taken.
24 insertCondJump(shortCircuitBlocks.at(i).second, bExit, shortCircuitBlocks.at(i + 1).first);
155 }
156 }
157
158 // Get the result with the phi node
159
1/2
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
241 switchToBlock(bExit);
160
2/4
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 241 times.
✗ Branch 7 not taken.
241 llvm::PHINode *result = builder.CreatePHI(firstOperandValue->getType(), node->operands.size(), "lor_phi");
161
2/2
✓ Branch 7 taken 506 times.
✓ Branch 8 taken 241 times.
747 for (const auto &[incomingBlock, value] : shortCircuitBlocks)
162
1/2
✓ Branch 1 taken 506 times.
✗ Branch 2 not taken.
506 result->addIncoming(value, incomingBlock);
163
164 // Return the result
165
1/2
✓ Branch 1 taken 241 times.
✗ Branch 2 not taken.
241 return LLVMExprResult{.value = result};
166 241 }
167
168 39579 std::any IRGenerator::visitLogicalAndExpr(const LogicalAndExprNode *node) {
169
1/2
✓ Branch 1 taken 39579 times.
✗ Branch 2 not taken.
39579 diGenerator.setSourceLocation(node);
170
171 // Check if only one operand is present -> loop through
172
2/2
✓ Branch 1 taken 39523 times.
✓ Branch 2 taken 56 times.
39579 if (node->operands.size() == 1)
173
1/2
✓ Branch 2 taken 39523 times.
✗ Branch 3 not taken.
39523 return visit(node->operands.front());
174
175 // It is a logical and expression
176 // Create exit block for short-circuiting
177
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 const std::string codeLoc = node->codeLoc.toPrettyLineAndColumn();
178
2/4
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
56 llvm::BasicBlock *bExit = createBlock("land.exit." + codeLoc);
179
180 // Visit the first operand
181
1/2
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 llvm::Value *firstOperandValue = resolveValue(node->operands.front());
182
183 // Prepare an array for value-to-block-mapping
184 56 std::vector<std::pair<llvm::BasicBlock *, llvm::Value *>> shortCircuitBlocks;
185
1/2
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 shortCircuitBlocks.reserve(node->operands.size());
186 // The first element is the first operand value with the original block
187
1/2
✓ Branch 2 taken 56 times.
✗ Branch 3 not taken.
56 shortCircuitBlocks.emplace_back(builder.GetInsertBlock(), firstOperandValue);
188 // Create a block for each additional operand and save it to the mapping
189
2/2
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 56 times.
117 for (size_t i = 1; i < node->operands.size(); i++)
190
6/12
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 61 times.
✗ Branch 8 not taken.
✓ Branch 10 taken 61 times.
✗ Branch 11 not taken.
✓ Branch 13 taken 61 times.
✗ Branch 14 not taken.
✓ Branch 16 taken 61 times.
✗ Branch 17 not taken.
61 shortCircuitBlocks.emplace_back(createBlock("land." + std::to_string(i) + "." + codeLoc), nullptr);
191 // Create conditional jump to the exit block if the first operand was true, otherwise to the next block
192
2/4
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 56 times.
✗ Branch 5 not taken.
56 insertCondJump(firstOperandValue, shortCircuitBlocks.at(1).first, bExit);
193
194 // Create block for each operand
195
2/2
✓ Branch 1 taken 61 times.
✓ Branch 2 taken 56 times.
117 for (size_t i = 1; i < node->operands.size(); i++) {
196 // Switch to the next block
197
2/4
✓ Branch 1 taken 61 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 61 times.
✗ Branch 5 not taken.
61 switchToBlock(shortCircuitBlocks.at(i).first);
198 // Evaluate operand and save the result in the mapping
199
2/4
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
✓ Branch 5 taken 61 times.
✗ Branch 6 not taken.
61 shortCircuitBlocks.at(i).second = resolveValue(node->operands[i]);
200 // Replace the array entry with the current insert block, since the insert block could have changed in the meantime
201
1/2
✓ Branch 2 taken 61 times.
✗ Branch 3 not taken.
61 shortCircuitBlocks.at(i).first = builder.GetInsertBlock();
202 // Check if there are more blocks to process
203
2/2
✓ Branch 1 taken 56 times.
✓ Branch 2 taken 5 times.
61 if (i == node->operands.size() - 1) {
204 // Insert a simple jump to the exit block for the last block
205
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 insertJump(bExit);
206 } else {
207 // Create conditional jump to the exit block if the operand was true, otherwise to the next block
208
3/6
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 5 times.
✗ Branch 5 not taken.
✓ Branch 7 taken 5 times.
✗ Branch 8 not taken.
5 insertCondJump(shortCircuitBlocks.at(i).second, shortCircuitBlocks.at(i + 1).first, bExit);
209 }
210 }
211
212 // Get the result with the phi node
213
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 switchToBlock(bExit);
214
2/4
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
✓ Branch 6 taken 56 times.
✗ Branch 7 not taken.
56 llvm::PHINode *result = builder.CreatePHI(firstOperandValue->getType(), node->operands.size(), "land_phi");
215
2/2
✓ Branch 7 taken 117 times.
✓ Branch 8 taken 56 times.
173 for (const auto &[incomingBlock, value] : shortCircuitBlocks)
216
1/2
✓ Branch 1 taken 117 times.
✗ Branch 2 not taken.
117 result->addIncoming(value, incomingBlock);
217
218 // Return the result
219
1/2
✓ Branch 1 taken 56 times.
✗ Branch 2 not taken.
56 return LLVMExprResult{.value = result};
220 56 }
221
222 39640 std::any IRGenerator::visitBitwiseOrExpr(const BitwiseOrExprNode *node) {
223
1/2
✓ Branch 1 taken 39640 times.
✗ Branch 2 not taken.
39640 diGenerator.setSourceLocation(node);
224
225 // Check if only one operand is present -> loop through
226
2/2
✓ Branch 1 taken 39610 times.
✓ Branch 2 taken 30 times.
39640 if (node->operands.size() == 1)
227
1/2
✓ Branch 2 taken 39610 times.
✗ Branch 3 not taken.
39610 return visit(node->operands.front());
228
229 // It is a bitwise or expression
230 // Evaluate first operand
231 30 const BitwiseXorExprNode *lhsNode = node->operands.front();
232
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
233
2/4
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 30 times.
✗ Branch 5 not taken.
30 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
234
235 // Evaluate all additional operands
236
2/2
✓ Branch 1 taken 31 times.
✓ Branch 2 taken 30 times.
61 for (size_t i = 1; i < node->operands.size(); i++) {
237 // Evaluate the operand
238 31 const BitwiseXorExprNode *rhsNode = node->operands[i];
239
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 const QualType rhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
240
2/4
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 31 times.
✗ Branch 5 not taken.
31 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
241
1/2
✓ Branch 1 taken 31 times.
✗ Branch 2 not taken.
31 result = conversionManager.getBitwiseOrInst(node, result, lhsSTy, rhs, rhsSTy, i - 1);
242 }
243
244 // Return result
245
1/2
✓ Branch 1 taken 30 times.
✗ Branch 2 not taken.
30 return result;
246 }
247
248 39671 std::any IRGenerator::visitBitwiseXorExpr(const BitwiseXorExprNode *node) {
249
1/2
✓ Branch 1 taken 39671 times.
✗ Branch 2 not taken.
39671 diGenerator.setSourceLocation(node);
250
251 // Check if only one operand is present -> loop through
252
2/2
✓ Branch 1 taken 39669 times.
✓ Branch 2 taken 2 times.
39671 if (node->operands.size() == 1)
253
1/2
✓ Branch 2 taken 39669 times.
✗ Branch 3 not taken.
39669 return visit(node->operands.front());
254
255 // It is a bitwise xor expression
256 // Evaluate first operand
257 2 const BitwiseAndExprNode *lhsNode = node->operands.front();
258
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
259
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2 times.
✗ Branch 5 not taken.
2 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
260
261 // Evaluate all additional operands
262
2/2
✓ Branch 1 taken 3 times.
✓ Branch 2 taken 2 times.
5 for (size_t i = 1; i < node->operands.size(); i++) {
263 // Evaluate the operand
264 3 const BitwiseAndExprNode *rhsNode = node->operands[i];
265
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 const QualType rhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
266
2/4
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3 times.
✗ Branch 5 not taken.
3 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
267
1/2
✓ Branch 1 taken 3 times.
✗ Branch 2 not taken.
3 result = conversionManager.getBitwiseXorInst(node, result, lhsSTy, rhs, rhsSTy);
268 }
269
270 // Return result
271
1/2
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
2 return result;
272 }
273
274 39674 std::any IRGenerator::visitBitwiseAndExpr(const BitwiseAndExprNode *node) {
275
1/2
✓ Branch 1 taken 39674 times.
✗ Branch 2 not taken.
39674 diGenerator.setSourceLocation(node);
276
277 // Check if only one operand is present -> loop through
278
2/2
✓ Branch 1 taken 39646 times.
✓ Branch 2 taken 28 times.
39674 if (node->operands.size() == 1)
279
1/2
✓ Branch 2 taken 39646 times.
✗ Branch 3 not taken.
39646 return visit(node->operands.front());
280
281 // It is a bitwise and expression
282 // Evaluate first operand
283 28 const EqualityExprNode *lhsNode = node->operands.front();
284
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
285
2/4
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 28 times.
✗ Branch 5 not taken.
28 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
286
287 // Evaluate all additional operands
288
2/2
✓ Branch 1 taken 29 times.
✓ Branch 2 taken 28 times.
57 for (size_t i = 1; i < node->operands.size(); i++) {
289 // Evaluate the operand
290 29 const EqualityExprNode *rhsNode = node->operands[i];
291
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 const QualType rhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
292
2/4
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 29 times.
✗ Branch 5 not taken.
29 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
293
1/2
✓ Branch 1 taken 29 times.
✗ Branch 2 not taken.
29 result = conversionManager.getBitwiseAndInst(rhsNode, result, lhsSTy, rhs, rhsSTy, i - 1);
294 }
295
296 // Return result
297
1/2
✓ Branch 1 taken 28 times.
✗ Branch 2 not taken.
28 return result;
298 }
299
300 39703 std::any IRGenerator::visitEqualityExpr(const EqualityExprNode *node) {
301
1/2
✓ Branch 1 taken 39703 times.
✗ Branch 2 not taken.
39703 diGenerator.setSourceLocation(node);
302
303 // Check if only one operand is present -> loop through
304
2/2
✓ Branch 1 taken 36268 times.
✓ Branch 2 taken 3435 times.
39703 if (node->operands.size() == 1)
305
1/2
✓ Branch 2 taken 36268 times.
✗ Branch 3 not taken.
36268 return visit(node->operands.front());
306
307 // It is an equality expression
308 // Evaluate lhs
309 3435 const RelationalExprNode *lhsNode = node->operands[0];
310
1/2
✓ Branch 1 taken 3435 times.
✗ Branch 2 not taken.
3435 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
311
2/4
✓ Branch 1 taken 3435 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3435 times.
✗ Branch 5 not taken.
3435 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
312
313 // Evaluate rhs
314 3435 const RelationalExprNode *rhsNode = node->operands[1];
315
1/2
✓ Branch 1 taken 3435 times.
✗ Branch 2 not taken.
3435 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
316
2/4
✓ Branch 1 taken 3435 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3435 times.
✗ Branch 5 not taken.
3435 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
317
318 // Retrieve the result value, based on the exact operator
319
2/3
✓ Branch 0 taken 2219 times.
✓ Branch 1 taken 1216 times.
✗ Branch 2 not taken.
3435 switch (node->op) {
320 2219 case EqualityExprNode::OP_EQUAL:
321
1/2
✓ Branch 1 taken 2219 times.
✗ Branch 2 not taken.
2219 result = conversionManager.getEqualInst(node, result, lhsSTy, rhs, rhsSTy, 0);
322 2219 break;
323 1216 case EqualityExprNode::OP_NOT_EQUAL:
324
1/2
✓ Branch 1 taken 1216 times.
✗ Branch 2 not taken.
1216 result = conversionManager.getNotEqualInst(node, result, lhsSTy, rhs, rhsSTy, 0);
325 1216 break;
326 default: // GCOV_EXCL_LINE
327 throw CompilerError(UNHANDLED_BRANCH, "EqualityExpr fall-through"); // GCOV_EXCL_LINE
328 }
329
330 // Return the result
331
1/2
✓ Branch 1 taken 3435 times.
✗ Branch 2 not taken.
3435 return result;
332 }
333
334 43138 std::any IRGenerator::visitRelationalExpr(const RelationalExprNode *node) {
335
1/2
✓ Branch 1 taken 43138 times.
✗ Branch 2 not taken.
43138 diGenerator.setSourceLocation(node);
336
337 // Check if only one operand is present -> loop through
338
2/2
✓ Branch 1 taken 40822 times.
✓ Branch 2 taken 2316 times.
43138 if (node->operands.size() == 1)
339
1/2
✓ Branch 2 taken 40822 times.
✗ Branch 3 not taken.
40822 return visit(node->operands.front());
340
341 // It is a relational expression
342 // Evaluate lhs
343 2316 const ShiftExprNode *lhsNode = node->operands[0];
344
1/2
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
2316 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
345
2/4
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2316 times.
✗ Branch 5 not taken.
2316 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
346
347 // Evaluate rhs
348 2316 const ShiftExprNode *rhsNode = node->operands[1];
349
1/2
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
2316 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
350
2/4
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2316 times.
✗ Branch 5 not taken.
2316 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
351
352 // Retrieve the result value, based on the exact operator
353
4/5
✓ Branch 0 taken 1344 times.
✓ Branch 1 taken 222 times.
✓ Branch 2 taken 236 times.
✓ Branch 3 taken 514 times.
✗ Branch 4 not taken.
2316 switch (node->op) {
354 1344 case RelationalExprNode::OP_LESS:
355
1/2
✓ Branch 1 taken 1344 times.
✗ Branch 2 not taken.
1344 result = conversionManager.getLessInst(node, result, lhsSTy, rhs, rhsSTy);
356 1344 break;
357 222 case RelationalExprNode::OP_GREATER:
358
1/2
✓ Branch 1 taken 222 times.
✗ Branch 2 not taken.
222 result = conversionManager.getGreaterInst(node, result, lhsSTy, rhs, rhsSTy);
359 222 break;
360 236 case RelationalExprNode::OP_LESS_EQUAL:
361
1/2
✓ Branch 1 taken 236 times.
✗ Branch 2 not taken.
236 result = conversionManager.getLessEqualInst(node, result, lhsSTy, rhs, rhsSTy);
362 236 break;
363 514 case RelationalExprNode::OP_GREATER_EQUAL:
364
1/2
✓ Branch 1 taken 514 times.
✗ Branch 2 not taken.
514 result = conversionManager.getGreaterEqualInst(node, result, lhsSTy, rhs, rhsSTy);
365 514 break;
366 default: // GCOV_EXCL_LINE
367 throw CompilerError(UNHANDLED_BRANCH, "EqualityExpr fall-through"); // GCOV_EXCL_LINE
368 }
369
370 // Return the result
371
1/2
✓ Branch 1 taken 2316 times.
✗ Branch 2 not taken.
2316 return result;
372 }
373
374 45454 std::any IRGenerator::visitShiftExpr(const ShiftExprNode *node) {
375
1/2
✓ Branch 1 taken 45454 times.
✗ Branch 2 not taken.
45454 diGenerator.setSourceLocation(node);
376
377 // Check if only one operand is present -> loop through
378
2/2
✓ Branch 1 taken 45439 times.
✓ Branch 2 taken 15 times.
45454 if (node->operands.size() == 1)
379
1/2
✓ Branch 2 taken 45439 times.
✗ Branch 3 not taken.
45439 return visit(node->operands.front());
380
381 // It is a shift expression
382 // Evaluate lhs
383 15 const AdditiveExprNode *lhsNode = node->operands[0];
384
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
385
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
15 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
386
387 // Evaluate rhs
388 15 const AdditiveExprNode *rhsNode = node->operands[1];
389
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
390
2/4
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 15 times.
✗ Branch 5 not taken.
15 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
391
392 // Retrieve the result value, based on the exact operator
393
2/3
✓ Branch 0 taken 10 times.
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
15 switch (node->op) {
394 10 case ShiftExprNode::OP_SHIFT_LEFT:
395
1/2
✓ Branch 1 taken 10 times.
✗ Branch 2 not taken.
10 result = conversionManager.getShiftLeftInst(node, result, lhsSTy, rhs, rhsSTy, 0);
396 10 break;
397 5 case ShiftExprNode::OP_SHIFT_RIGHT:
398
1/2
✓ Branch 1 taken 5 times.
✗ Branch 2 not taken.
5 result = conversionManager.getShiftRightInst(node, result, lhsSTy, rhs, rhsSTy, 0);
399 5 break;
400 default: // GCOV_EXCL_LINE
401 throw CompilerError(UNHANDLED_BRANCH, "ShiftExpr fall-through"); // GCOV_EXCL_LINE
402 }
403
404 // Return the result
405
1/2
✓ Branch 1 taken 15 times.
✗ Branch 2 not taken.
15 return result;
406 }
407
408 45469 std::any IRGenerator::visitAdditiveExpr(const AdditiveExprNode *node) {
409
1/2
✓ Branch 1 taken 45469 times.
✗ Branch 2 not taken.
45469 diGenerator.setSourceLocation(node);
410
411 // Check if only one operand is present -> loop through
412
2/2
✓ Branch 1 taken 42725 times.
✓ Branch 2 taken 2744 times.
45469 if (node->operands.size() == 1)
413
1/2
✓ Branch 2 taken 42725 times.
✗ Branch 3 not taken.
42725 return visit(node->operands.front());
414
415 // It is an additive expression
416 // Evaluate first operand
417 2744 const MultiplicativeExprNode *lhsNode = node->operands[0];
418
1/2
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
2744 QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
419
2/4
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2744 times.
✗ Branch 5 not taken.
2744 auto lhs = std::any_cast<LLVMExprResult>(visit(lhsNode));
420
421
1/2
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
2744 auto opQueue = node->opQueue;
422 2744 size_t operandIndex = 1;
423
2/2
✓ Branch 1 taken 3115 times.
✓ Branch 2 taken 2744 times.
5859 while (!opQueue.empty()) {
424 3115 const size_t operatorIndex = operandIndex - 1;
425 // Evaluate next operand
426 3115 const MultiplicativeExprNode *rhsNode = node->operands[operandIndex++];
427
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 3115 times.
3115 assert(rhsNode != nullptr);
428
1/2
✓ Branch 1 taken 3115 times.
✗ Branch 2 not taken.
3115 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
429
2/4
✓ Branch 1 taken 3115 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 3115 times.
✗ Branch 5 not taken.
3115 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
430
431 // Retrieve the result, based on the exact operator
432
2/3
✓ Branch 1 taken 1971 times.
✓ Branch 2 taken 1144 times.
✗ Branch 3 not taken.
3115 switch (opQueue.front().first) {
433 1971 case AdditiveExprNode::OP_PLUS:
434
1/2
✓ Branch 1 taken 1971 times.
✗ Branch 2 not taken.
1971 lhs = conversionManager.getPlusInst(node, lhs, lhsSTy, rhs, rhsSTy, operatorIndex);
435 1971 break;
436 1144 case AdditiveExprNode::OP_MINUS:
437
1/2
✓ Branch 1 taken 1144 times.
✗ Branch 2 not taken.
1144 lhs = conversionManager.getMinusInst(node, lhs, lhsSTy, rhs, rhsSTy, operatorIndex);
438 1144 break;
439 default: // GCOV_EXCL_LINE
440 throw CompilerError(UNHANDLED_BRANCH, "AdditiveExpr fall-through"); // GCOV_EXCL_LINE
441 }
442
443 // Retrieve the new lhs symbol type
444 3115 lhsSTy = opQueue.front().second;
445
446 3115 opQueue.pop();
447 }
448
449 // Return the result
450
1/2
✓ Branch 1 taken 2744 times.
✗ Branch 2 not taken.
2744 return lhs;
451 2744 }
452
453 48584 std::any IRGenerator::visitMultiplicativeExpr(const MultiplicativeExprNode *node) {
454
1/2
✓ Branch 1 taken 48584 times.
✗ Branch 2 not taken.
48584 diGenerator.setSourceLocation(node);
455
456 // Check if only one operand is present -> loop through
457
2/2
✓ Branch 1 taken 47799 times.
✓ Branch 2 taken 785 times.
48584 if (node->operands.size() == 1)
458
1/2
✓ Branch 2 taken 47799 times.
✗ Branch 3 not taken.
47799 return visit(node->operands.front());
459
460 // It is an additive expression
461 // Evaluate first operand
462 785 const CastExprNode *lhsNode = node->operands[0];
463
1/2
✓ Branch 1 taken 785 times.
✗ Branch 2 not taken.
785 QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
464
2/4
✓ Branch 1 taken 785 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 785 times.
✗ Branch 5 not taken.
785 auto result = std::any_cast<LLVMExprResult>(visit(lhsNode));
465
466
1/2
✓ Branch 1 taken 785 times.
✗ Branch 2 not taken.
785 auto opQueue = node->opQueue;
467 785 size_t operandIndex = 1;
468
2/2
✓ Branch 1 taken 805 times.
✓ Branch 2 taken 785 times.
1590 while (!opQueue.empty()) {
469 805 const size_t operatorIndex = operandIndex - 1;
470 // Evaluate next operand
471 805 const CastExprNode *rhsNode = node->operands[operandIndex++];
472
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 805 times.
805 assert(rhsNode != nullptr);
473
1/2
✓ Branch 1 taken 805 times.
✗ Branch 2 not taken.
805 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
474
2/4
✓ Branch 1 taken 805 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 805 times.
✗ Branch 5 not taken.
805 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
475
476 // Retrieve the result, based on the exact operator
477
3/4
✓ Branch 1 taken 603 times.
✓ Branch 2 taken 193 times.
✓ Branch 3 taken 9 times.
✗ Branch 4 not taken.
805 switch (opQueue.front().first) {
478 603 case MultiplicativeExprNode::OP_MUL:
479
1/2
✓ Branch 1 taken 603 times.
✗ Branch 2 not taken.
603 result = conversionManager.getMulInst(node, result, lhsSTy, rhs, rhsSTy, operatorIndex);
480 603 break;
481 193 case MultiplicativeExprNode::OP_DIV:
482
1/2
✓ Branch 1 taken 193 times.
✗ Branch 2 not taken.
193 result = conversionManager.getDivInst(node, result, lhsSTy, rhs, rhsSTy, operatorIndex);
483 193 break;
484 9 case MultiplicativeExprNode::OP_REM:
485
1/2
✓ Branch 1 taken 9 times.
✗ Branch 2 not taken.
9 result = conversionManager.getRemInst(node, result, lhsSTy, rhs, rhsSTy);
486 9 break;
487 default: // GCOV_EXCL_LINE
488 throw CompilerError(UNHANDLED_BRANCH, "MultiplicativeExpr fall-through"); // GCOV_EXCL_LINE
489 }
490
491 // Retrieve the new lhs symbol type
492 805 lhsSTy = opQueue.front().second;
493 805 opQueue.pop();
494 }
495
496 // Return the result
497
1/2
✓ Branch 1 taken 785 times.
✗ Branch 2 not taken.
785 return result;
498 785 }
499
500 49389 std::any IRGenerator::visitCastExpr(const CastExprNode *node) {
501
1/2
✓ Branch 1 taken 49389 times.
✗ Branch 2 not taken.
49389 diGenerator.setSourceLocation(node);
502
503 // Check if only one operand is present -> loop through
504
2/2
✓ Branch 0 taken 47233 times.
✓ Branch 1 taken 2156 times.
49389 if (!node->isCast)
505
1/2
✓ Branch 1 taken 47233 times.
✗ Branch 2 not taken.
47233 return visit(node->prefixUnaryExpr);
506
507 // It is a cast expression
508 // Retrieve target symbol type
509
1/2
✓ Branch 1 taken 2156 times.
✗ Branch 2 not taken.
2156 const QualType targetSTy = node->getEvaluatedSymbolType(manIdx);
510
511 // Evaluate rhs
512 2156 const PrefixUnaryExprNode *rhsNode = node->prefixUnaryExpr;
513
1/2
✓ Branch 1 taken 2156 times.
✗ Branch 2 not taken.
2156 const QualType rhsSTy = rhsNode->getEvaluatedSymbolType(manIdx);
514
2/4
✓ Branch 1 taken 2156 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2156 times.
✗ Branch 5 not taken.
2156 auto rhs = std::any_cast<LLVMExprResult>(visit(rhsNode));
515
516 // Retrieve the result value
517
1/2
✓ Branch 1 taken 2156 times.
✗ Branch 2 not taken.
2156 const LLVMExprResult result = conversionManager.getCastInst(node, targetSTy, rhs, rhsSTy);
518
519 // Return the result
520
1/2
✓ Branch 1 taken 2156 times.
✗ Branch 2 not taken.
2156 return result;
521 }
522
523 54534 std::any IRGenerator::visitPrefixUnaryExpr(const PrefixUnaryExprNode *node) {
524
1/2
✓ Branch 1 taken 54534 times.
✗ Branch 2 not taken.
54534 diGenerator.setSourceLocation(node);
525
526 // If no operator is applied, simply visit the atomic expression
527
2/2
✓ Branch 0 taken 53837 times.
✓ Branch 1 taken 697 times.
54534 if (node->op == PrefixUnaryExprNode::OP_NONE)
528
1/2
✓ Branch 1 taken 53837 times.
✗ Branch 2 not taken.
53837 return visit(node->postfixUnaryExpr);
529
530 // Evaluate lhs
531 697 const PrefixUnaryExprNode *lhsNode = node->prefixUnaryExpr;
532
1/2
✓ Branch 1 taken 697 times.
✗ Branch 2 not taken.
697 const QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
533
2/4
✓ Branch 1 taken 697 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 697 times.
✗ Branch 5 not taken.
697 auto lhs = std::any_cast<LLVMExprResult>(visit(lhsNode));
534
535
7/8
✓ Branch 0 taken 16 times.
✓ Branch 1 taken 26 times.
✓ Branch 2 taken 4 times.
✓ Branch 3 taken 520 times.
✓ Branch 4 taken 1 times.
✓ Branch 5 taken 75 times.
✓ Branch 6 taken 55 times.
✗ Branch 7 not taken.
697 switch (node->op) {
536 16 case PrefixUnaryExprNode::OP_MINUS: {
537 // Execute operation
538
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 lhs = conversionManager.getPrefixMinusInst(node, lhs, lhsSTy);
539
540 // This operator can not work in-place, so we need additional memory
541
2/4
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 16 times.
✗ Branch 6 not taken.
16 lhs.ptr = insertAlloca(lhs.value->getType());
542
543 // Store the new value
544
1/2
✓ Branch 1 taken 16 times.
✗ Branch 2 not taken.
16 insertStore(lhs.value, lhs.ptr);
545
546 16 break;
547 }
548 26 case PrefixUnaryExprNode::OP_PLUS_PLUS: {
549 // Make sure the value is present
550
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 resolveValue(lhsNode, lhs);
551
552 // Execute operation
553
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 lhs.value = conversionManager.getPrefixPlusPlusInst(node, lhs, lhsSTy).value;
554
555 // If this operation happens on a volatile variable, store the value directly
556
3/4
✓ Branch 0 taken 25 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 25 times.
26 if (lhs.entry && lhs.entry->isVolatile)
557 insertStore(lhs.value, lhs.ptr, true);
558
559 // Save to the existing address if possible, otherwise (e.g. for literals) allocate new space
560
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 25 times.
26 if (!lhs.ptr)
561
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 lhs.ptr = insertAlloca(lhs.value->getType());
562
563 // Store the new value
564
1/2
✓ Branch 1 taken 26 times.
✗ Branch 2 not taken.
26 insertStore(lhs.value, lhs.ptr);
565
566 26 break;
567 }
568 4 case PrefixUnaryExprNode::OP_MINUS_MINUS: {
569 // Make sure the value is present
570
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 resolveValue(lhsNode, lhs);
571
572 // Execute operation
573
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 lhs.value = conversionManager.getPrefixMinusMinusInst(node, lhs, lhsSTy).value;
574
575 // If this operation happens on a volatile variable, store the value directly
576
3/4
✓ Branch 0 taken 3 times.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 3 times.
4 if (lhs.entry && lhs.entry->isVolatile)
577 insertStore(lhs.value, lhs.ptr, true);
578
579 // Save to the existing address if possible, otherwise (e.g. for literals) allocate new space
580
2/2
✓ Branch 0 taken 1 times.
✓ Branch 1 taken 3 times.
4 if (!lhs.ptr)
581
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
2 lhs.ptr = insertAlloca(lhs.value->getType());
582
583 // Store the new value
584
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 insertStore(lhs.value, lhs.ptr);
585
586 4 break;
587 }
588 520 case PrefixUnaryExprNode::OP_NOT: {
589 // Make sure the value is present
590
1/2
✓ Branch 1 taken 520 times.
✗ Branch 2 not taken.
520 resolveValue(lhsNode, lhs);
591
592 // Execute operation
593
1/2
✓ Branch 1 taken 520 times.
✗ Branch 2 not taken.
520 lhs = conversionManager.getPrefixNotInst(node, lhs, lhsSTy);
594
595 // This operator can not work in-place, so we need additional memory
596
2/4
✓ Branch 1 taken 520 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 520 times.
✗ Branch 6 not taken.
520 lhs.ptr = insertAlloca(lhs.value->getType());
597
598 // Store the new value
599
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 520 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 520 times.
✗ Branch 6 not taken.
520 insertStore(lhs.value, lhs.ptr, lhs.entry && lhs.entry->isVolatile);
600
601 520 break;
602 }
603 1 case PrefixUnaryExprNode::OP_BITWISE_NOT: {
604 // Make sure the value is present
605
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 resolveValue(lhsNode, lhs);
606
607 // Execute operation
608
1/2
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
1 lhs = conversionManager.getPrefixBitwiseNotInst(node, lhs, lhsSTy);
609
610 // This operator can not work in-place, so we need additional memory
611
2/4
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 lhs.ptr = insertAlloca(lhs.value->getType());
612
613 // Store the new value
614
2/6
✗ Branch 0 not taken.
✓ Branch 1 taken 1 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 5 taken 1 times.
✗ Branch 6 not taken.
1 insertStore(lhs.value, lhs.ptr, lhs.entry && lhs.entry->isVolatile);
615
616 1 break;
617 }
618 75 case PrefixUnaryExprNode::OP_DEREFERENCE: {
619 // Make sure the value is present
620
1/2
✓ Branch 1 taken 75 times.
✗ Branch 2 not taken.
75 resolveValue(lhsNode, lhs);
621
622 // Execute operation
623 75 lhs.ptr = lhs.value;
624
625 // Reset the value
626 75 lhs.value = nullptr;
627
628 75 break;
629 }
630 55 case PrefixUnaryExprNode::OP_ADDRESS_OF: {
631 // Make sure the address is present
632
1/2
✓ Branch 1 taken 55 times.
✗ Branch 2 not taken.
55 resolveAddress(lhs);
633
634 // Execute operation
635 55 lhs.value = lhs.ptr;
636
637 // Reset the address
638 55 lhs.ptr = nullptr;
639
640 55 break;
641 }
642 default: // GCOV_EXCL_LINE
643 throw CompilerError(UNHANDLED_BRANCH, "PrefixUnaryExpr fall-through"); // GCOV_EXCL_LINE
644 }
645
646
1/2
✓ Branch 1 taken 697 times.
✗ Branch 2 not taken.
697 return lhs;
647 }
648
649 68564 std::any IRGenerator::visitPostfixUnaryExpr(const PostfixUnaryExprNode *node) {
650
1/2
✓ Branch 1 taken 68564 times.
✗ Branch 2 not taken.
68564 diGenerator.setSourceLocation(node);
651
652 // If no operator is applied, simply visit the atomic expression
653
2/2
✓ Branch 0 taken 53837 times.
✓ Branch 1 taken 14727 times.
68564 if (node->op == PostfixUnaryExprNode::OP_NONE)
654
1/2
✓ Branch 1 taken 53837 times.
✗ Branch 2 not taken.
53837 return visit(node->atomicExpr);
655
656 // Evaluate lhs
657 14727 const PostfixUnaryExprNode *lhsNode = node->postfixUnaryExpr;
658
1/2
✓ Branch 1 taken 14727 times.
✗ Branch 2 not taken.
14727 QualType lhsSTy = lhsNode->getEvaluatedSymbolType(manIdx);
659
2/4
✓ Branch 1 taken 14727 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 14727 times.
✗ Branch 5 not taken.
14727 auto lhs = std::any_cast<LLVMExprResult>(visit(lhsNode));
660
661
4/5
✓ Branch 0 taken 2118 times.
✓ Branch 1 taken 11133 times.
✓ Branch 2 taken 1234 times.
✓ Branch 3 taken 242 times.
✗ Branch 4 not taken.
14727 switch (node->op) {
662 2118 case PostfixUnaryExprNode::OP_SUBSCRIPT: {
663
1/2
✓ Branch 1 taken 2118 times.
✗ Branch 2 not taken.
2118 lhsSTy = lhsSTy.removeReferenceWrapper();
664
665 // Get the index value
666 2118 const AssignExprNode *indexExpr = node->subscriptIndexExpr;
667
1/2
✓ Branch 1 taken 2118 times.
✗ Branch 2 not taken.
2118 llvm::Value *indexValue = resolveValue(indexExpr);
668 // Come up with the address
669
8/10
✓ Branch 1 taken 2118 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 135 times.
✓ Branch 4 taken 1983 times.
✓ Branch 6 taken 135 times.
✗ Branch 7 not taken.
✓ Branch 8 taken 95 times.
✓ Branch 9 taken 40 times.
✓ Branch 10 taken 95 times.
✓ Branch 11 taken 2023 times.
2118 if (lhsSTy.isArray() && lhsSTy.getArraySize() != ARRAY_SIZE_UNKNOWN) { // Array
670 // Make sure the address is present
671
1/2
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
95 resolveAddress(lhs);
672
673 // Calculate address of array item
674
1/2
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
95 llvm::Type *lhsTy = lhsSTy.toLLVMType(sourceFile);
675
1/2
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
95 llvm::Value *indices[2] = {builder.getInt64(0), indexValue};
676
2/4
✓ Branch 1 taken 95 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 95 times.
✗ Branch 6 not taken.
190 lhs.ptr = insertInBoundsGEP(lhsTy, lhs.ptr, indices);
677 } else { // Pointer
678 // Make sure the value is present
679
1/2
✓ Branch 1 taken 2023 times.
✗ Branch 2 not taken.
2023 resolveValue(lhsNode, lhs);
680
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2023 times.
2023 assert(lhs.value != nullptr);
681
682 // Now the pointer is the value
683 2023 lhs.ptr = lhs.value;
684
685
2/4
✓ Branch 1 taken 2023 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 2023 times.
✗ Branch 5 not taken.
2023 llvm::Type *lhsTy = lhsSTy.getContained().toLLVMType(sourceFile);
686 // Calculate address of pointer item
687
2/4
✓ Branch 1 taken 2023 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2023 times.
✗ Branch 6 not taken.
4046 lhs.ptr = insertInBoundsGEP(lhsTy, lhs.ptr, indexValue);
688 }
689
690 // Reset value and entry
691 2118 lhs.value = nullptr;
692 2118 lhs.entry = nullptr;
693 2118 break;
694 }
695 11133 case PostfixUnaryExprNode::OP_MEMBER_ACCESS: {
696 // Get the address of the struct instance
697
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 resolveAddress(lhs);
698
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 lhsSTy = lhsSTy.removeReferenceWrapper();
699
700 // Auto de-reference pointer
701
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 autoDeReferencePtr(lhs.ptr, lhsSTy);
702
2/4
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
✗ Branch 3 not taken.
✓ Branch 4 taken 11133 times.
11133 assert(lhsSTy.is(TY_STRUCT));
703
704 // Retrieve struct scope
705 11133 const std::string &fieldName = node->identifier;
706
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 Scope *structScope = lhsSTy.getBodyScope();
707
708 // Retrieve field entry
709 11133 std::vector<size_t> indexPath;
710
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 lhs.entry = structScope->symbolTable.lookupInComposedFields(fieldName, indexPath);
711
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 11133 times.
11133 assert(lhs.entry != nullptr);
712
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 const QualType fieldSymbolType = lhs.entry->getQualType();
713
714 // Get address of the field in the struct instance
715
2/4
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11133 times.
✗ Branch 5 not taken.
22266 std::vector<llvm::Value *> indices = {builder.getInt64(0)};
716
2/2
✓ Branch 4 taken 11139 times.
✓ Branch 5 taken 11133 times.
22272 for (const size_t index : indexPath)
717
2/4
✓ Branch 1 taken 11139 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 11139 times.
✗ Branch 5 not taken.
11139 indices.push_back(builder.getInt32(index));
718
1/2
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
11133 const std::string name = fieldName + "_addr";
719
3/6
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 11133 times.
✗ Branch 6 not taken.
✓ Branch 8 taken 11133 times.
✗ Branch 9 not taken.
11133 llvm::Value *memberAddr = insertInBoundsGEP(lhsSTy.toLLVMType(sourceFile), lhs.ptr, indices, name);
720
721 // Set as ptr or refPtr, depending on the type
722
3/4
✓ Branch 1 taken 11133 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 142 times.
✓ Branch 4 taken 10991 times.
11133 if (fieldSymbolType.isRef()) {
723 142 lhs.ptr = nullptr;
724 142 lhs.refPtr = memberAddr;
725 } else {
726 10991 lhs.ptr = memberAddr;
727 10991 lhs.refPtr = nullptr;
728 }
729
730 // Reset the value
731 11133 lhs.value = nullptr;
732 11133 break;
733 11133 }
734 1234 case PostfixUnaryExprNode::OP_PLUS_PLUS: {
735 // Make sure a value is present
736
1/2
✓ Branch 1 taken 1234 times.
✗ Branch 2 not taken.
1234 resolveValue(lhsNode, lhs);
737
738 // Allocate new local variable if required
739
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 1232 times.
1234 if (!lhs.ptr) {
740
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 assert(lhs.value != nullptr);
741
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
4 lhs.ptr = insertAlloca(lhs.value->getType());
742 }
743
744 // Execute operation
745
1/2
✓ Branch 1 taken 1234 times.
✗ Branch 2 not taken.
1234 const LLVMExprResult result = conversionManager.getPostfixPlusPlusInst(node, lhs, lhsSTy, 0);
746
747 // Save the new value to the old address
748
3/4
✓ Branch 1 taken 1234 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 9 times.
✓ Branch 4 taken 1225 times.
1234 if (conversionManager.callsOverloadedOpFct(node, 0)) {
749 9 lhs.value = result.value;
750 9 lhs.ptr = result.ptr;
751 } else {
752
5/6
✓ Branch 0 taken 1223 times.
✓ Branch 1 taken 2 times.
✓ Branch 2 taken 3 times.
✓ Branch 3 taken 1220 times.
✓ Branch 5 taken 1225 times.
✗ Branch 6 not taken.
1225 insertStore(result.value, lhs.ptr, lhs.entry && lhs.entry->isVolatile);
753 1225 lhs.ptr = nullptr;
754 }
755 1234 break;
756 }
757 242 case PostfixUnaryExprNode::OP_MINUS_MINUS: {
758 // Make sure a value is present
759
1/2
✓ Branch 1 taken 242 times.
✗ Branch 2 not taken.
242 resolveValue(lhsNode, lhs);
760
761 // Allocate new local variable if required
762
2/2
✓ Branch 0 taken 2 times.
✓ Branch 1 taken 240 times.
242 if (!lhs.ptr) {
763
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 2 times.
2 assert(lhs.value != nullptr);
764
2/4
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 5 taken 2 times.
✗ Branch 6 not taken.
4 lhs.ptr = insertAlloca(lhs.value->getType());
765 }
766
767 // Execute operation
768
1/2
✓ Branch 1 taken 242 times.
✗ Branch 2 not taken.
242 const LLVMExprResult result = conversionManager.getPostfixMinusMinusInst(node, lhs, lhsSTy, 0);
769
770 // Save the new value to the old address
771
3/4
✓ Branch 1 taken 242 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 6 times.
✓ Branch 4 taken 236 times.
242 if (conversionManager.callsOverloadedOpFct(node, 0)) {
772 6 lhs.value = result.value;
773 6 lhs.ptr = result.ptr;
774 } else {
775
4/6
✓ Branch 0 taken 234 times.
✓ Branch 1 taken 2 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 234 times.
✓ Branch 5 taken 236 times.
✗ Branch 6 not taken.
236 insertStore(result.value, lhs.ptr, lhs.entry && lhs.entry->isVolatile);
776 236 lhs.ptr = nullptr;
777 }
778 242 break;
779 }
780 default: // GCOV_EXCL_LINE
781 throw CompilerError(UNHANDLED_BRANCH, "PostfixUnaryExpr fall-through"); // GCOV_EXCL_LINE
782 }
783
784
1/2
✓ Branch 1 taken 14727 times.
✗ Branch 2 not taken.
14727 return lhs;
785 }
786
787 53837 std::any IRGenerator::visitAtomicExpr(const AtomicExprNode *node) {
788
1/2
✓ Branch 1 taken 53837 times.
✗ Branch 2 not taken.
53837 diGenerator.setSourceLocation(node);
789
790 // If constant
791
2/2
✓ Branch 0 taken 8982 times.
✓ Branch 1 taken 44855 times.
53837 if (node->constant) {
792
2/4
✓ Branch 1 taken 8982 times.
✗ Branch 2 not taken.
✓ Branch 4 taken 8982 times.
✗ Branch 5 not taken.
8982 const auto constantValue = std::any_cast<llvm::Constant *>(visit(node->constant));
793
1/2
✓ Branch 1 taken 8982 times.
✗ Branch 2 not taken.
17964 return LLVMExprResult{.constant = constantValue};
794 }
795
796 // If value
797
2/2
✓ Branch 0 taken 10317 times.
✓ Branch 1 taken 34538 times.
44855 if (node->value)
798
1/2
✓ Branch 1 taken 10317 times.
✗ Branch 2 not taken.
10317 return visit(node->value);
799
800 // Is assign expression
801
2/2
✓ Branch 0 taken 479 times.
✓ Branch 1 taken 34059 times.
34538 if (node->assignExpr)
802
1/2
✓ Branch 1 taken 479 times.
✗ Branch 2 not taken.
479 return visit(node->assignExpr);
803
804 // Check for builtin calls
805
2/2
✓ Branch 0 taken 1093 times.
✓ Branch 1 taken 32966 times.
34059 if (node->builtinCall)
806
1/2
✓ Branch 1 taken 1093 times.
✗ Branch 2 not taken.
1093 return visit(node->builtinCall);
807
808 // Identifier (local or global variable access)
809
1/2
✗ Branch 1 not taken.
✓ Branch 2 taken 32966 times.
32966 assert(!node->identifierFragments.empty());
810
811 // Get symbol table entry
812
1/2
✓ Branch 1 taken 32966 times.
✗ Branch 2 not taken.
32966 const auto &[varEntry, accessScope, capture] = node->data.at(manIdx);
813
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32966 times.
32966 assert(varEntry != nullptr);
814
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32966 times.
32966 assert(accessScope != nullptr);
815
1/2
✓ Branch 1 taken 32966 times.
✗ Branch 2 not taken.
32966 const QualType varSymbolType = varEntry->getQualType();
816
1/2
✓ Branch 1 taken 32966 times.
✗ Branch 2 not taken.
32966 llvm::Type *varType = varSymbolType.toLLVMType(sourceFile);
817
818 // Check if external global variable
819
7/8
✓ Branch 0 taken 1204 times.
✓ Branch 1 taken 31762 times.
✓ Branch 3 taken 1204 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 53 times.
✓ Branch 6 taken 1151 times.
✓ Branch 7 taken 53 times.
✓ Branch 8 taken 32913 times.
32966 if (varEntry->global && accessScope->isImportedBy(rootScope)) {
820 // External global variables need to be declared and allocated in the current module
821
1/2
✓ Branch 2 taken 53 times.
✗ Branch 3 not taken.
53 llvm::Value *varAddress = module->getOrInsertGlobal(varEntry->name, varType);
822
1/2
✓ Branch 1 taken 53 times.
✗ Branch 2 not taken.
53 varEntry->updateAddress(varAddress);
823 }
824
825 // Check if enum item
826
2/2
✓ Branch 0 taken 231 times.
✓ Branch 1 taken 32735 times.
32966 if (accessScope->type == ScopeType::ENUM) {
827
1/2
✓ Branch 0 taken 231 times.
✗ Branch 1 not taken.
231 const auto itemNode = spice_pointer_cast<const EnumItemNode *>(varEntry->declNode);
828
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
231 llvm::Constant *constantItemValue = llvm::ConstantInt::get(varType, itemNode->itemValue);
829
1/2
✓ Branch 1 taken 231 times.
✗ Branch 2 not taken.
462 return LLVMExprResult{.constant = constantItemValue, .entry = varEntry};
830 }
831
832
1/2
✓ Branch 1 taken 32735 times.
✗ Branch 2 not taken.
32735 llvm::Value *address = varEntry->getAddress();
833
1/2
✗ Branch 0 not taken.
✓ Branch 1 taken 32735 times.
32735 assert(address != nullptr);
834
835 // If this is a function/procedure reference, return it as value
836
7/8
✓ Branch 0 taken 1204 times.
✓ Branch 1 taken 31531 times.
✓ Branch 3 taken 1204 times.
✗ Branch 4 not taken.
✓ Branch 5 taken 4 times.
✓ Branch 6 taken 1200 times.
✓ Branch 7 taken 4 times.
✓ Branch 8 taken 32731 times.
32735 if (varEntry->global && varSymbolType.isOneOf({TY_FUNCTION, TY_PROCEDURE})) {
837
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
4 llvm::Value *fatPtr = buildFatFctPtr(nullptr, nullptr, address);
838
1/2
✓ Branch 1 taken 4 times.
✗ Branch 2 not taken.
8 return LLVMExprResult{.ptr = fatPtr, .entry = varEntry};
839 }
840
841 // Load the address of the referenced variable
842
10/12
✓ Branch 1 taken 32731 times.
✗ Branch 2 not taken.
✓ Branch 3 taken 30395 times.
✓ Branch 4 taken 2336 times.
✓ Branch 5 taken 27 times.
✓ Branch 6 taken 30368 times.
✓ Branch 8 taken 27 times.
✗ Branch 9 not taken.
✓ Branch 10 taken 9 times.
✓ Branch 11 taken 18 times.
✓ Branch 12 taken 2345 times.
✓ Branch 13 taken 30386 times.
32731 if (varSymbolType.isRef() || (capture && capture->getMode() == BY_REFERENCE))
843
1/2
✓ Branch 1 taken 2345 times.
✗ Branch 2 not taken.
4690 return LLVMExprResult{.refPtr = address, .entry = varEntry};
844
845
1/2
✓ Branch 1 taken 30386 times.
✗ Branch 2 not taken.
60772 return LLVMExprResult{.ptr = address, .entry = varEntry};
846 }
847
848 } // namespace spice::compiler
849