mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
compiler: move layout to asm_gen
This commit is contained in:
parent
27c1b3308e
commit
be04fa1b6e
@ -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);
|
||||
}
|
||||
|
50
sbc/attr.ts
Normal file
50
sbc/attr.ts
Normal file
@ -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;
|
||||
}
|
||||
}
|
14
sbc/lir.ts
14
sbc/lir.ts
@ -10,8 +10,6 @@ export type Fn = {
|
||||
label: string;
|
||||
mir: mir.Fn;
|
||||
lines: Line[];
|
||||
frameSize: number;
|
||||
localOffsets: Map<number, number>;
|
||||
|
||||
localRegs: Map<number, Reg>;
|
||||
};
|
||||
@ -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":
|
||||
|
@ -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<number, number>();
|
||||
private localRegs = new Map<number, Reg>();
|
||||
|
||||
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;
|
||||
}
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user