From be04fa1b6e41cd1cc69cee3a65bd7d755f9d2960 Mon Sep 17 00:00:00 2001 From: sfja Date: Wed, 26 Mar 2025 22:15:39 +0100 Subject: [PATCH] compiler: move layout to asm_gen --- sbc/asm_gen.ts | 40 +++++++++++++++--------------------- sbc/attr.ts | 50 +++++++++++++++++++++++++++++++++++++++++++++ sbc/lir.ts | 14 ++++++------- sbc/lir_gen.ts | 42 +++++-------------------------------- sbc/lir_optimize.ts | 6 ++++-- 5 files changed, 82 insertions(+), 70 deletions(-) create mode 100644 sbc/attr.ts diff --git a/sbc/asm_gen.ts b/sbc/asm_gen.ts index c54c77c..dba7b90 100644 --- a/sbc/asm_gen.ts +++ b/sbc/asm_gen.ts @@ -144,24 +144,17 @@ export class AsmGen { } this.layout = allocator.finalize(); + const returnLocalOffset = this.layout + .offset(fn.localRegs.get(fn.mir.returnLocal.id)!); + this.writeln(`${fn.label}:`); this.writeIns(`push rbp`); this.writeIns(`mov rbp, rsp`); - const frameSize = fn.frameSize; - const newFrameSize = this.layout.frameSize; - console.log({ frameSize, newFrameSize }); - - this.writeIns(`sub rsp, ${fn.frameSize}`); + this.writeIns(`sub rsp, ${this.layout.frameSize}`); this.writeIns(`jmp .L${fn.mir.entry.id}`); - const isAlloc = (ins: lir.Ins): boolean => - ins.tag === "alloc_param" || ins.tag === "alloc_local"; - for (const line of fn.lines) { - if (isAlloc(line.ins)) { - continue; - } for (const label of line.labels) { this.writeln(`.L${label}:`); } @@ -169,14 +162,7 @@ export class AsmGen { } this.writeln(`.exit:`); - - const returnLocalOffset = fn.localOffsets.get(fn.mir.returnLocal.id)!; this.writeIns(`mov rax, QWORD ${this.relative(returnLocalOffset)}`); - - const newReturnLocalOffset = this.layout - .offset(fn.localRegs.get(fn.mir.returnLocal.id)!); - console.log({ returnLocalOffset, newReturnLocalOffset }); - this.writeIns(`mov rsp, rbp`); this.writeIns(`pop rbp`); this.writeIns(`ret`); @@ -193,7 +179,8 @@ export class AsmGen { return; case "alloc_param": case "alloc_local": - throw new Error("should not be included"); + // Handled elsewhere. + return; case "mov_int": this.writeIns(`mov ${r(ins.reg)}, ${ins.val}`); return; @@ -211,17 +198,23 @@ export class AsmGen { return; case "load": this.writeIns( - `mov ${r(ins.reg)}, QWORD ${this.relative(ins.offset)}`, + `mov ${r(ins.reg)}, QWORD ${ + this.relative(this.layout.offset(ins.sReg)) + }`, ); return; case "store_reg": this.writeIns( - `mov QWORD ${this.relative(ins.offset)}, ${r(ins.reg)}`, + `mov QWORD ${ + this.relative(this.layout.offset(ins.sReg)) + }, ${r(ins.reg)}`, ); return; case "store_imm": this.writeIns( - `mov QWORD ${this.relative(ins.offset)}, ${ins.val}`, + `mov QWORD ${ + this.relative(this.layout.offset(ins.sReg)) + }, ${ins.val}`, ); return; case "call_reg": @@ -388,7 +381,8 @@ class StackAllocator { frameSize += align8(size); } - frameSize = align(frameSize, 16); + // frameSize - 8 is safe because frameSize is always >= 8. + frameSize = align(frameSize - 8, 16); return new StackLayout(frameSize, regOffsets); } diff --git a/sbc/attr.ts b/sbc/attr.ts new file mode 100644 index 0000000..ef45590 --- /dev/null +++ b/sbc/attr.ts @@ -0,0 +1,50 @@ +import * as ast from "./ast.ts"; + +export class AttrView { + public constructor( + private attrs: ast.Attr[], + ) {} + + public static fromStmt(stmt: ast.Stmt): AttrView { + if (stmt.kind.tag !== "fn") { + throw new Error("invalid statement"); + } + return new AttrView(stmt.kind.attrs); + } + + public has(ident: string): boolean { + return this.attrs + .some((attr) => attr.ident === ident); + } + + public get(ident: string): OneAttrView { + const attr = this.attrs + .find((attr) => attr.ident === ident); + if (!attr) { + throw new Error("not found"); + } + return new OneAttrView(attr); + } +} + +export class OneAttrView { + public constructor( + private attr: ast.Attr, + ) {} + + public get args(): number { + return this.attr.args.length; + } + + public isStr(argIdx: number): boolean { + return this.attr.args[argIdx].kind.tag === "str"; + } + + public strVal(argIdx: number): string { + const arg = this.attr.args[argIdx]; + if (arg.kind.tag !== "str") { + throw new Error("invalid argument expression"); + } + return arg.kind.val; + } +} diff --git a/sbc/lir.ts b/sbc/lir.ts index c3bf897..e141a9c 100644 --- a/sbc/lir.ts +++ b/sbc/lir.ts @@ -10,8 +10,6 @@ export type Fn = { label: string; mir: mir.Fn; lines: Line[]; - frameSize: number; - localOffsets: Map; localRegs: Map; }; @@ -31,9 +29,9 @@ export type Ins = | { tag: "mov_fn"; reg: Reg; fn: Fn } | { tag: "push"; reg: Reg } | { tag: "pop"; reg: Reg } - | { tag: "load"; reg: Reg; offset: number } - | { tag: "store_reg"; offset: number; reg: Reg } - | { tag: "store_imm"; offset: number; val: number } + | { tag: "load"; reg: Reg; sReg: Reg } + | { tag: "store_reg"; sReg: Reg; reg: Reg } + | { tag: "store_imm"; sReg: Reg; val: number } | { tag: "call_reg"; reg: Reg; args: number } | { tag: "call_imm"; fn: Fn; args: number } | { tag: "jmp"; target: Label } @@ -89,11 +87,11 @@ export class ProgramStringifyer { case "pop": return `pop %${ins.reg}`; case "load": - return `load %${ins.reg}, [${ins.offset}]`; + return `load %${ins.reg}, [%${ins.sReg}]`; case "store_reg": - return `store_reg [${ins.offset}], %${ins.reg}`; + return `store_reg [%${ins.sReg}], %${ins.reg}`; case "store_imm": - return `store_val [${ins.offset}], ${ins.val}`; + return `store_val [%${ins.sReg}], ${ins.val}`; case "call_reg": return `call_reg %${ins.reg}, ${ins.args}`; case "call_imm": diff --git a/sbc/lir_gen.ts b/sbc/lir_gen.ts index 8d9661e..aa9231b 100644 --- a/sbc/lir_gen.ts +++ b/sbc/lir_gen.ts @@ -36,8 +36,6 @@ export class LirGen { label, mir, lines: [], - frameSize: 0, - localOffsets: new Map(), localRegs: new Map(), }; this.fns.set(id, fn); @@ -77,7 +75,6 @@ class FnGen { private currentLabels: Label[] = []; - private localOffsets = new Map(); private localRegs = new Map(); public constructor( @@ -92,39 +89,16 @@ class FnGen { this.blockLabels.set(block.id, label); } - let currentOffset = 8 + this.fn.mir.paramLocals.size * 8; - let frameSize = 0; - for (const local of this.fn.mir.paramLocals.values()) { - this.localOffsets.set(local.id, currentOffset); - currentOffset -= 8; - const reg = this.reg(); this.pushIns({ tag: "alloc_param", reg, size: 8 }); + this.localRegs.set(local.id, reg); } - // return address - currentOffset -= 8; - // old rbp - currentOffset -= 8; - // return value - this.localOffsets.set(this.fn.mir.returnLocal.id, currentOffset); - currentOffset -= 8; - frameSize += 8; - { const reg = this.reg(); this.pushIns({ tag: "alloc_local", reg, size: 8 }); this.localRegs.set(this.fn.mir.returnLocal.id, reg); } - - for (const local of this.fn.mir.locals) { - if (this.localOffsets.has(local.id)) { - continue; - } - this.localOffsets.set(local.id, currentOffset); - currentOffset -= 8; - frameSize += 8; - } for (const local of this.fn.mir.locals) { if (this.localRegs.has(local.id)) { continue; @@ -134,12 +108,6 @@ class FnGen { this.localRegs.set(local.id, reg); } - if (frameSize % 16 !== 8) { - frameSize += 8; - } - - this.fn.frameSize = frameSize; - this.fn.localOffsets = this.localOffsets; this.fn.localRegs = this.localRegs; for (const block of this.fn.mir.blocks) { @@ -200,17 +168,17 @@ class FnGen { } case "load": { const reg = this.reg(); - const offset = this.localOffsets.get(k.local.id)!; - this.pushIns({ tag: "load", reg, offset }); + const sReg = this.localRegs.get(k.local.id)!; + this.pushIns({ tag: "load", reg, sReg }); this.pushIns({ tag: "push", reg }); this.pushIns({ tag: "kill", reg }); return; } case "store": { const reg = this.reg(); - const offset = this.localOffsets.get(k.local.id)!; + const sReg = this.localRegs.get(k.local.id)!; this.pushIns({ tag: "pop", reg }); - this.pushIns({ tag: "store_reg", offset, reg }); + this.pushIns({ tag: "store_reg", sReg, reg }); this.pushIns({ tag: "kill", reg }); return; } diff --git a/sbc/lir_optimize.ts b/sbc/lir_optimize.ts index a4f55d6..d4d47fa 100644 --- a/sbc/lir_optimize.ts +++ b/sbc/lir_optimize.ts @@ -145,10 +145,10 @@ function eliminateMovIntStoreReg(fn: Fn) { ) { throw new Error(); } - const offset = storeReg.ins.offset; + const sReg = storeReg.ins.sReg; const val = movInt.ins.val; fn.lines.splice(i + 1, 2); - fn.lines[i].ins = { tag: "store_imm", offset, val }; + fn.lines[i].ins = { tag: "store_imm", sReg, val }; } } @@ -223,8 +223,10 @@ function replaceReg(fn: Fn, cand: Reg, replacement: Reg) { case "load": case "store_reg": ins.reg = r(ins.reg); + ins.sReg = r(ins.sReg); break; case "store_imm": + ins.sReg = r(ins.sReg); break; case "call_reg": ins.reg = r(ins.reg);