diff --git a/sbc/asm_gen.ts b/sbc/asm_gen.ts index d53e23c..e279a73 100644 --- a/sbc/asm_gen.ts +++ b/sbc/asm_gen.ts @@ -168,7 +168,7 @@ export class AsmGen { this.writeIns(`push rbp`); this.writeIns(`mov rbp, rsp`); - this.writeIns(`sub rsp, ${this.layout.frameSize}`); + this.writeIns(`sub rsp, ${this.layout.frameSize - 8}`); this.writeIns(`jmp .L${fn.mir.entry.id}`); for (const line of fn.lines.slice(bodyIdx)) { @@ -422,6 +422,7 @@ class StackAllocator { currentOffset -= 8; // caller rbp currentOffset -= 8; + frameSize += 8; for (const [reg, size] of this.localRegs) { regOffsets.set(reg, currentOffset); diff --git a/sbc/lir_gen.ts b/sbc/lir_gen.ts index a159777..e7474e8 100644 --- a/sbc/lir_gen.ts +++ b/sbc/lir_gen.ts @@ -12,6 +12,10 @@ import * as ast from "./ast.ts"; import * as mir from "./mir.ts"; import { optimizeMirFn } from "./mir_optimize.ts"; +export type LirGenOpts = { + optimize?: boolean; +}; + export class LirGen { private strings = new StringIntern(); @@ -22,6 +26,7 @@ export class LirGen { public constructor( private ast: ast.Stmt[], private mirGen: MirGen, + private opts: LirGenOpts = {}, ) {} public generate(): Program { @@ -30,7 +35,9 @@ export class LirGen { throw new Error("only functions can compile top level"); } const mir = this.mirGen.fnMir(stmt, stmt.kind); - optimizeMirFn(mir); + if (this.opts.optimize !== false) { + optimizeMirFn(mir); + } const id = this.fnIds++; const label = `sbc__${stmt.kind.ident}`; const fn: Fn = { @@ -189,6 +196,16 @@ class FnGen { this.pushIns({ tag: "pop", reg }); this.pushIns({ tag: "call_reg", reg, args: k.args }); this.pushIns({ tag: "kill", reg }); + + const rval = this.reg(); + this.pushIns({ tag: "pop", reg: rval }); + for (let i = 0; i < k.args; ++i) { + const reg = this.reg(); + this.pushIns({ tag: "pop", reg }); + this.pushIns({ tag: "kill", reg }); + } + this.pushIns({ tag: "push", reg: rval }); + this.pushIns({ tag: "kill", reg: rval }); return; } case "lt": diff --git a/sbc/main.ts b/sbc/main.ts index 568279b..eb46dc6 100644 --- a/sbc/main.ts +++ b/sbc/main.ts @@ -17,6 +17,8 @@ async function main() { const re = new Resolver(ast).resolve(); const ch = new Checker(re); + const optimize = true; + const mirGen = new MirGen(re, ch); // console.log("=== MIR ==="); @@ -28,11 +30,15 @@ async function main() { // console.log(new FnStringifyer(fnMir).stringify()); // } - const lir = new LirGen(ast, mirGen).generate(); + const lir = new LirGen(ast, mirGen, { + optimize, + }).generate(); // console.log("=== LIR ==="); // console.log(new ProgramStringifyer(lir).stringify()); - optimizeLir(lir); + if (optimize) { + optimizeLir(lir); + } const asm = new AsmGen(lir).generate(); // console.log("=== ASM ==="); diff --git a/sbc/mir_gen.ts b/sbc/mir_gen.ts index 0ba4476..0973f97 100644 --- a/sbc/mir_gen.ts +++ b/sbc/mir_gen.ts @@ -110,15 +110,18 @@ export class FnMirGen { } case "while": { const entry = this.currentBlock; + const cond = this.block(); - const loop = this.block(); - const exit = this.block(); + this.currentBlock = cond; + this.lowerExpr(k.expr); + const condExit = this.currentBlock; entry.ter = Ter({ tag: "goto", target: cond }); - this.currentBlock = cond; - this.lowerExpr(k.expr); - this.currentBlock.ter = Ter({ + const loop = this.block(); + const exit = this.block(); + + condExit.ter = Ter({ tag: "if", truthy: loop, falsy: exit, @@ -128,7 +131,8 @@ export class FnMirGen { this.currentBlock = loop; this.lowerBlock(k.body); - this.currentBlock.ter = Ter({ tag: "goto", target: cond }); + const loopExit = this.currentBlock; + loopExit.ter = Ter({ tag: "goto", target: cond }); this.currentBlock = exit; return; @@ -136,23 +140,31 @@ export class FnMirGen { case "if": { this.lowerExpr(k.expr); const entry = this.currentBlock; - const exit = this.block(); - const truthy = this.block(); + const truthy = this.block(); this.currentBlock = truthy; this.lowerBlock(k.truthy); - this.currentBlock.ter = Ter({ tag: "goto", target: exit }); + const truthyExit = this.currentBlock; - let falsy = exit; if (k.falsy) { - falsy = this.block(); + const falsy = this.block(); this.currentBlock = falsy; this.lowerBlock(k.falsy); - this.currentBlock.ter = Ter({ tag: "goto", target: exit }); - } + const falsyExit = this.currentBlock; - entry.ter = Ter({ tag: "if", truthy, falsy }); - this.currentBlock = exit; + const exit = this.block(); + truthyExit.ter = Ter({ tag: "goto", target: exit }); + falsyExit.ter = Ter({ tag: "goto", target: exit }); + + entry.ter = Ter({ tag: "if", truthy, falsy }); + this.currentBlock = exit; + } else { + const exit = this.block(); + truthyExit.ter = Ter({ tag: "goto", target: exit }); + + entry.ter = Ter({ tag: "if", truthy, falsy: exit }); + this.currentBlock = exit; + } return; } case "return": { diff --git a/sbc/mir_optimize.ts b/sbc/mir_optimize.ts index edf855b..ff1d18f 100644 --- a/sbc/mir_optimize.ts +++ b/sbc/mir_optimize.ts @@ -2,9 +2,9 @@ import * as ast from "./ast.ts"; import { Block, Fn, FnStringifyer } from "./mir.ts"; export function optimizeMirFn(fn: Fn) { - console.log(`=== OPTIMIZING ${(fn.stmt.kind as ast.FnStmt).ident} ===`); - console.log("=== BEFORE OPTIMIZATION ==="); - console.log(new FnStringifyer(fn).stringify()); + // console.log(`=== OPTIMIZING ${(fn.stmt.kind as ast.FnStmt).ident} ===`); + // console.log("=== BEFORE OPTIMIZATION ==="); + // console.log(new FnStringifyer(fn).stringify()); const blockSize = fn.blocks .map((block) => block.stmts.length) @@ -27,8 +27,8 @@ export function optimizeMirFn(fn: Fn) { sizeHistory.add(sizeBefore); } - console.log("=== AFTER OPTIMIZATION ==="); - console.log(new FnStringifyer(fn).stringify()); + // console.log("=== AFTER OPTIMIZATION ==="); + // console.log(new FnStringifyer(fn).stringify()); } function fnSize(fn: Fn, blockSize: number): number { diff --git a/sbc/program.sbl b/sbc/program.sbl index dee4023..fa55611 100644 --- a/sbc/program.sbl +++ b/sbc/program.sbl @@ -4,16 +4,27 @@ fn println(value: *str) -> int {} #[c_function("print_int")] fn print_int(value: int) -> int {} +fn factorial(v: int) -> int { + if v == 0 { + return 1; + } + return v * factorial(v - 1); +} + #[c_export("sbc_main")] fn main() -> int { let i = 0; - while i < 10 { - - println("Hello\ world"); - - i = i + 1; - } + // while i < 10 { + // + // println("Hello\ world"); + // + // i = i + 1; + // } + + let a = factorial(5); + + print_int(a); return 0; }