slige/compiler/middle/elim_unused_local.ts

82 lines
2.2 KiB
TypeScript
Raw Permalink Normal View History

2025-01-03 01:15:05 +01:00
import { FnStmtKind } from "../ast.ts";
import { Reporter } from "../info.ts";
import {
Block,
Fn,
LocalId,
Mir,
RValue,
visitBlockDsts,
visitBlockSrcs,
} from "./mir.ts";
export function eliminateUnusedLocals(
mir: Mir,
reporter: Reporter,
isPassOne: boolean,
) {
for (const fn of mir.fns) {
new EliminateUnusedLocalsFnPass(fn, reporter, isPassOne).pass();
}
}
class EliminateUnusedLocalsFnPass {
private locals: LocalId[];
public constructor(
private fn: Fn,
private reporter: Reporter,
private isPassOne: boolean,
) {
this.locals = this.fn.locals
.slice(1 + (fn.stmt.kind as FnStmtKind).params.length)
.map((local) => local.id);
}
public pass() {
for (const block of this.fn.blocks) {
this.markLocalsInBlock(block);
}
for (const local of this.locals) {
for (const block of this.fn.blocks) {
this.eliminateLocalInBlock(block, local);
}
}
for (const id of this.locals) {
const local = this.fn.locals.find((local) => local.id === id)!;
if (local.sym?.type === "let" && this.isPassOne) {
this.reporter.reportWarning({
reporter: "analysis mf'er",
msg: `unused let symbol '${local.sym.ident}'`,
pos: local.sym.pos,
});
}
}
this.fn.locals = this.fn.locals
.filter((local) => !this.locals.includes(local.id));
}
private eliminateLocalInBlock(block: Block, local: LocalId) {
const elimIndices: number[] = [];
visitBlockDsts(block, (dst, i) => {
if (dst === local) {
elimIndices.push(i);
}
});
for (const i of elimIndices.toReversed()) {
block.ops.splice(i, 1);
}
}
private markLocalsInBlock(block: Block) {
visitBlockSrcs(block, (src) => this.markUsed(src));
}
private markUsed(local: RValue) {
if (local.type !== "local") {
return;
}
this.locals = this.locals.filter((lid) => lid !== local.id);
}
}