UNPKG

@eagleoutice/flowr

Version:

Static Dataflow Analyzer and Program Slicer for the R Programming Language

78 lines 3.04 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.convertCfgToBasicBlocks = convertCfgToBasicBlocks; const control_flow_graph_1 = require("./control-flow-graph"); const assert_1 = require("../util/assert"); /** if true, return the target */ function singleOutgoingFd(outgoing) { if (!outgoing || outgoing.size !== 1) { return undefined; } const next = outgoing.entries().next().value; if (control_flow_graph_1.CfgEdge.isFlowDependency(next?.[1])) { return next[0]; } else { return undefined; } } /** * Take a control flow information of a graph without any basic blocks and convert it to a graph with basic blocks. */ function convertCfgToBasicBlocks(cfInfo) { const newCfg = wrapEveryVertexInBasicBlock(cfInfo.graph); if (!newCfg) { return cfInfo; } for (const [id, vtx] of newCfg.vertices(false)) { if (!control_flow_graph_1.CfgVertex.isBlock(vtx)) { continue; } const outgoing = newCfg.outgoingEdges(id); const target = singleOutgoingFd(outgoing); if (target) { const targetIn = newCfg.ingoingEdges(target); if (targetIn && targetIn.size === 1) { newCfg.mergeTwoBasicBlocks(id, target); } } const ingoing = newCfg.ingoingEdges(id); const ingoingTarget = singleOutgoingFd(ingoing); if (ingoingTarget) { const ingoingOut = newCfg.outgoingEdges(ingoingTarget); if (ingoingOut && ingoingOut.size === 1) { newCfg.mergeTwoBasicBlocks(ingoingTarget, id); } } } const findEntries = cfInfo.entryPoints.map(e => control_flow_graph_1.CfgVertex.getId(newCfg.getBasicBlock(e))); const findExits = cfInfo.exitPoints.map(e => control_flow_graph_1.CfgVertex.getId(newCfg.getBasicBlock(e))); if (findEntries.some(assert_1.isUndefined) || findExits.some(assert_1.isUndefined)) { /* something went wrong */ return cfInfo; } return { ...cfInfo, graph: newCfg, entryPoints: findEntries, exitPoints: findExits, }; } /** only returns undefined when the cfg already contains basic blocks */ function wrapEveryVertexInBasicBlock(existing) { const newGraph = new control_flow_graph_1.ControlFlowGraph(); for (const [id, vertex] of existing.vertices(false)) { if (control_flow_graph_1.CfgVertex.isBlock(vertex)) { return undefined; } newGraph.addVertex(control_flow_graph_1.CfgVertex.makeBlock(control_flow_graph_1.CfgVertex.toBasicBlockId(id), [vertex])); } // promote all edges for (const [from, outgoing] of existing.edges().entries()) { for (const [to, edge] of outgoing.entries()) { newGraph.addEdge(control_flow_graph_1.CfgVertex.toBasicBlockId(from), control_flow_graph_1.CfgVertex.toBasicBlockId(to), edge); } } return newGraph; } //# sourceMappingURL=cfg-to-basic-blocks.js.map