mirror of
https://git.sfja.dk/Mikkel/slige.git
synced 2025-01-18 12:46:31 +00:00
82 lines
2.2 KiB
TypeScript
82 lines
2.2 KiB
TypeScript
|
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);
|
||
|
}
|
||
|
}
|