slige/compiler/middle/cfg.ts

108 lines
2.9 KiB
TypeScript
Raw Permalink Normal View History

2025-01-17 06:44:53 +00:00
import { Block, BlockId, Fn } from "./mir.ts";
2025-01-03 00:15:05 +00:00
export function createCfg(fn: Fn): Cfg {
return new CfgBuilder(fn).build();
}
export class Cfg {
public constructor(
private graph: Map<BlockId, CfgNode>,
2025-01-17 06:44:53 +00:00
private entry_: BlockId,
2025-01-03 00:15:05 +00:00
private exit: BlockId,
) {}
2025-01-17 06:44:53 +00:00
public entry(): Block {
return this.graph.get(this.entry_)!.block;
}
2025-01-03 00:15:05 +00:00
public parents(block: Block): Block[] {
return this.graph
.get(block.id)!.parents
.map((id) => this.graph.get(id)!.block);
}
public children(block: Block): Block[] {
return this.graph
.get(block.id)!.children
.map((id) => this.graph.get(id)!.block);
}
public index(block: Block): number {
return this.graph.get(block.id)!.index;
}
public print() {
for (const [id, node] of this.graph.entries()) {
const l = <T>(v: T[]) => v.map((v) => `${v}`).join(", ");
console.log(`graph[${id}] = {`);
console.log(` id: ${node.block.id},`);
console.log(` index: ${node.index},`);
console.log(` parents: [${l(node.parents)}],`);
console.log(` children: [${l(node.children)}],`);
console.log(`}`);
}
}
}
type CfgNode = {
block: Block;
index: number;
parents: BlockId[];
children: BlockId[];
};
class CfgBuilder {
private nodes: [Block, number][] = [];
private edges: [BlockId, BlockId][] = [];
public constructor(private fn: Fn) {}
public build(): Cfg {
for (
const [block, index] of this.fn.blocks
.map((v, i) => [v, i] as const)
) {
this.addNode(block, index);
const tk = block.ter.kind;
switch (tk.type) {
case "error":
break;
case "return":
break;
case "jump":
this.addEdge(block.id, tk.target);
break;
case "if":
this.addEdge(block.id, tk.truthy);
this.addEdge(block.id, tk.falsy);
break;
}
}
const graph = new Map<BlockId, CfgNode>();
for (const [block, index] of this.nodes) {
const parents = this.edges
.filter(([_from, to]) => to === block.id)
.map(([from, _to]) => from);
const children = this.edges
.filter(([from, _to]) => from === block.id)
.map(([_from, to]) => to);
graph.set(block.id, { block, index, parents, children });
}
return new Cfg(graph, this.fn.entry, this.fn.exit);
}
private addNode(block: Block, index: number) {
this.nodes.push([block, index]);
}
private addEdge(from: BlockId, to: BlockId) {
this.edges.push([from, to]);
}
}