src/irgenerator/GenControlStructures.cpp
| Line | Branch | Exec | Source |
|---|---|---|---|
| 1 | // Copyright (c) 2021-2026 ChilliBits. All rights reserved. | ||
| 2 | |||
| 3 | #include "IRGenerator.h" | ||
| 4 | |||
| 5 | #include <ast/ASTNodes.h> | ||
| 6 | #include <symboltablebuilder/ScopeHandle.h> | ||
| 7 | |||
| 8 | namespace spice::compiler { | ||
| 9 | |||
| 10 | 16980 | std::any IRGenerator::visitUnsafeBlockDef(const UnsafeBlockNode *node) { | |
| 11 | // Change scope | ||
| 12 |
2/4✓ Branch 2 → 3 taken 16980 times.
✗ Branch 2 → 14 not taken.
✓ Branch 3 → 4 taken 16980 times.
✗ Branch 3 → 12 not taken.
|
16980 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::UNSAFE_BODY, node); |
| 13 | |||
| 14 | // Visit instructions in the block | ||
| 15 |
1/2✓ Branch 5 → 6 taken 16980 times.
✗ Branch 5 → 16 not taken.
|
16980 | visit(node->body); |
| 16 | |||
| 17 |
1/2✓ Branch 7 → 8 taken 16980 times.
✗ Branch 7 → 17 not taken.
|
33960 | return nullptr; |
| 18 | 16980 | } | |
| 19 | |||
| 20 | 7383 | std::any IRGenerator::visitForLoop(const ForLoopNode *node) { | |
| 21 | // Create blocks | ||
| 22 |
1/2✓ Branch 2 → 3 taken 7383 times.
✗ Branch 2 → 73 not taken.
|
7383 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 23 |
2/4✓ Branch 3 → 4 taken 7383 times.
✗ Branch 3 → 51 not taken.
✓ Branch 4 → 5 taken 7383 times.
✗ Branch 4 → 49 not taken.
|
7383 | llvm::BasicBlock *bHead = createBlock("for.head." + codeLine); |
| 24 |
2/4✓ Branch 6 → 7 taken 7383 times.
✗ Branch 6 → 54 not taken.
✓ Branch 7 → 8 taken 7383 times.
✗ Branch 7 → 52 not taken.
|
7383 | llvm::BasicBlock *bBody = createBlock("for.body." + codeLine); |
| 25 |
2/4✓ Branch 9 → 10 taken 7383 times.
✗ Branch 9 → 57 not taken.
✓ Branch 10 → 11 taken 7383 times.
✗ Branch 10 → 55 not taken.
|
7383 | llvm::BasicBlock *bTail = createBlock("for.tail." + codeLine); |
| 26 |
2/4✓ Branch 12 → 13 taken 7383 times.
✗ Branch 12 → 60 not taken.
✓ Branch 13 → 14 taken 7383 times.
✗ Branch 13 → 58 not taken.
|
7383 | llvm::BasicBlock *bExit = createBlock("for.exit." + codeLine); |
| 27 | |||
| 28 | // Change scope | ||
| 29 |
2/4✓ Branch 15 → 16 taken 7383 times.
✗ Branch 15 → 63 not taken.
✓ Branch 16 → 17 taken 7383 times.
✗ Branch 16 → 61 not taken.
|
7383 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::FOR_BODY, node); |
| 30 | |||
| 31 | // Save the break/continue targets, paired with the scope to clean up to when jumping there | ||
| 32 |
1/2✓ Branch 18 → 19 taken 7383 times.
✗ Branch 18 → 69 not taken.
|
7383 | breakTargets.emplace_back(currentScope, bExit); |
| 33 |
1/2✓ Branch 19 → 20 taken 7383 times.
✗ Branch 19 → 69 not taken.
|
7383 | continueTargets.emplace_back(currentScope, bTail); |
| 34 | |||
| 35 | // Init statement | ||
| 36 |
1/2✓ Branch 20 → 21 taken 7383 times.
✗ Branch 20 → 65 not taken.
|
7383 | visit(node->initDecl); |
| 37 | // Create jump from original to head block | ||
| 38 |
1/2✓ Branch 22 → 23 taken 7383 times.
✗ Branch 22 → 69 not taken.
|
7383 | insertJump(bHead); |
| 39 | |||
| 40 | // Switch to head block | ||
| 41 |
1/2✓ Branch 23 → 24 taken 7383 times.
✗ Branch 23 → 69 not taken.
|
7383 | switchToBlock(bHead); |
| 42 | // Condition evaluation | ||
| 43 |
1/2✓ Branch 24 → 25 taken 7383 times.
✗ Branch 24 → 69 not taken.
|
7383 | llvm::Value *condValue = resolveValueInExprScope(node->condAssign); |
| 44 | // Create conditional jump from head to body or exit block | ||
| 45 |
1/2✓ Branch 25 → 26 taken 7383 times.
✗ Branch 25 → 69 not taken.
|
7383 | insertCondJump(condValue, bBody, bExit); |
| 46 | |||
| 47 | // Switch to body block | ||
| 48 |
1/2✓ Branch 26 → 27 taken 7383 times.
✗ Branch 26 → 69 not taken.
|
7383 | switchToBlock(bBody); |
| 49 | // Visit body | ||
| 50 |
1/2✓ Branch 27 → 28 taken 7383 times.
✗ Branch 27 → 66 not taken.
|
7383 | visit(node->body); |
| 51 | // Create jump from body to tail block | ||
| 52 |
1/2✓ Branch 29 → 30 taken 7383 times.
✗ Branch 29 → 69 not taken.
|
7383 | insertJump(bTail); |
| 53 | |||
| 54 | // Switch to tail block | ||
| 55 |
1/2✓ Branch 30 → 31 taken 7383 times.
✗ Branch 30 → 69 not taken.
|
7383 | switchToBlock(bTail); |
| 56 | // Inc statement | ||
| 57 |
1/2✓ Branch 31 → 32 taken 7383 times.
✗ Branch 31 → 67 not taken.
|
7383 | visit(node->incAssign); |
| 58 | // Create jump from tail to head | ||
| 59 |
1/2✓ Branch 33 → 34 taken 7383 times.
✗ Branch 33 → 69 not taken.
|
7383 | insertJump(bHead); |
| 60 | |||
| 61 | // Switch to exit block | ||
| 62 |
1/2✓ Branch 34 → 35 taken 7383 times.
✗ Branch 34 → 69 not taken.
|
7383 | switchToBlock(bExit); |
| 63 | |||
| 64 | // Pop break/continue targets | ||
| 65 |
1/2✗ Branch 36 → 37 not taken.
✓ Branch 36 → 38 taken 7383 times.
|
7383 | assert(breakTargets.back().block == bExit); |
| 66 | 7383 | breakTargets.pop_back(); | |
| 67 |
1/2✗ Branch 40 → 41 not taken.
✓ Branch 40 → 42 taken 7383 times.
|
7383 | assert(continueTargets.back().block == bTail); |
| 68 | 7383 | continueTargets.pop_back(); | |
| 69 | |||
| 70 |
1/2✓ Branch 43 → 44 taken 7383 times.
✗ Branch 43 → 68 not taken.
|
14766 | return nullptr; |
| 71 | 7383 | } | |
| 72 | |||
| 73 | 650 | std::any IRGenerator::visitForeachLoop(const ForeachLoopNode *node) { | |
| 74 | // Create blocks | ||
| 75 |
1/2✓ Branch 2 → 3 taken 650 times.
✗ Branch 2 → 283 not taken.
|
650 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 76 |
2/4✓ Branch 3 → 4 taken 650 times.
✗ Branch 3 → 193 not taken.
✓ Branch 4 → 5 taken 650 times.
✗ Branch 4 → 191 not taken.
|
650 | llvm::BasicBlock *bHead = createBlock("foreach.head." + codeLine); |
| 77 |
2/4✓ Branch 6 → 7 taken 650 times.
✗ Branch 6 → 196 not taken.
✓ Branch 7 → 8 taken 650 times.
✗ Branch 7 → 194 not taken.
|
650 | llvm::BasicBlock *bBody = createBlock("foreach.body." + codeLine); |
| 78 |
2/4✓ Branch 9 → 10 taken 650 times.
✗ Branch 9 → 199 not taken.
✓ Branch 10 → 11 taken 650 times.
✗ Branch 10 → 197 not taken.
|
650 | llvm::BasicBlock *bTail = createBlock("foreach.tail." + codeLine); |
| 79 |
2/4✓ Branch 12 → 13 taken 650 times.
✗ Branch 12 → 202 not taken.
✓ Branch 13 → 14 taken 650 times.
✗ Branch 13 → 200 not taken.
|
650 | llvm::BasicBlock *bExit = createBlock("foreach.exit." + codeLine); |
| 80 | |||
| 81 | // Change scope | ||
| 82 |
2/4✓ Branch 15 → 16 taken 650 times.
✗ Branch 15 → 205 not taken.
✓ Branch 16 → 17 taken 650 times.
✗ Branch 16 → 203 not taken.
|
650 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::FOREACH_BODY, node); |
| 83 | |||
| 84 | // Save the break/continue targets, paired with the scope to clean up to when jumping there | ||
| 85 |
1/2✓ Branch 18 → 19 taken 650 times.
✗ Branch 18 → 279 not taken.
|
650 | breakTargets.emplace_back(currentScope, bExit); |
| 86 |
1/2✓ Branch 19 → 20 taken 650 times.
✗ Branch 19 → 279 not taken.
|
650 | continueTargets.emplace_back(currentScope, bTail); |
| 87 | |||
| 88 | // Resolve iterator | ||
| 89 | 650 | ExprNode *iteratorAssignNode = node->iteratorAssign; | |
| 90 | llvm::Value *iteratorPtr; | ||
| 91 |
2/2✓ Branch 20 → 21 taken 592 times.
✓ Branch 20 → 66 taken 58 times.
|
650 | if (node->getIteratorFct != nullptr) { // The iteratorAssignExpr is of type Iterable |
| 92 |
1/2✓ Branch 21 → 22 taken 592 times.
✗ Branch 21 → 227 not taken.
|
592 | llvm::Value *iterablePtr = resolveAddress(iteratorAssignNode); |
| 93 | |||
| 94 | llvm::Value *iterator; | ||
| 95 | 592 | llvm::Value *iteratorAddr = nullptr; | |
| 96 | 592 | const QualType &iteratorType = node->getIteratorFct->returnType; | |
| 97 |
10/16✓ Branch 22 → 23 taken 592 times.
✗ Branch 22 → 207 not taken.
✓ Branch 25 → 26 taken 8 times.
✓ Branch 25 → 31 taken 584 times.
✓ Branch 26 → 27 taken 8 times.
✗ Branch 26 → 207 not taken.
✓ Branch 28 → 29 taken 8 times.
✗ Branch 28 → 207 not taken.
✓ Branch 29 → 30 taken 8 times.
✗ Branch 29 → 31 not taken.
✓ Branch 32 → 33 taken 8 times.
✓ Branch 32 → 34 taken 584 times.
✓ Branch 34 → 35 taken 8 times.
✓ Branch 34 → 49 taken 584 times.
✗ Branch 207 → 208 not taken.
✗ Branch 207 → 209 not taken.
|
1184 | if (!node->getIteratorFct->isMethod() && node->getIteratorFct->getParamTypes().front().isArray()) { // Array as iterable |
| 98 | // Call iterate() function from std/iterator/array-iterator | ||
| 99 |
1/2✓ Branch 35 → 36 taken 8 times.
✗ Branch 35 → 227 not taken.
|
8 | llvm::Function *iterateFct = stdFunctionManager.getIterateFct(node->getIteratorFct); |
| 100 |
2/4✓ Branch 36 → 37 taken 8 times.
✗ Branch 36 → 227 not taken.
✓ Branch 37 → 38 taken 8 times.
✗ Branch 37 → 227 not taken.
|
8 | const size_t arraySize = iteratorAssignNode->getEvaluatedSymbolType(manIdx).getArraySize(); |
| 101 |
1/2✗ Branch 38 → 39 not taken.
✓ Branch 38 → 40 taken 8 times.
|
8 | assert(arraySize > 0); |
| 102 |
4/8✓ Branch 40 → 41 taken 8 times.
✗ Branch 40 → 217 not taken.
✓ Branch 43 → 44 taken 8 times.
✗ Branch 43 → 214 not taken.
✓ Branch 44 → 45 taken 8 times.
✗ Branch 44 → 211 not taken.
✓ Branch 45 → 46 taken 8 times.
✗ Branch 45 → 211 not taken.
|
24 | iterator = insertCall(iterateFct, {iterablePtr, builder.getInt64(arraySize)}, iteratorType, iteratorAddr); |
| 103 | } else { // Struct as iterable | ||
| 104 | // Call .getIterator() on iterable | ||
| 105 |
1/2✓ Branch 49 → 50 taken 584 times.
✗ Branch 49 → 227 not taken.
|
584 | llvm::Function *getIteratorFct = stdFunctionManager.getIteratorFct(node->getIteratorFct); |
| 106 |
3/6✓ Branch 52 → 53 taken 584 times.
✗ Branch 52 → 222 not taken.
✓ Branch 53 → 54 taken 584 times.
✗ Branch 53 → 219 not taken.
✓ Branch 54 → 55 taken 584 times.
✗ Branch 54 → 219 not taken.
|
1752 | iterator = insertCall(getIteratorFct, {iterablePtr}, iteratorType, iteratorAddr); |
| 107 | } | ||
| 108 | |||
| 109 | // Resolve address of iterator. If it is returned via memory or coerced, it already lives in memory | ||
| 110 | 592 | LLVMExprResult callResult = {.node = iteratorAssignNode}; | |
| 111 |
1/2✓ Branch 58 → 59 taken 592 times.
✗ Branch 58 → 60 not taken.
|
592 | if (iteratorAddr != nullptr) |
| 112 | 592 | callResult.ptr = iteratorAddr; | |
| 113 | else | ||
| 114 | ✗ | callResult.value = iterator; | |
| 115 |
1/2✓ Branch 61 → 62 taken 592 times.
✗ Branch 61 → 227 not taken.
|
592 | iteratorPtr = resolveAddress(callResult); |
| 116 | |||
| 117 | // If an anonymous symbol exists, set its address | ||
| 118 |
3/4✓ Branch 62 → 63 taken 592 times.
✗ Branch 62 → 227 not taken.
✓ Branch 63 → 64 taken 2 times.
✓ Branch 63 → 65 taken 590 times.
|
592 | if (const SymbolTableEntry *returnSymbol = currentScope->symbolTable.lookupAnonymous(iteratorAssignNode)) |
| 119 |
1/2✓ Branch 64 → 65 taken 2 times.
✗ Branch 64 → 227 not taken.
|
2 | updateAddress(returnSymbol, iteratorPtr); |
| 120 | } else { // The iteratorAssignExpr is of type Iterator | ||
| 121 |
1/2✓ Branch 66 → 67 taken 58 times.
✗ Branch 66 → 279 not taken.
|
58 | iteratorPtr = resolveAddress(iteratorAssignNode); |
| 122 | } | ||
| 123 | |||
| 124 | // Check we have an idx | ||
| 125 | 650 | const DeclStmtNode *idxDeclNode = node->idxVarDecl; | |
| 126 | 650 | const bool hasIdx = idxDeclNode != nullptr; | |
| 127 | // Retrieve item ref type | ||
| 128 |
3/4✓ Branch 68 → 69 taken 44 times.
✓ Branch 68 → 70 taken 606 times.
✗ Branch 71 → 72 not taken.
✓ Branch 71 → 73 taken 650 times.
|
650 | assert(hasIdx ? node->getIdxFct != nullptr : node->getFct != nullptr); |
| 129 |
2/2✓ Branch 73 → 74 taken 44 times.
✓ Branch 73 → 75 taken 606 times.
|
650 | const QualType itemRefSTy = hasIdx ? node->getIdxFct->returnType : node->getFct->returnType; |
| 130 | |||
| 131 | // Visit idx variable declaration if required | ||
| 132 | 650 | const SymbolTableEntry *idxEntry = nullptr; | |
| 133 | 650 | llvm::Value *idxAddress = nullptr; | |
| 134 |
2/2✓ Branch 76 → 77 taken 44 times.
✓ Branch 76 → 83 taken 606 times.
|
650 | if (hasIdx) { |
| 135 |
1/2✓ Branch 77 → 78 taken 44 times.
✗ Branch 77 → 228 not taken.
|
44 | visit(idxDeclNode); |
| 136 | // Get address of idx variable | ||
| 137 |
1/2✓ Branch 79 → 80 taken 44 times.
✗ Branch 79 → 279 not taken.
|
44 | idxEntry = idxDeclNode->entries.at(manIdx); |
| 138 |
1/2✓ Branch 80 → 81 taken 44 times.
✗ Branch 80 → 279 not taken.
|
44 | idxAddress = getAddress(idxEntry); |
| 139 |
1/2✗ Branch 81 → 82 not taken.
✓ Branch 81 → 83 taken 44 times.
|
44 | assert(idxAddress != nullptr); |
| 140 | } | ||
| 141 | |||
| 142 | // Visit item variable declaration | ||
| 143 | 650 | const DeclStmtNode *itemDeclNode = node->itemVarDecl; | |
| 144 |
1/2✓ Branch 83 → 84 taken 650 times.
✗ Branch 83 → 229 not taken.
|
650 | visit(itemDeclNode); |
| 145 | // Get address of item variable | ||
| 146 |
1/2✓ Branch 85 → 86 taken 650 times.
✗ Branch 85 → 279 not taken.
|
650 | const SymbolTableEntry *itemEntry = itemDeclNode->entries.at(manIdx); |
| 147 |
1/2✓ Branch 86 → 87 taken 650 times.
✗ Branch 86 → 279 not taken.
|
650 | llvm::Value *itemAddress = getAddress(itemEntry); |
| 148 |
1/2✗ Branch 87 → 88 not taken.
✓ Branch 87 → 89 taken 650 times.
|
650 | assert(itemAddress != nullptr); |
| 149 | |||
| 150 | // Create jump from original to head block | ||
| 151 |
1/2✓ Branch 89 → 90 taken 650 times.
✗ Branch 89 → 279 not taken.
|
650 | insertJump(bHead); |
| 152 | |||
| 153 | // Switch to head block | ||
| 154 |
1/2✓ Branch 90 → 91 taken 650 times.
✗ Branch 90 → 279 not taken.
|
650 | switchToBlock(bHead); |
| 155 |
1/2✓ Branch 91 → 92 taken 650 times.
✗ Branch 91 → 279 not taken.
|
650 | diGenerator.setSourceLocation(node); |
| 156 | // Call .isValid() on iterator | ||
| 157 |
1/2✗ Branch 92 → 93 not taken.
✓ Branch 92 → 94 taken 650 times.
|
650 | assert(node->isValidFct); |
| 158 |
1/2✓ Branch 94 → 95 taken 650 times.
✗ Branch 94 → 279 not taken.
|
650 | llvm::Function *isValidFct = stdFunctionManager.getIteratorIsValidFct(node->isValidFct); |
| 159 |
4/8✓ Branch 95 → 96 taken 650 times.
✗ Branch 95 → 232 not taken.
✓ Branch 97 → 98 taken 650 times.
✗ Branch 97 → 230 not taken.
✓ Branch 98 → 99 taken 650 times.
✗ Branch 98 → 230 not taken.
✓ Branch 99 → 100 taken 650 times.
✗ Branch 99 → 279 not taken.
|
650 | llvm::Value *isValid = builder.CreateCall(isValidFct, iteratorPtr); |
| 160 | // Create conditional jump from head to body or exit block | ||
| 161 |
1/2✓ Branch 99 → 100 taken 650 times.
✗ Branch 99 → 279 not taken.
|
650 | insertCondJump(isValid, bBody, bExit); |
| 162 | |||
| 163 | // Switch to body block | ||
| 164 |
1/2✓ Branch 100 → 101 taken 650 times.
✗ Branch 100 → 279 not taken.
|
650 | switchToBlock(bBody); |
| 165 | // Get the current iterator values | ||
| 166 | 650 | LLVMExprResult itemResult; | |
| 167 |
2/2✓ Branch 101 → 102 taken 44 times.
✓ Branch 101 → 142 taken 606 times.
|
650 | if (hasIdx) { |
| 168 | // Allocate space to save pair | ||
| 169 | 44 | const QualType &pairSTy = node->getIdxFct->returnType; | |
| 170 |
1/2✓ Branch 102 → 103 taken 44 times.
✗ Branch 102 → 262 not taken.
|
44 | llvm::Type *pairTy = pairSTy.toLLVMType(sourceFile); |
| 171 | // Call .getIdx() on iterator. If the pair is returned via memory or coerced, it already lives in memory | ||
| 172 |
1/2✗ Branch 103 → 104 not taken.
✓ Branch 103 → 105 taken 44 times.
|
44 | assert(node->getIdxFct); |
| 173 |
1/2✓ Branch 105 → 106 taken 44 times.
✗ Branch 105 → 262 not taken.
|
44 | llvm::Function *getIdxFct = stdFunctionManager.getIteratorGetIdxFct(node->getIdxFct); |
| 174 | 44 | llvm::Value *pairPtr = nullptr; | |
| 175 |
3/6✓ Branch 108 → 109 taken 44 times.
✗ Branch 108 → 236 not taken.
✓ Branch 109 → 110 taken 44 times.
✗ Branch 109 → 233 not taken.
✓ Branch 110 → 111 taken 44 times.
✗ Branch 110 → 233 not taken.
|
88 | llvm::Value *pair = insertCall(getIdxFct, {iteratorPtr}, pairSTy, pairPtr); |
| 176 |
1/2✗ Branch 113 → 114 not taken.
✓ Branch 113 → 123 taken 44 times.
|
44 | if (pairPtr == nullptr) { |
| 177 | ✗ | pairPtr = insertAlloca(pairSTy, "pair.addr"); | |
| 178 | ✗ | pair->setName("pair"); | |
| 179 | ✗ | insertStore(pair, pairPtr); | |
| 180 | } | ||
| 181 | // Store idx to idx var | ||
| 182 |
2/4✓ Branch 125 → 126 taken 44 times.
✗ Branch 125 → 250 not taken.
✓ Branch 126 → 127 taken 44 times.
✗ Branch 126 → 248 not taken.
|
44 | llvm::Value *idxAddrInPair = insertStructGEP(pairTy, pairPtr, 0, "idx.addr"); |
| 183 | 44 | LLVMExprResult idxResult = {.ptr = idxAddrInPair}; | |
| 184 |
2/4✓ Branch 129 → 130 taken 44 times.
✗ Branch 129 → 132 not taken.
✓ Branch 130 → 131 taken 44 times.
✗ Branch 130 → 132 not taken.
|
44 | assert(idxAddress != nullptr && idxEntry != nullptr); |
| 185 |
2/4✓ Branch 133 → 134 taken 44 times.
✗ Branch 133 → 254 not taken.
✓ Branch 134 → 135 taken 44 times.
✗ Branch 134 → 254 not taken.
|
44 | doAssignment(idxAddress, idxEntry, idxResult, QualType(TY_LONG), node, true); |
| 186 | // Store item to item var | ||
| 187 |
2/4✓ Branch 137 → 138 taken 44 times.
✗ Branch 137 → 258 not taken.
✓ Branch 138 → 139 taken 44 times.
✗ Branch 138 → 256 not taken.
|
88 | itemResult.refPtr = insertStructGEP(pairTy, pairPtr, 1, "item.addr"); |
| 188 | } else { | ||
| 189 | // Call .get() on iterator | ||
| 190 |
1/2✗ Branch 142 → 143 not taken.
✓ Branch 142 → 144 taken 606 times.
|
606 | assert(node->getFct); |
| 191 |
1/2✓ Branch 144 → 145 taken 606 times.
✗ Branch 144 → 279 not taken.
|
606 | llvm::Function *getFct = stdFunctionManager.getIteratorGetFct(node->getFct); |
| 192 |
3/6✓ Branch 145 → 146 taken 606 times.
✗ Branch 145 → 265 not taken.
✓ Branch 147 → 148 taken 606 times.
✗ Branch 147 → 263 not taken.
✓ Branch 148 → 149 taken 606 times.
✗ Branch 148 → 263 not taken.
|
606 | itemResult.ptr = builder.CreateCall(getFct, iteratorPtr); |
| 193 | } | ||
| 194 |
2/2✓ Branch 150 → 151 taken 5 times.
✓ Branch 150 → 161 taken 645 times.
|
650 | if (node->calledItemCopyCtor != nullptr) { |
| 195 | // Call copy ctor | ||
| 196 |
1/2✓ Branch 151 → 152 taken 5 times.
✗ Branch 151 → 279 not taken.
|
5 | llvm::Value *rhsAddress = resolveAddress(itemResult); |
| 197 |
1/2✗ Branch 152 → 153 not taken.
✓ Branch 152 → 154 taken 5 times.
|
5 | assert(rhsAddress != nullptr); |
| 198 |
2/4✓ Branch 156 → 157 taken 5 times.
✗ Branch 156 → 268 not taken.
✓ Branch 157 → 158 taken 5 times.
✗ Branch 157 → 266 not taken.
|
15 | generateCtorOrDtorCall(itemEntry, node->calledItemCopyCtor, {rhsAddress}); |
| 199 | } else { | ||
| 200 | // Perform normal assignment | ||
| 201 |
1/2✓ Branch 161 → 162 taken 645 times.
✗ Branch 161 → 273 not taken.
|
645 | doAssignment(itemAddress, itemEntry, itemResult, itemRefSTy, node, true); |
| 202 | } | ||
| 203 | // Visit body | ||
| 204 |
1/2✓ Branch 163 → 164 taken 650 times.
✗ Branch 163 → 274 not taken.
|
650 | visit(node->body); |
| 205 | // Create jump from body to tail block | ||
| 206 |
1/2✓ Branch 165 → 166 taken 650 times.
✗ Branch 165 → 279 not taken.
|
650 | insertJump(bTail); |
| 207 | |||
| 208 | // Switch to tail block | ||
| 209 |
1/2✓ Branch 166 → 167 taken 650 times.
✗ Branch 166 → 279 not taken.
|
650 | switchToBlock(bTail); |
| 210 |
1/2✓ Branch 167 → 168 taken 650 times.
✗ Branch 167 → 279 not taken.
|
650 | diGenerator.setSourceLocation(node); |
| 211 | // Call .next() on iterator | ||
| 212 |
1/2✗ Branch 168 → 169 not taken.
✓ Branch 168 → 170 taken 650 times.
|
650 | assert(node->nextFct); |
| 213 |
1/2✓ Branch 170 → 171 taken 650 times.
✗ Branch 170 → 279 not taken.
|
650 | llvm::Function *nextFct = stdFunctionManager.getIteratorNextFct(node->nextFct); |
| 214 |
4/8✓ Branch 171 → 172 taken 650 times.
✗ Branch 171 → 277 not taken.
✓ Branch 173 → 174 taken 650 times.
✗ Branch 173 → 275 not taken.
✓ Branch 174 → 175 taken 650 times.
✗ Branch 174 → 275 not taken.
✓ Branch 175 → 176 taken 650 times.
✗ Branch 175 → 279 not taken.
|
650 | builder.CreateCall(nextFct, iteratorPtr); |
| 215 | // Create jump from tail to head block | ||
| 216 |
1/2✓ Branch 175 → 176 taken 650 times.
✗ Branch 175 → 279 not taken.
|
650 | insertJump(bHead); |
| 217 | |||
| 218 | // Switch to exit block | ||
| 219 |
1/2✓ Branch 176 → 177 taken 650 times.
✗ Branch 176 → 279 not taken.
|
650 | switchToBlock(bExit); |
| 220 | |||
| 221 | // Pop break/continue targets | ||
| 222 |
1/2✗ Branch 178 → 179 not taken.
✓ Branch 178 → 180 taken 650 times.
|
650 | assert(breakTargets.back().block == bExit); |
| 223 | 650 | breakTargets.pop_back(); | |
| 224 |
1/2✗ Branch 182 → 183 not taken.
✓ Branch 182 → 184 taken 650 times.
|
650 | assert(continueTargets.back().block == bTail); |
| 225 | 650 | continueTargets.pop_back(); | |
| 226 | |||
| 227 |
1/2✓ Branch 185 → 186 taken 650 times.
✗ Branch 185 → 278 not taken.
|
1300 | return nullptr; |
| 228 | 650 | } | |
| 229 | |||
| 230 | 2763 | std::any IRGenerator::visitWhileLoop(const WhileLoopNode *node) { | |
| 231 | // Create blocks | ||
| 232 |
1/2✓ Branch 2 → 3 taken 2763 times.
✗ Branch 2 → 59 not taken.
|
2763 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 233 |
2/4✓ Branch 3 → 4 taken 2763 times.
✗ Branch 3 → 42 not taken.
✓ Branch 4 → 5 taken 2763 times.
✗ Branch 4 → 40 not taken.
|
2763 | llvm::BasicBlock *bHead = createBlock("while.head." + codeLine); |
| 234 |
2/4✓ Branch 6 → 7 taken 2763 times.
✗ Branch 6 → 45 not taken.
✓ Branch 7 → 8 taken 2763 times.
✗ Branch 7 → 43 not taken.
|
2763 | llvm::BasicBlock *bBody = createBlock("while.body." + codeLine); |
| 235 |
2/4✓ Branch 9 → 10 taken 2763 times.
✗ Branch 9 → 48 not taken.
✓ Branch 10 → 11 taken 2763 times.
✗ Branch 10 → 46 not taken.
|
2763 | llvm::BasicBlock *bExit = createBlock("while.exit." + codeLine); |
| 236 | |||
| 237 | // Change scope | ||
| 238 |
2/4✓ Branch 12 → 13 taken 2763 times.
✗ Branch 12 → 51 not taken.
✓ Branch 13 → 14 taken 2763 times.
✗ Branch 13 → 49 not taken.
|
2763 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::WHILE_BODY, node); |
| 239 | |||
| 240 | // Save the break/continue targets, paired with the scope to clean up to when jumping there | ||
| 241 |
1/2✓ Branch 15 → 16 taken 2763 times.
✗ Branch 15 → 55 not taken.
|
2763 | breakTargets.emplace_back(currentScope, bExit); |
| 242 |
1/2✓ Branch 16 → 17 taken 2763 times.
✗ Branch 16 → 55 not taken.
|
2763 | continueTargets.emplace_back(currentScope, bHead); |
| 243 | |||
| 244 | // Jump to head block | ||
| 245 |
1/2✓ Branch 17 → 18 taken 2763 times.
✗ Branch 17 → 55 not taken.
|
2763 | insertJump(bHead); |
| 246 | |||
| 247 | // Switch to head block | ||
| 248 |
1/2✓ Branch 18 → 19 taken 2763 times.
✗ Branch 18 → 55 not taken.
|
2763 | switchToBlock(bHead); |
| 249 | // Evaluate condition | ||
| 250 |
1/2✓ Branch 19 → 20 taken 2763 times.
✗ Branch 19 → 55 not taken.
|
2763 | llvm::Value *condValue = resolveValueInExprScope(node->condition); |
| 251 | // Jump to body or exit block, depending on the condition | ||
| 252 |
1/2✓ Branch 20 → 21 taken 2763 times.
✗ Branch 20 → 55 not taken.
|
2763 | insertCondJump(condValue, bBody, bExit); |
| 253 | |||
| 254 | // Switch to body block | ||
| 255 |
1/2✓ Branch 21 → 22 taken 2763 times.
✗ Branch 21 → 55 not taken.
|
2763 | switchToBlock(bBody); |
| 256 | // Visit body | ||
| 257 |
1/2✓ Branch 22 → 23 taken 2763 times.
✗ Branch 22 → 53 not taken.
|
2763 | visit(node->body); |
| 258 | // Create jump to head block | ||
| 259 |
1/2✓ Branch 24 → 25 taken 2763 times.
✗ Branch 24 → 55 not taken.
|
2763 | insertJump(bHead); |
| 260 | |||
| 261 | // Switch to exit block | ||
| 262 |
1/2✓ Branch 25 → 26 taken 2763 times.
✗ Branch 25 → 55 not taken.
|
2763 | switchToBlock(bExit); |
| 263 | |||
| 264 | // Pop break/continue targets | ||
| 265 |
1/2✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 2763 times.
|
2763 | assert(breakTargets.back().block == bExit); |
| 266 | 2763 | breakTargets.pop_back(); | |
| 267 |
1/2✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 2763 times.
|
2763 | assert(continueTargets.back().block == bHead); |
| 268 | 2763 | continueTargets.pop_back(); | |
| 269 | |||
| 270 |
1/2✓ Branch 34 → 35 taken 2763 times.
✗ Branch 34 → 54 not taken.
|
5526 | return nullptr; |
| 271 | 2763 | } | |
| 272 | |||
| 273 | 119 | std::any IRGenerator::visitDoWhileLoop(const DoWhileLoopNode *node) { | |
| 274 | // Create blocks | ||
| 275 |
1/2✓ Branch 2 → 3 taken 119 times.
✗ Branch 2 → 59 not taken.
|
119 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 276 |
2/4✓ Branch 3 → 4 taken 119 times.
✗ Branch 3 → 42 not taken.
✓ Branch 4 → 5 taken 119 times.
✗ Branch 4 → 40 not taken.
|
119 | llvm::BasicBlock *bBody = createBlock("dowhile.body." + codeLine); |
| 277 |
2/4✓ Branch 6 → 7 taken 119 times.
✗ Branch 6 → 45 not taken.
✓ Branch 7 → 8 taken 119 times.
✗ Branch 7 → 43 not taken.
|
119 | llvm::BasicBlock *bFoot = createBlock("dowhile.foot." + codeLine); |
| 278 |
2/4✓ Branch 9 → 10 taken 119 times.
✗ Branch 9 → 48 not taken.
✓ Branch 10 → 11 taken 119 times.
✗ Branch 10 → 46 not taken.
|
119 | llvm::BasicBlock *bExit = createBlock("dowhile.exit." + codeLine); |
| 279 | |||
| 280 | // Change scope | ||
| 281 |
2/4✓ Branch 12 → 13 taken 119 times.
✗ Branch 12 → 51 not taken.
✓ Branch 13 → 14 taken 119 times.
✗ Branch 13 → 49 not taken.
|
119 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::WHILE_BODY, node); |
| 282 | |||
| 283 | // Save the break/continue targets, paired with the scope to clean up to when jumping there | ||
| 284 |
1/2✓ Branch 15 → 16 taken 119 times.
✗ Branch 15 → 55 not taken.
|
119 | breakTargets.emplace_back(currentScope, bExit); |
| 285 |
1/2✓ Branch 16 → 17 taken 119 times.
✗ Branch 16 → 55 not taken.
|
119 | continueTargets.emplace_back(currentScope, bFoot); |
| 286 | |||
| 287 | // Jump to body block | ||
| 288 |
1/2✓ Branch 17 → 18 taken 119 times.
✗ Branch 17 → 55 not taken.
|
119 | insertJump(bBody); |
| 289 | |||
| 290 | // Switch to body block | ||
| 291 |
1/2✓ Branch 18 → 19 taken 119 times.
✗ Branch 18 → 55 not taken.
|
119 | switchToBlock(bBody); |
| 292 | // Visit body | ||
| 293 |
1/2✓ Branch 19 → 20 taken 119 times.
✗ Branch 19 → 53 not taken.
|
119 | visit(node->body); |
| 294 | // Create jump to foot block | ||
| 295 |
1/2✓ Branch 21 → 22 taken 119 times.
✗ Branch 21 → 55 not taken.
|
119 | insertJump(bFoot); |
| 296 | |||
| 297 | // Switch to head block | ||
| 298 |
1/2✓ Branch 22 → 23 taken 119 times.
✗ Branch 22 → 55 not taken.
|
119 | switchToBlock(bFoot); |
| 299 | // Evaluate condition | ||
| 300 |
1/2✓ Branch 23 → 24 taken 119 times.
✗ Branch 23 → 55 not taken.
|
119 | llvm::Value *condValue = resolveValueInExprScope(node->condition); |
| 301 | // Jump to body or exit block, depending on the condition | ||
| 302 |
1/2✓ Branch 24 → 25 taken 119 times.
✗ Branch 24 → 55 not taken.
|
119 | insertCondJump(condValue, bBody, bExit); |
| 303 | |||
| 304 | // Switch to exit block | ||
| 305 |
1/2✓ Branch 25 → 26 taken 119 times.
✗ Branch 25 → 55 not taken.
|
119 | switchToBlock(bExit); |
| 306 | |||
| 307 | // Pop break/continue targets | ||
| 308 |
1/2✗ Branch 27 → 28 not taken.
✓ Branch 27 → 29 taken 119 times.
|
119 | assert(breakTargets.back().block == bExit); |
| 309 | 119 | breakTargets.pop_back(); | |
| 310 |
1/2✗ Branch 31 → 32 not taken.
✓ Branch 31 → 33 taken 119 times.
|
119 | assert(continueTargets.back().block == bFoot); |
| 311 | 119 | continueTargets.pop_back(); | |
| 312 | |||
| 313 |
1/2✓ Branch 34 → 35 taken 119 times.
✗ Branch 34 → 54 not taken.
|
238 | return nullptr; |
| 314 | 119 | } | |
| 315 | |||
| 316 | 38534 | std::any IRGenerator::visitIfStmt(const IfStmtNode *node) { | |
| 317 | // If we have a compile time decision, only evaluate the respective branch | ||
| 318 |
8/10✓ Branch 2 → 3 taken 38534 times.
✗ Branch 2 → 104 not taken.
✓ Branch 3 → 4 taken 38310 times.
✓ Branch 3 → 7 taken 224 times.
✓ Branch 4 → 5 taken 38310 times.
✗ Branch 4 → 104 not taken.
✓ Branch 5 → 6 taken 346 times.
✓ Branch 5 → 7 taken 37964 times.
✓ Branch 8 → 9 taken 346 times.
✓ Branch 8 → 19 taken 38188 times.
|
38534 | if (node->doCompileThenBranch(manIdx) && !node->doCompileElseBranch(manIdx)) { |
| 319 |
2/4✓ Branch 9 → 10 taken 346 times.
✗ Branch 9 → 75 not taken.
✓ Branch 10 → 11 taken 346 times.
✗ Branch 10 → 73 not taken.
|
346 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::IF_ELSE_BODY, node); |
| 320 |
1/2✓ Branch 12 → 13 taken 346 times.
✗ Branch 12 → 77 not taken.
|
346 | visit(node->thenBody); |
| 321 |
2/4✓ Branch 14 → 15 taken 346 times.
✗ Branch 14 → 78 not taken.
✓ Branch 15 → 16 taken 346 times.
✗ Branch 15 → 78 not taken.
|
346 | return builder.getTrue(); |
| 322 | 346 | } | |
| 323 |
7/10✓ Branch 19 → 20 taken 38188 times.
✗ Branch 19 → 104 not taken.
✓ Branch 20 → 21 taken 224 times.
✓ Branch 20 → 24 taken 37964 times.
✓ Branch 21 → 22 taken 224 times.
✗ Branch 21 → 104 not taken.
✓ Branch 22 → 23 taken 224 times.
✗ Branch 22 → 24 not taken.
✓ Branch 25 → 26 taken 224 times.
✓ Branch 25 → 34 taken 37964 times.
|
38188 | if (!node->doCompileThenBranch(manIdx) && node->doCompileElseBranch(manIdx)) { |
| 324 |
2/2✓ Branch 26 → 27 taken 4 times.
✓ Branch 26 → 30 taken 220 times.
|
224 | if (node->elseStmt) |
| 325 |
1/2✓ Branch 27 → 28 taken 4 times.
✗ Branch 27 → 82 not taken.
|
4 | visit(node->elseStmt); |
| 326 |
2/4✓ Branch 30 → 31 taken 224 times.
✗ Branch 30 → 83 not taken.
✓ Branch 31 → 32 taken 224 times.
✗ Branch 31 → 83 not taken.
|
448 | return builder.getFalse(); |
| 327 | } | ||
| 328 | |||
| 329 | // Create blocks | ||
| 330 |
1/2✓ Branch 34 → 35 taken 37964 times.
✗ Branch 34 → 104 not taken.
|
37964 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 331 |
2/4✓ Branch 35 → 36 taken 37964 times.
✗ Branch 35 → 86 not taken.
✓ Branch 36 → 37 taken 37964 times.
✗ Branch 36 → 84 not taken.
|
37964 | llvm::BasicBlock *bThen = createBlock("if.then." + codeLine); |
| 332 |
6/10✓ Branch 38 → 39 taken 2081 times.
✓ Branch 38 → 42 taken 35883 times.
✓ Branch 39 → 40 taken 2081 times.
✗ Branch 39 → 87 not taken.
✓ Branch 40 → 41 taken 2081 times.
✗ Branch 40 → 87 not taken.
✓ Branch 43 → 44 taken 2081 times.
✓ Branch 43 → 45 taken 35883 times.
✗ Branch 87 → 88 not taken.
✗ Branch 87 → 89 not taken.
|
37964 | llvm::BasicBlock *bElse = node->elseStmt ? createBlock("if.else." + codeLine) : nullptr; |
| 333 |
2/4✓ Branch 45 → 46 taken 37964 times.
✗ Branch 45 → 93 not taken.
✓ Branch 46 → 47 taken 37964 times.
✗ Branch 46 → 91 not taken.
|
37964 | llvm::BasicBlock *bExit = createBlock("if.exit." + codeLine); |
| 334 | |||
| 335 | // Change scope | ||
| 336 |
2/4✓ Branch 48 → 49 taken 37964 times.
✗ Branch 48 → 96 not taken.
✓ Branch 49 → 50 taken 37964 times.
✗ Branch 49 → 94 not taken.
|
37964 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::IF_ELSE_BODY, node); |
| 337 | |||
| 338 | // Retrieve condition value | ||
| 339 |
1/2✓ Branch 51 → 52 taken 37964 times.
✗ Branch 51 → 100 not taken.
|
37964 | llvm::Value *condValue = resolveValueInExprScope(node->condition); |
| 340 | // Check if condition is fulfilled | ||
| 341 |
3/4✓ Branch 52 → 53 taken 2081 times.
✓ Branch 52 → 54 taken 35883 times.
✓ Branch 55 → 56 taken 37964 times.
✗ Branch 55 → 100 not taken.
|
37964 | insertCondJump(condValue, bThen, node->elseStmt ? bElse : bExit); |
| 342 | |||
| 343 | // Switch to then block | ||
| 344 |
1/2✓ Branch 56 → 57 taken 37964 times.
✗ Branch 56 → 100 not taken.
|
37964 | switchToBlock(bThen); |
| 345 | // Visit then body | ||
| 346 |
1/2✓ Branch 57 → 58 taken 37964 times.
✗ Branch 57 → 98 not taken.
|
37964 | visit(node->thenBody); |
| 347 | // Create jump from then to end block | ||
| 348 |
1/2✓ Branch 59 → 60 taken 37964 times.
✗ Branch 59 → 100 not taken.
|
37964 | insertJump(bExit); |
| 349 | |||
| 350 | // Change scope back | ||
| 351 |
1/2✓ Branch 60 → 61 taken 37964 times.
✗ Branch 60 → 100 not taken.
|
37964 | scopeHandle.leaveScopeEarly(); |
| 352 | |||
| 353 |
2/2✓ Branch 61 → 62 taken 2081 times.
✓ Branch 61 → 66 taken 35883 times.
|
37964 | if (node->elseStmt) { |
| 354 | // Switch to else block | ||
| 355 |
1/2✓ Branch 62 → 63 taken 2081 times.
✗ Branch 62 → 100 not taken.
|
2081 | switchToBlock(bElse); |
| 356 | // Visit else block | ||
| 357 |
1/2✓ Branch 63 → 64 taken 2081 times.
✗ Branch 63 → 99 not taken.
|
2081 | visit(node->elseStmt); |
| 358 | // Create jump from else to end block | ||
| 359 |
1/2✓ Branch 65 → 66 taken 2081 times.
✗ Branch 65 → 100 not taken.
|
2081 | insertJump(bExit); |
| 360 | } | ||
| 361 | |||
| 362 | // Switch to exit block | ||
| 363 |
1/2✓ Branch 66 → 67 taken 37964 times.
✗ Branch 66 → 100 not taken.
|
37964 | switchToBlock(bExit); |
| 364 | |||
| 365 | // Return conditional value as result for the 'if' stmt | ||
| 366 |
1/2✓ Branch 67 → 68 taken 37964 times.
✗ Branch 67 → 100 not taken.
|
37964 | return condValue; |
| 367 | 37964 | } | |
| 368 | |||
| 369 | 2085 | std::any IRGenerator::visitElseStmt(const ElseStmtNode *node) { | |
| 370 |
2/2✓ Branch 2 → 3 taken 919 times.
✓ Branch 2 → 6 taken 1166 times.
|
2085 | if (node->ifStmt) { // It is an else if branch |
| 371 |
1/2✓ Branch 3 → 4 taken 919 times.
✗ Branch 3 → 17 not taken.
|
919 | visit(node->ifStmt); |
| 372 | } else { // It is an else branch | ||
| 373 | // Change scope | ||
| 374 |
2/4✓ Branch 6 → 7 taken 1166 times.
✗ Branch 6 → 20 not taken.
✓ Branch 7 → 8 taken 1166 times.
✗ Branch 7 → 18 not taken.
|
1166 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::IF_ELSE_BODY, node); |
| 375 | |||
| 376 | // Generate IR for nested statements | ||
| 377 |
1/2✓ Branch 9 → 10 taken 1166 times.
✗ Branch 9 → 22 not taken.
|
1166 | visit(node->body); |
| 378 | 1166 | } | |
| 379 | |||
| 380 |
1/2✓ Branch 13 → 14 taken 2085 times.
✗ Branch 13 → 26 not taken.
|
4170 | return nullptr; |
| 381 | } | ||
| 382 | |||
| 383 | 41 | std::any IRGenerator::visitSwitchStmt(const SwitchStmtNode *node) { | |
| 384 | // Create blocks | ||
| 385 | 41 | std::vector<llvm::BasicBlock *> bCases; | |
| 386 |
1/2✓ Branch 3 → 4 taken 41 times.
✗ Branch 3 → 122 not taken.
|
41 | bCases.reserve(node->caseBranches.size()); |
| 387 |
2/2✓ Branch 23 → 6 taken 305 times.
✓ Branch 23 → 24 taken 41 times.
|
387 | for (const auto caseBranch : node->caseBranches) |
| 388 |
4/8✓ Branch 8 → 9 taken 305 times.
✗ Branch 8 → 98 not taken.
✓ Branch 9 → 10 taken 305 times.
✗ Branch 9 → 96 not taken.
✓ Branch 10 → 11 taken 305 times.
✗ Branch 10 → 94 not taken.
✓ Branch 11 → 12 taken 305 times.
✗ Branch 11 → 94 not taken.
|
305 | bCases.push_back(createBlock("switch.case." + caseBranch->codeLoc.toPrettyLine())); |
| 389 | 41 | llvm::BasicBlock *bDefault = nullptr; | |
| 390 |
2/2✓ Branch 24 → 25 taken 25 times.
✓ Branch 24 → 31 taken 16 times.
|
41 | if (node->hasDefaultBranch) |
| 391 |
3/6✓ Branch 25 → 26 taken 25 times.
✗ Branch 25 → 106 not taken.
✓ Branch 26 → 27 taken 25 times.
✗ Branch 26 → 104 not taken.
✓ Branch 27 → 28 taken 25 times.
✗ Branch 27 → 102 not taken.
|
25 | bDefault = createBlock("switch.default." + node->defaultBranch->codeLoc.toPrettyLine()); |
| 392 |
1/2✓ Branch 31 → 32 taken 41 times.
✗ Branch 31 → 122 not taken.
|
41 | const std::string codeLine = node->codeLoc.toPrettyLine(); |
| 393 |
2/4✓ Branch 32 → 33 taken 41 times.
✗ Branch 32 → 110 not taken.
✓ Branch 33 → 34 taken 41 times.
✗ Branch 33 → 108 not taken.
|
41 | llvm::BasicBlock *bExit = createBlock("switch.exit." + codeLine); |
| 394 | |||
| 395 | // Save the break target. The scope to clean up to is set by each case/default branch as it is visited below, | ||
| 396 | // since it changes per branch (there is no single scope spanning the whole switch statement). | ||
| 397 |
1/2✓ Branch 35 → 36 taken 41 times.
✗ Branch 35 → 111 not taken.
|
41 | breakTargets.emplace_back(nullptr, bExit); |
| 398 | |||
| 399 | // Visit switch expression | ||
| 400 |
1/2✓ Branch 36 → 37 taken 41 times.
✗ Branch 36 → 120 not taken.
|
41 | llvm::Value *exprValue = resolveValue(node->assignExpr); |
| 401 | |||
| 402 | // Generate switch instruction | ||
| 403 |
3/4✓ Branch 38 → 39 taken 25 times.
✓ Branch 38 → 40 taken 16 times.
✓ Branch 41 → 42 taken 41 times.
✗ Branch 41 → 120 not taken.
|
41 | llvm::SwitchInst *switchInst = builder.CreateSwitch(exprValue, bDefault ? bDefault : bExit, node->caseBranches.size()); |
| 404 | |||
| 405 | // Generate case branches | ||
| 406 |
2/2✓ Branch 77 → 43 taken 305 times.
✓ Branch 77 → 78 taken 41 times.
|
346 | for (size_t i = 0; i < node->caseBranches.size(); i++) { |
| 407 |
1/2✓ Branch 43 → 44 taken 305 times.
✗ Branch 43 → 117 not taken.
|
305 | const CaseBranchNode *caseBranch = node->caseBranches.at(i); |
| 408 | |||
| 409 | // Push fallthrough block | ||
| 410 | 305 | llvm::BasicBlock *bFallthrough = bDefault; | |
| 411 |
2/2✓ Branch 45 → 46 taken 264 times.
✓ Branch 45 → 48 taken 41 times.
|
305 | if (i + 1 < node->caseBranches.size()) |
| 412 |
1/2✓ Branch 46 → 47 taken 264 times.
✗ Branch 46 → 117 not taken.
|
264 | bFallthrough = bCases.at(i + 1); |
| 413 |
1/2✓ Branch 48 → 49 taken 305 times.
✗ Branch 48 → 117 not taken.
|
305 | fallthroughBlocks.push(bFallthrough); |
| 414 | |||
| 415 | // Switch to case block | ||
| 416 |
2/4✓ Branch 49 → 50 taken 305 times.
✗ Branch 49 → 117 not taken.
✓ Branch 50 → 51 taken 305 times.
✗ Branch 50 → 117 not taken.
|
305 | switchToBlock(bCases.at(i)); |
| 417 | |||
| 418 | // Visit case body | ||
| 419 |
1/2✓ Branch 51 → 52 taken 305 times.
✗ Branch 51 → 112 not taken.
|
305 | visit(caseBranch); |
| 420 | |||
| 421 | // Create jump from case to exit block | ||
| 422 |
1/2✓ Branch 53 → 54 taken 305 times.
✗ Branch 53 → 117 not taken.
|
305 | insertJump(bExit); |
| 423 | |||
| 424 | // Pop fallthrough block | ||
| 425 |
1/2✓ Branch 54 → 55 taken 305 times.
✗ Branch 54 → 117 not taken.
|
305 | fallthroughBlocks.pop(); |
| 426 | |||
| 427 | // Add case to switch instruction | ||
| 428 |
2/2✓ Branch 74 → 57 taken 315 times.
✓ Branch 74 → 75 taken 305 times.
|
925 | for (const CaseConstantNode *caseConstantNode : caseBranch->caseConstants) { |
| 429 |
2/4✓ Branch 59 → 60 taken 315 times.
✗ Branch 59 → 115 not taken.
✓ Branch 60 → 61 taken 315 times.
✗ Branch 60 → 113 not taken.
|
315 | const auto caseValue = std::any_cast<llvm::Constant *>(visit(caseConstantNode)); |
| 430 |
3/6✓ Branch 62 → 63 taken 315 times.
✗ Branch 62 → 116 not taken.
✓ Branch 63 → 64 taken 315 times.
✗ Branch 63 → 116 not taken.
✓ Branch 64 → 65 taken 315 times.
✗ Branch 64 → 116 not taken.
|
315 | switchInst->addCase(llvm::cast<llvm::ConstantInt>(caseValue), bCases.at(i)); |
| 431 | } | ||
| 432 | } | ||
| 433 | |||
| 434 | // Generate default branch | ||
| 435 |
2/2✓ Branch 78 → 79 taken 25 times.
✓ Branch 78 → 83 taken 16 times.
|
41 | if (node->hasDefaultBranch) { |
| 436 | // Switch to default block | ||
| 437 |
1/2✓ Branch 79 → 80 taken 25 times.
✗ Branch 79 → 120 not taken.
|
25 | switchToBlock(bDefault); |
| 438 | |||
| 439 | // Visit default body | ||
| 440 |
1/2✓ Branch 80 → 81 taken 25 times.
✗ Branch 80 → 118 not taken.
|
25 | visit(node->defaultBranch); |
| 441 | |||
| 442 | // Create jump from default to exit block | ||
| 443 |
1/2✓ Branch 82 → 83 taken 25 times.
✗ Branch 82 → 120 not taken.
|
25 | insertJump(bExit); |
| 444 | } | ||
| 445 | |||
| 446 | // Switch to exit block | ||
| 447 |
1/2✓ Branch 83 → 84 taken 41 times.
✗ Branch 83 → 120 not taken.
|
41 | switchToBlock(bExit); |
| 448 | |||
| 449 | // Pop break target | ||
| 450 |
1/2✗ Branch 85 → 86 not taken.
✓ Branch 85 → 87 taken 41 times.
|
41 | assert(breakTargets.back().block == bExit); |
| 451 | 41 | breakTargets.pop_back(); | |
| 452 | |||
| 453 |
1/2✓ Branch 88 → 89 taken 41 times.
✗ Branch 88 → 119 not taken.
|
82 | return nullptr; |
| 454 | 41 | } | |
| 455 | |||
| 456 | 305 | std::any IRGenerator::visitCaseBranch(const CaseBranchNode *node) { | |
| 457 | // Change to case body scope | ||
| 458 |
2/4✓ Branch 2 → 3 taken 305 times.
✗ Branch 2 → 15 not taken.
✓ Branch 3 → 4 taken 305 times.
✗ Branch 3 → 13 not taken.
|
305 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::CASE_BODY); |
| 459 | |||
| 460 | // A 'break' within this branch targets the enclosing switch; point it at this branch's own scope | ||
| 461 | 305 | breakTargets.back().scope = currentScope; | |
| 462 | |||
| 463 | // Visit case body | ||
| 464 |
1/2✓ Branch 6 → 7 taken 305 times.
✗ Branch 6 → 17 not taken.
|
305 | visit(node->body); |
| 465 | |||
| 466 |
1/2✓ Branch 8 → 9 taken 305 times.
✗ Branch 8 → 18 not taken.
|
610 | return nullptr; |
| 467 | 305 | } | |
| 468 | |||
| 469 | 25 | std::any IRGenerator::visitDefaultBranch(const DefaultBranchNode *node) { | |
| 470 | // Change to default body scope | ||
| 471 |
2/4✓ Branch 2 → 3 taken 25 times.
✗ Branch 2 → 15 not taken.
✓ Branch 3 → 4 taken 25 times.
✗ Branch 3 → 13 not taken.
|
25 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::DEFAULT_BODY); |
| 472 | |||
| 473 | // A 'break' within this branch targets the enclosing switch; point it at this branch's own scope | ||
| 474 | 25 | breakTargets.back().scope = currentScope; | |
| 475 | |||
| 476 | // Visit case body | ||
| 477 |
1/2✓ Branch 6 → 7 taken 25 times.
✗ Branch 6 → 17 not taken.
|
25 | visit(node->body); |
| 478 | |||
| 479 |
1/2✓ Branch 8 → 9 taken 25 times.
✗ Branch 8 → 18 not taken.
|
50 | return nullptr; |
| 480 | 25 | } | |
| 481 | |||
| 482 | 177 | std::any IRGenerator::visitAnonymousBlockStmt(const AnonymousBlockStmtNode *node) { | |
| 483 | // Change scope | ||
| 484 | 177 | node->bodyScope->parent = currentScope; // Needed for nested scopes in generic functions | |
| 485 | 177 | node->bodyScope->symbolTable.parent = ¤tScope->symbolTable; // Needed for nested scopes in generic functions | |
| 486 |
2/4✓ Branch 2 → 3 taken 177 times.
✗ Branch 2 → 14 not taken.
✓ Branch 3 → 4 taken 177 times.
✗ Branch 3 → 12 not taken.
|
177 | ScopeHandle scopeHandle(this, node->getScopeId(), ScopeType::ANONYMOUS_BLOCK_BODY, node); |
| 487 | |||
| 488 | // Visit instructions in the block | ||
| 489 |
1/2✓ Branch 5 → 6 taken 177 times.
✗ Branch 5 → 16 not taken.
|
177 | visit(node->body); |
| 490 | |||
| 491 |
1/2✓ Branch 7 → 8 taken 177 times.
✗ Branch 7 → 17 not taken.
|
354 | return nullptr; |
| 492 | 177 | } | |
| 493 | |||
| 494 | } // namespace spice::compiler | ||
| 495 |