()
| 16 | } |
| 17 | |
| 18 | build() { |
| 19 | const cfg = this.strandsContext.cfg; |
| 20 | const mergeBlock = CFG.createBasicBlock(cfg, BlockType.MERGE); |
| 21 | |
| 22 | // Create a BRANCH block to handle phi node declarations |
| 23 | const branchBlock = CFG.createBasicBlock(cfg, BlockType.BRANCH); |
| 24 | CFG.addEdge(cfg, cfg.currentBlock, branchBlock); |
| 25 | CFG.addEdge(cfg, branchBlock, mergeBlock); |
| 26 | |
| 27 | // Initialize loop variable phi node |
| 28 | const { initialVar, phiNode } = this.initializeLoopVariable(cfg, branchBlock); |
| 29 | |
| 30 | // Execute condition and update callbacks to get nodes for analysis |
| 31 | CFG.pushBlock(cfg, cfg.currentBlock); |
| 32 | const loopVarNode = createStrandsNode(phiNode.id, phiNode.dimension, this.strandsContext); |
| 33 | const conditionNode = this.conditionCb(loopVarNode); |
| 34 | const updateResult = this.updateCb(loopVarNode); |
| 35 | CFG.popBlock(cfg); |
| 36 | |
| 37 | // Check if loop has bounded iteration count |
| 38 | const isBounded = this.loopIsBounded(initialVar, conditionNode, updateResult); |
| 39 | |
| 40 | if (isBounded) { |
| 41 | this.buildBoundedLoop(cfg, branchBlock, mergeBlock, initialVar, phiNode, conditionNode, updateResult); |
| 42 | } else { |
| 43 | this.buildUnboundedLoop(cfg, branchBlock, mergeBlock, initialVar, phiNode, conditionNode, updateResult); |
| 44 | } |
| 45 | |
| 46 | // Update the phi nodes created in buildBoundedLoop with actual body results |
| 47 | const finalPhiNodes = this.phiNodesForBody; |
| 48 | CFG.pushBlockForModification(cfg, branchBlock); |
| 49 | for (const [varName, resultNode] of Object.entries(this.bodyResults)) { |
| 50 | if (varName !== 'loopVar' && finalPhiNodes[varName]) { |
| 51 | // Update the phi node's second input to use the actual body result |
| 52 | const phiNodeID = finalPhiNodes[varName].id; |
| 53 | const phiNodeData = DAG.getNodeDataFromID(this.strandsContext.dag, phiNodeID); |
| 54 | // Update the dependsOn array to include the actual body result |
| 55 | if (phiNodeData.dependsOn.length > 1) { |
| 56 | phiNodeData.dependsOn[1] = resultNode.id; |
| 57 | } |
| 58 | if (phiNodeData.phiInputs && phiNodeData.phiInputs.length > 1) { |
| 59 | phiNodeData.phiInputs[1].value = resultNode; |
| 60 | } |
| 61 | } |
| 62 | } |
| 63 | CFG.popBlock(cfg); |
| 64 | |
| 65 | // Create assignment nodes in the branch block for initial values |
| 66 | CFG.pushBlockForModification(cfg, branchBlock); |
| 67 | for (const [varName, initialValueNode] of Object.entries(this.initialVars)) { |
| 68 | if (varName !== 'loopVar' && finalPhiNodes[varName]) { |
| 69 | // Create an assignment statement: phiNode = initialValue |
| 70 | const phiNodeID = finalPhiNodes[varName].id; |
| 71 | const sourceNodeID = initialValueNode.id; |
| 72 | // Create an assignment operation node for the initial value |
| 73 | const assignmentNode = DAG.createNodeData({ |
| 74 | nodeType: NodeType.ASSIGNMENT, |
| 75 | dependsOn: [phiNodeID, sourceNodeID], |
no test coverage detected