more codegen
Some checks failed
Check / Explore-Gitea-Actions (push) Failing after 8s

This commit is contained in:
sfja 2026-04-17 16:47:04 +02:00
parent bfac7bb765
commit ec84b385d3
5 changed files with 195 additions and 20 deletions

View File

@ -1,14 +1,9 @@
fn add(a: int, b: int) -> int fn main() -> i32
{ {
return a + b; let a = 2;
} let b = a + 5;
return b;
fn main()
{
let sum = add(2, 3);
print_int(sum);
print_int(2 - 3);
} }

View File

@ -52,10 +52,10 @@ class InstructionSelector {
src: Reg.reg(Regs.bp), src: Reg.reg(Regs.bp),
}), }),
); );
entry.push(new Inst({ tag: "PopR", dst: Reg.reg(Regs.bp) })); exit.push(new Inst({ tag: "PopR", dst: Reg.reg(Regs.bp) }));
entry.push(new Inst({ tag: "Ret" })); exit.push(new Inst({ tag: "Ret" }));
return new Fn([entry, ...blocks, exit]); return new Fn(this.fn, [entry, ...blocks, exit]);
} }
private generateFrameLayout() { private generateFrameLayout() {
@ -63,14 +63,14 @@ class InstructionSelector {
const align = (alignment: number) => { const align = (alignment: number) => {
if (offset % alignment != 0) { if (offset % alignment != 0) {
offset += alignment - offset % alignment; offset -= alignment + offset % alignment;
} }
}; };
const pushLocal = (inst: mir.Inst, size: number, alignment: number) => { const pushLocal = (inst: mir.Inst, size: number, alignment: number) => {
align(alignment); align(alignment);
this.locals.set(inst, offset); this.locals.set(inst, offset);
offset += size; offset -= size;
}; };
this.fn.visit({ this.fn.visit({
@ -102,28 +102,93 @@ class InstructionSelector {
}, },
}); });
// c abi requires 16 bit stack alignment,
// might aswell do it here.
align(16); align(16);
this.localsSize = offset; this.localsSize = -offset;
} }
private generateBasicBlock(bb: mir.BasicBlock): Block { private generateBasicBlock(bb: mir.BasicBlock): Block {
const regs = new Map<mir.Inst, Reg>();
const block = new Block(); const block = new Block();
for (const inst of bb.insts) { for (const inst of bb.insts) {
const save = (r: Reg): Reg => {
regs.set(inst, r);
return r;
};
const k = inst.kind; const k = inst.kind;
switch (k.tag) { switch (k.tag) {
case "Alloca": case "Alloca":
save(Reg.temp());
break;
case "Void":
block.push(
new Inst({
tag: "MovRI",
dst: save(Reg.temp()),
imm: 0,
}),
);
break; break;
case "Int": case "Int":
block.push( block.push(
new Inst({ new Inst({
tag: "MovRI", tag: "MovRI",
dst: Reg.reg(Regs.bp), dst: save(Reg.temp()),
imm: k.value, imm: k.value,
}), }),
); );
break; break;
case "Store":
block.push(
new Inst({
tag: "MovMRR",
dst: Reg.reg(Regs.bp),
offset: this.locals.get(k.target)!,
src: regs.get(k.source)!,
}),
);
break;
case "Load":
block.push(
new Inst({
tag: "MovRMR",
dst: save(Reg.temp()),
offset: this.locals.get(k.source)!,
src: Reg.reg(Regs.bp),
}),
);
break;
case "Add":
block.push(
new Inst({
tag: "AddR",
dst_op1: save(regs.get(k.left)!),
op2: regs.get(k.right)!,
}),
);
break;
case "Return":
block.push(
new Inst({
tag: "MovRR",
dst: Reg.reg(Regs.a),
src: regs.get(k.source)!,
}),
);
block.push(
new Inst({
tag: "Jmp",
bb: this.exitBlock,
}),
);
break;
default: default:
console.error(`not implemented (${k.tag})`);
// throw new Error( // throw new Error(
// `not implemented (${k.tag})`, // `not implemented (${k.tag})`,
// ); // );

View File

@ -1,15 +1,18 @@
import * as mir from "../../mir.ts";
export class Module { export class Module {
private fns: Fn[] = []; private fns: Fn[] = [];
} }
export class Fn { export class Fn {
constructor( constructor(
private blocks: Block[] = [], public mirFn: mir.Fn,
public blocks: Block[] = [],
) {} ) {}
} }
export class Block { export class Block {
private insts: Inst[] = []; public insts: Inst[] = [];
push(inst: Inst) { push(inst: Inst) {
this.insts.push(inst); this.insts.push(inst);
@ -38,7 +41,7 @@ export class Reg {
static tempId = 1000; static tempId = 1000;
private constructor( private constructor(
private id: number, public id: number,
) {} ) {}
static reg(reg: Regs): Reg { static reg(reg: Regs): Reg {

View File

@ -50,7 +50,10 @@ if (Deno.args.includes("--print-mir")) {
} }
} }
// const result = selectFnInstructions(mainMiddleFn); const result = selectFnInstructions(mainMiddleFn);
stringify.printWithConsoleColors(
stringify.x86_64FnPretty(result, stringify.consoleColors),
);
// console.log(JSON.stringify(result, null, 4)); // console.log(JSON.stringify(result, null, 4));
if (!reporter.ok()) { if (!reporter.ok()) {

View File

@ -1,5 +1,6 @@
import * as ty from "./ty.ts"; import * as ty from "./ty.ts";
import * as mir from "./mir.ts"; import * as mir from "./mir.ts";
import * as codegenX8664 from "./codegen/x86_64/module.ts";
export type PrettyColors = { export type PrettyColors = {
punctuation: string; punctuation: string;
@ -336,3 +337,111 @@ class MirFnPrettyStringifier {
return id; return id;
} }
} }
export function x86_64FnPretty(fn: codegenX8664.Fn, colors = noColors): string {
const c = colors;
const blockIds = new Map<codegenX8664.Block, number>();
const reg = (reg: codegenX8664.Reg): string => {
const cl = c.typeIdent;
switch (reg.id) {
case codegenX8664.Regs.a:
return `${cl}rax`;
case codegenX8664.Regs.b:
return `${cl}rbx`;
case codegenX8664.Regs.c:
return `${cl}rbc`;
case codegenX8664.Regs.si:
return `${cl}rsi`;
case codegenX8664.Regs.di:
return `${cl}rdi`;
case codegenX8664.Regs.sp:
return `${cl}rsp`;
case codegenX8664.Regs.bp:
return `${cl}rbp`;
case codegenX8664.Regs.r8:
return `${cl}r8`;
case codegenX8664.Regs.r9:
return `${cl}r9`;
case codegenX8664.Regs.r10:
return `${cl}r10`;
case codegenX8664.Regs.r11:
return `${cl}r11`;
case codegenX8664.Regs.r12:
return `${cl}r12`;
case codegenX8664.Regs.r13:
return `${cl}r13`;
case codegenX8664.Regs.r14:
return `${cl}r14`;
case codegenX8664.Regs.r15:
return `${cl}r15`;
default:
return `${c.varIdent}%${reg.id - 1000}`;
}
};
const imm = (v: number): string => {
return `${c.literal}${v}`;
};
const mem = (r: codegenX8664.Reg, off: number): string => {
return `${c.keyword}qword ${c.punctuation}[${reg(r)}${c.punctuation}${
off !== 0 ? `-${c.literal}${-off}${c.punctuation}` : ""
}]`;
};
const line = (op: string, ...ops: string[]): string => {
return ` ${c.operator}${op} ${ops.join(", ")}\n`;
};
for (const block of fn.blocks) {
const id = blockIds.size;
blockIds.set(block, id);
}
let result = "";
result += `${c.fnIdent}${fn.mirFn.stmt.kind.ident}${c.punctuation}:\n`;
for (const block of fn.blocks) {
const id = blockIds.get(block)!;
result += `${c.varIdent}.l${id}${c.punctuation}:\n`;
for (const inst of block.insts) {
const k = inst.kind;
switch (k.tag) {
case "PushR":
result += line("push", reg(k.src));
break;
case "PopR":
result += line("pop", reg(k.dst));
break;
case "MovRR":
result += line("mov", reg(k.dst), reg(k.src));
break;
case "SubRI":
result += line("sub", reg(k.dst), imm(k.imm));
break;
case "MovRI":
result += line("mov", reg(k.dst), imm(k.imm));
break;
case "MovMRR":
result += line("mov", mem(k.dst, k.offset), reg(k.src));
break;
case "MovRMR":
result += line("mov", reg(k.dst), mem(k.src, k.offset));
break;
case "AddR":
result += line("add", reg(k.dst_op1), reg(k.op2));
break;
case "Jmp":
result += line(
"jmp",
`${c.varIdent}.l${blockIds.get(k.bb)!}`,
);
break;
case "Ret":
result += line("ret");
break;
}
}
}
return result;
}