@eagleoutice/flowr
Version:
Static Dataflow Analyzer and Program Slicer for the R Programming Language
81 lines • 2.88 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.convertCfgToBasicBlocks = convertCfgToBasicBlocks;
const control_flow_graph_1 = require("./control-flow-graph");
/** if true, return the target */
function singleOutgoingFd(outgoing) {
if (!outgoing || outgoing.size !== 1) {
return undefined;
}
const next = outgoing.entries().next().value;
if (next?.[1].label === 0 /* CfgEdgeType.Fd */) {
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 (vtx.type !== control_flow_graph_1.CfgVertexType.Block) {
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 => newCfg.getBasicBlock(e)?.id);
const findExits = cfInfo.exitPoints.map(e => newCfg.getBasicBlock(e)?.id);
if (findEntries.some(f => f === undefined) || findExits.some(f => f === undefined)) {
/* 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 (vertex.type === control_flow_graph_1.CfgVertexType.Block) {
return undefined;
}
newGraph.addVertex({
type: control_flow_graph_1.CfgVertexType.Block,
elems: [vertex],
id: 'bb-' + id,
});
}
// promote all edges
for (const [from, outgoing] of existing.edges().entries()) {
for (const [to, edge] of outgoing.entries()) {
newGraph.addEdge('bb-' + from, 'bb-' + to, edge);
}
}
return newGraph;
}
//# sourceMappingURL=cfg-to-basic-blocks.js.map