compiler: fix stack alignment

This commit is contained in:
sfja 2025-03-27 20:16:56 +01:00
parent 14d5afcaea
commit 43740eb9ee
2 changed files with 25 additions and 30 deletions

View File

@ -108,6 +108,10 @@ export class AsmGen {
this.writeIns(`push rbp`); this.writeIns(`push rbp`);
this.writeIns(`mov rbp, rsp`); this.writeIns(`mov rbp, rsp`);
this.writeIns(`sub rsp, 8`); this.writeIns(`sub rsp, 8`);
// By doing this, we avoid having to maintain 16-byte stack alignment.
this.writeIns(`and rsp, 0xFFFFFFFFFFFFFFF0`);
for (let i = 0; i < args; ++i) { for (let i = 0; i < args; ++i) {
this.writeIns(`mov rax, ${this.relative((i + 2) * 8)}`); this.writeIns(`mov rax, ${this.relative((i + 2) * 8)}`);
this.writeIns(`push rax`); this.writeIns(`push rax`);
@ -130,7 +134,6 @@ export class AsmGen {
this.writeIns(`push rbp`); this.writeIns(`push rbp`);
this.writeIns(`mov rbp, rsp`); this.writeIns(`mov rbp, rsp`);
this.writeIns(`sub rsp, 8`);
const args = fn.mir.paramLocals.size; const args = fn.mir.paramLocals.size;
@ -168,7 +171,7 @@ export class AsmGen {
this.writeIns(`push rbp`); this.writeIns(`push rbp`);
this.writeIns(`mov rbp, rsp`); this.writeIns(`mov rbp, rsp`);
this.writeIns(`sub rsp, ${this.layout.frameSize - 8}`); this.writeIns(`sub rsp, ${this.layout.frameSize}`);
this.writeIns(`jmp .L${fn.mir.entry.id}`); this.writeIns(`jmp .L${fn.mir.entry.id}`);
for (const line of fn.lines.slice(bodyIdx)) { for (const line of fn.lines.slice(bodyIdx)) {
@ -404,6 +407,8 @@ class StackAllocator {
public finalize(): StackLayout { public finalize(): StackLayout {
const regOffsets = new Map<lir.Reg, number>(); const regOffsets = new Map<lir.Reg, number>();
// Last param is at [rbp+8]
// See: https://eli.thegreenplace.net/2011/09/06/stack-frame-layout-on-x86-64
let currentOffset = 8; let currentOffset = 8;
for (const [reg, size] of [...this.paramRegs].toReversed()) { for (const [reg, size] of [...this.paramRegs].toReversed()) {
@ -412,27 +417,17 @@ class StackAllocator {
regOffsets.set(reg, currentOffset); regOffsets.set(reg, currentOffset);
} }
// Start at 8 because rbp is pushed, and // First local is at [rbp-8]
// therefore the *first value*, meaning // See above.
// the return address is at stack[top - 1]. currentOffset = -8;
currentOffset = 8;
let frameSize = 0; let frameSize = 0;
// return address
currentOffset -= 8;
// caller rbp
currentOffset -= 8;
frameSize += 8;
for (const [reg, size] of this.localRegs) { for (const [reg, size] of this.localRegs) {
regOffsets.set(reg, currentOffset); regOffsets.set(reg, currentOffset);
currentOffset -= align8(size); currentOffset -= align8(size);
frameSize += align8(size); frameSize += align8(size);
} }
// frameSize - 8 is safe because frameSize is always >= 8.
frameSize = align(frameSize - 8, 16);
return new StackLayout(frameSize, regOffsets); return new StackLayout(frameSize, regOffsets);
} }
} }

View File

@ -1,8 +1,15 @@
#[c_function("println")] fn main() -> int {
fn println(value: *str) -> int {} let i = 0;
#[c_function("print_int")]
fn print_int(value: int) -> int {} while i < 10 {
print_int(factorial(i));
println("Hello\ world");
i = i + 1;
}
return 0;
}
fn factorial(v: int) -> int { fn factorial(v: int) -> int {
if v == 0 { if v == 0 {
@ -11,17 +18,10 @@ fn factorial(v: int) -> int {
return v * factorial(v - 1); return v * factorial(v - 1);
} }
fn main() -> int { #[c_function("println")]
let i = 0; fn println(value: *str) -> int {}
#[c_function("print_int")]
while i < 10 { fn print_int(value: int) -> int {}
// print_int(i);
println("Hello\ world");
i = i + 1;
}
return 0;
}
#[c_export("sbc_main")] #[c_export("sbc_main")]
fn sbc_main() -> int { fn sbc_main() -> int {