136 lines
3.8 KiB
TypeScript
Raw Normal View History

2025-03-24 16:16:43 +01:00
import * as mir from "./mir.ts";
export type Program = {
strings: Map<number, string>;
fns: Fn[];
};
export type Fn = {
id: number;
label: string;
mir: mir.Fn;
lines: Line[];
2025-03-26 16:21:46 +01:00
localRegs: Map<number, Reg>;
2025-03-24 16:16:43 +01:00
};
export type Line = {
labels: Label[];
ins: Ins;
};
export type Ins =
| { tag: "error" }
| { tag: "nop" }
2025-03-26 16:21:46 +01:00
| { tag: "alloc_param"; reg: Reg; size: number }
| { tag: "alloc_local"; reg: Reg; size: number }
2025-03-24 16:16:43 +01:00
| { tag: "mov_int"; reg: Reg; val: number }
| { tag: "mov_string"; reg: Reg; stringId: number }
| { tag: "mov_fn"; reg: Reg; fn: Fn }
| { tag: "push"; reg: Reg }
| { tag: "pop"; reg: Reg }
2025-03-26 22:15:39 +01:00
| { tag: "load"; reg: Reg; sReg: Reg }
| { tag: "store_reg"; sReg: Reg; reg: Reg }
| { tag: "store_imm"; sReg: Reg; val: number }
2025-03-25 10:56:35 +01:00
| { tag: "call_reg"; reg: Reg; args: number }
2025-03-25 15:45:24 +01:00
| { tag: "call_imm"; fn: Fn; args: number }
2025-03-24 16:16:43 +01:00
| { tag: "jmp"; target: Label }
| { tag: "jnz_reg"; reg: Reg; target: Label }
| { tag: "ret" }
2025-03-27 13:56:24 +01:00
| { tag: BinaryOp; dst: Reg; src: Reg }
2025-03-25 10:56:35 +01:00
| { tag: "kill"; reg: Reg };
2025-03-24 16:16:43 +01:00
2025-03-27 13:56:24 +01:00
export type BinaryOp =
| "lt"
| "gt"
| "le"
| "ge"
| "eq"
| "ne"
| "add"
| "sub"
| "mul"
| "div"
| "mod";
2025-03-24 16:16:43 +01:00
export type Reg = number;
export type Label = number;
export class ProgramStringifyer {
public constructor(
private program: Program,
) {}
public stringify(): string {
return this.program.fns
.map((fn) =>
`${fn.label}:\n${
fn.lines
.map((label) =>
`${
label.labels
2025-03-25 15:45:24 +01:00
.map((label) => `.L${label}:\n`)
2025-03-24 16:16:43 +01:00
.join()
} ${this.ins(label.ins)}\n`
)
.join("")
}`
)
.join("");
}
private ins(ins: Ins): string {
switch (ins.tag) {
case "error":
return "<error>";
case "nop":
return "nop";
2025-03-26 16:21:46 +01:00
case "alloc_param":
return `alloc_param %${ins.reg}, ${ins.size}`;
case "alloc_local":
return `alloc_local %${ins.reg}, ${ins.size}`;
2025-03-24 16:16:43 +01:00
case "mov_int":
return `mov_int %${ins.reg}, ${ins.val}`;
case "mov_string":
return `mov_string %${ins.reg}, string+${ins.stringId}`;
case "mov_fn":
return `mov_fn %${ins.reg}, ${ins.fn.label}`;
case "push":
return `push %${ins.reg}`;
case "pop":
return `pop %${ins.reg}`;
case "load":
2025-03-26 22:15:39 +01:00
return `load %${ins.reg}, [%${ins.sReg}]`;
2025-03-25 15:45:24 +01:00
case "store_reg":
2025-03-26 22:15:39 +01:00
return `store_reg [%${ins.sReg}], %${ins.reg}`;
2025-03-25 15:45:24 +01:00
case "store_imm":
2025-03-26 22:15:39 +01:00
return `store_val [%${ins.sReg}], ${ins.val}`;
2025-03-24 16:16:43 +01:00
case "call_reg":
2025-03-25 10:56:35 +01:00
return `call_reg %${ins.reg}, ${ins.args}`;
2025-03-25 15:45:24 +01:00
case "call_imm":
2025-03-25 10:56:35 +01:00
return `call_fn ${ins.fn.label}, ${ins.args}`;
2025-03-24 16:16:43 +01:00
case "jmp":
2025-03-26 12:57:22 +01:00
return `jmp .L${ins.target}`;
2025-03-24 16:16:43 +01:00
case "jnz_reg":
2025-03-26 12:57:22 +01:00
return `jnz_reg %${ins.reg}, .L${ins.target}`;
2025-03-24 16:16:43 +01:00
case "ret":
return "ret";
case "lt":
2025-03-27 13:56:24 +01:00
case "gt":
case "le":
case "ge":
2025-03-24 16:16:43 +01:00
case "eq":
2025-03-27 13:56:24 +01:00
case "ne":
2025-03-24 16:16:43 +01:00
case "add":
2025-03-27 13:56:24 +01:00
case "sub":
case "div":
2025-03-24 16:16:43 +01:00
case "mul":
2025-03-27 13:56:24 +01:00
case "mod":
2025-03-24 16:16:43 +01:00
return `${ins.tag} %${ins.dst}, %${ins.src}`;
2025-03-25 10:56:35 +01:00
case "kill":
return `kill %${ins.reg}`;
2025-03-24 16:16:43 +01:00
}
const _: never = ins;
}
}