mirror of
https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
synced 2025-04-27 16:24:07 +02:00
works, but segfaults
This commit is contained in:
parent
2025a450f6
commit
fd2f6243a2
14
backup-compiler/.clang-format
Normal file
14
backup-compiler/.clang-format
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
Language: Cpp
|
||||||
|
BasedOnStyle: WebKit
|
||||||
|
IndentWidth: 4
|
||||||
|
ColumnLimit: 80
|
||||||
|
IndentCaseLabels: true
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
|
|
||||||
|
BinPackArguments: false
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
|
||||||
|
BinPackParameters: false
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
|
4
backup-compiler/.gitignore
vendored
Normal file
4
backup-compiler/.gitignore
vendored
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
out.nasm
|
||||||
|
*.o
|
||||||
|
out
|
||||||
|
|
18
backup-compiler/Makefile
Normal file
18
backup-compiler/Makefile
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
|
||||||
|
all: out
|
||||||
|
|
||||||
|
out: entry.o out.o lib.o
|
||||||
|
gcc $^ -o $@ -no-pie
|
||||||
|
|
||||||
|
%.o: %.c
|
||||||
|
gcc -c -o $@ -std=c17 -Wall -Wextra -Wpedantic -pedantic -pedantic-errors $^
|
||||||
|
|
||||||
|
%.o: %.nasm
|
||||||
|
nasm -f elf64 $< -o $@
|
||||||
|
|
||||||
|
out.nasm: program.sbl
|
||||||
|
deno run --allow-read --allow-write --check main.ts $<
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -rf out.asm out.o lib.o entry.o out
|
||||||
|
|
@ -25,17 +25,28 @@ export class AsmGen {
|
|||||||
}
|
}
|
||||||
this.writeln(`section .text`);
|
this.writeln(`section .text`);
|
||||||
for (const fn of this.lir.fns) {
|
for (const fn of this.lir.fns) {
|
||||||
this.writeln(`align 8`);
|
this.generateFn(fn);
|
||||||
this.writeln(`global ${fn.label}:`);
|
|
||||||
this.writeln(`${fn.label}:`);
|
|
||||||
|
|
||||||
this.generateFnBody(fn);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
this.writeln(`; vim: syntax=nasm commentstring=;\\ %s`);
|
||||||
|
this.writeln("");
|
||||||
return this.writer.finalize();
|
return this.writer.finalize();
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateFnBody(fn: lir.Fn) {
|
private generateFn(fn: lir.Fn) {
|
||||||
|
const query = this.queryCFunction(fn);
|
||||||
|
if (query.found) {
|
||||||
|
const { label, args } = query;
|
||||||
|
this.generateCFunctionBody(fn, label, args);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
this.generateFnBody(fn);
|
||||||
|
}
|
||||||
|
|
||||||
|
private queryCFunction(
|
||||||
|
fn: lir.Fn,
|
||||||
|
): { found: false } | { found: true; label: string; args: number } {
|
||||||
const stmtKind = fn.mir.stmt.kind;
|
const stmtKind = fn.mir.stmt.kind;
|
||||||
if (stmtKind.tag !== "fn") {
|
if (stmtKind.tag !== "fn") {
|
||||||
throw new Error();
|
throw new Error();
|
||||||
@ -45,12 +56,41 @@ export class AsmGen {
|
|||||||
if (!arg || arg.kind.tag !== "string") {
|
if (!arg || arg.kind.tag !== "string") {
|
||||||
throw new Error("incorrect args for attribute");
|
throw new Error("incorrect args for attribute");
|
||||||
}
|
}
|
||||||
const label = arg.kind.val;
|
return {
|
||||||
this.generateCFunctionBody(label, fn.mir.paramLocals.size);
|
found: true,
|
||||||
return;
|
label: arg.kind.val,
|
||||||
|
args: fn.mir.paramLocals.size,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
return { found: false };
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateCFunctionBody(fn: lir.Fn, label: string, args: number) {
|
||||||
|
this.writeln(`extern ${label}`);
|
||||||
|
this.writeln(`global ${fn.label}`);
|
||||||
|
this.writeln(`${fn.label}:`);
|
||||||
|
|
||||||
|
this.writeIns(`push rbp`);
|
||||||
|
this.writeIns(`mov rbp, rsp`);
|
||||||
|
for (let i = 0; i < args; ++i) {
|
||||||
|
this.writeIns(`mov rax, ${this.relative((i + 2) * 8)}`);
|
||||||
|
this.writeIns(`push rax`);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.writeIns(`push r12`);
|
const argRegs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
||||||
|
for (const reg of argRegs.slice(0, args + 1)) {
|
||||||
|
this.writeIns(`pop ${reg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
this.writeIns(`call ${label}`);
|
||||||
|
this.writeIns(`mov rsp, rbp`);
|
||||||
|
this.writeIns(`pop rbp`);
|
||||||
|
this.writeIns(`ret`);
|
||||||
|
}
|
||||||
|
|
||||||
|
private generateFnBody(fn: lir.Fn) {
|
||||||
|
this.writeln(`global ${fn.label}:`);
|
||||||
|
this.writeln(`${fn.label}:`);
|
||||||
this.writeIns(`push rbp`);
|
this.writeIns(`push rbp`);
|
||||||
this.writeIns(`mov rbp, rsp`);
|
this.writeIns(`mov rbp, rsp`);
|
||||||
this.writeIns(`sub rsp, ${fn.frameSize}`);
|
this.writeIns(`sub rsp, ${fn.frameSize}`);
|
||||||
@ -64,30 +104,11 @@ export class AsmGen {
|
|||||||
}
|
}
|
||||||
|
|
||||||
this.writeln(`.exit:`);
|
this.writeln(`.exit:`);
|
||||||
|
const returnLocalOffset = fn.localOffsets.get(fn.mir.returnLocal.id)!;
|
||||||
|
this.writeIns(`mov rax, QWORD ${this.relative(returnLocalOffset)}`);
|
||||||
this.writeIns(`mov rsp, rbp`);
|
this.writeIns(`mov rsp, rbp`);
|
||||||
this.writeIns(`pop rbp`);
|
this.writeIns(`pop rbp`);
|
||||||
this.writeIns(`pop r12`);
|
this.writeIns(`ret`);
|
||||||
}
|
|
||||||
|
|
||||||
private generateCFunctionBody(label: string, args: number) {
|
|
||||||
const argRegs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
|
||||||
const returnReg = "rax";
|
|
||||||
if (args > argRegs.length) {
|
|
||||||
throw new Error(
|
|
||||||
`arg count (${args}) > ${argRegs.length} not supported`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.writeIns(`push ${returnReg}`);
|
|
||||||
for (const reg of argRegs.slice(0, args + 1)) {
|
|
||||||
this.writeIns(`push ${reg}`);
|
|
||||||
}
|
|
||||||
this.writeIns(`call ${label}`);
|
|
||||||
this.writeIns(`mov r12, rax`);
|
|
||||||
for (const reg of argRegs.slice(0, args + 1).toReversed()) {
|
|
||||||
this.writeIns(`push ${reg}`);
|
|
||||||
}
|
|
||||||
this.writeIns(`pop ${returnReg}`);
|
|
||||||
this.writeIns(`push r12`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private generateIns(ins: lir.Ins) {
|
private generateIns(ins: lir.Ins) {
|
||||||
@ -115,16 +136,27 @@ export class AsmGen {
|
|||||||
this.writeIns(`pop ${r(ins.reg)}`);
|
this.writeIns(`pop ${r(ins.reg)}`);
|
||||||
return;
|
return;
|
||||||
case "load":
|
case "load":
|
||||||
this.writeIns(`mov QWORD [rbp${ins.offset}], ${r(ins.reg)}`);
|
this.writeIns(
|
||||||
|
`mov ${r(ins.reg)}, QWORD ${this.relative(ins.offset)}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
case "store":
|
case "store_reg":
|
||||||
this.writeIns(`mov ${r(ins.reg)}, QWORD [rbp${ins.offset}]`);
|
this.writeIns(
|
||||||
|
`mov QWORD ${this.relative(ins.offset)}, ${r(ins.reg)}`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
case "store_imm":
|
||||||
|
this.writeIns(
|
||||||
|
`mov QWORD ${this.relative(ins.offset)}, ${ins.val}`,
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
case "call_reg":
|
case "call_reg":
|
||||||
this.generateCall(r(ins.reg), ins.args);
|
this.writeIns(`call ${r(ins.reg)}`);
|
||||||
|
this.writeIns(`push rax`);
|
||||||
return;
|
return;
|
||||||
case "call_fn":
|
case "call_imm":
|
||||||
this.generateCall(ins.fn.label, ins.args);
|
this.writeIns(`call ${ins.fn.label}`);
|
||||||
|
this.writeIns(`push rax`);
|
||||||
return;
|
return;
|
||||||
case "jmp":
|
case "jmp":
|
||||||
this.writeIns(`jmp .L${ins.target}`);
|
this.writeIns(`jmp .L${ins.target}`);
|
||||||
@ -153,27 +185,7 @@ export class AsmGen {
|
|||||||
this.kill(ins.reg);
|
this.kill(ins.reg);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
const _: never = ins;
|
||||||
|
|
||||||
private generateCall(value: string, args: number) {
|
|
||||||
const argRegs = ["rdi", "rsi", "rdx", "rcx", "r8", "r9"];
|
|
||||||
const returnReg = "rax";
|
|
||||||
if (args > argRegs.length) {
|
|
||||||
throw new Error(
|
|
||||||
`arg count (${args}) > ${argRegs.length} not supported`,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
this.writeIns(`push ${returnReg}`);
|
|
||||||
for (const reg of argRegs.slice(0, args + 1)) {
|
|
||||||
this.writeIns(`push ${reg}`);
|
|
||||||
}
|
|
||||||
this.writeIns(`call ${value}`);
|
|
||||||
this.writeIns(`mov r12, rax`);
|
|
||||||
for (const reg of argRegs.slice(0, args + 1).toReversed()) {
|
|
||||||
this.writeIns(`push ${reg}`);
|
|
||||||
}
|
|
||||||
this.writeIns(`pop ${returnReg}`);
|
|
||||||
this.writeIns(`push r12`);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private reg(reg: lir.Reg): string {
|
private reg(reg: lir.Reg): string {
|
||||||
@ -198,7 +210,6 @@ export class AsmGen {
|
|||||||
|
|
||||||
private allocReg(reg: lir.Reg) {
|
private allocReg(reg: lir.Reg) {
|
||||||
if (!this.liveRegs.has(reg)) {
|
if (!this.liveRegs.has(reg)) {
|
||||||
this.liveRegs.add(reg);
|
|
||||||
const regSel = [
|
const regSel = [
|
||||||
"rax",
|
"rax",
|
||||||
"rdi",
|
"rdi",
|
||||||
@ -213,10 +224,15 @@ export class AsmGen {
|
|||||||
if (!regSel) {
|
if (!regSel) {
|
||||||
throw new Error("ran out of registers");
|
throw new Error("ran out of registers");
|
||||||
}
|
}
|
||||||
|
this.liveRegs.add(reg);
|
||||||
this.regSelect.set(reg, regSel);
|
this.regSelect.set(reg, regSel);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private relative(offset: number): string {
|
||||||
|
return `[rbp${offset >= 0 ? `+${offset}` : `${offset}`}]`;
|
||||||
|
}
|
||||||
|
|
||||||
private kill(reg: lir.Reg) {
|
private kill(reg: lir.Reg) {
|
||||||
this.liveRegs.delete(reg);
|
this.liveRegs.delete(reg);
|
||||||
this.regSelect.delete(reg);
|
this.regSelect.delete(reg);
|
||||||
|
8
backup-compiler/entry.c
Normal file
8
backup-compiler/entry.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
|
||||||
|
extern int32_t sbc__main(void);
|
||||||
|
|
||||||
|
int main(void)
|
||||||
|
{
|
||||||
|
sbc__main();
|
||||||
|
}
|
8
backup-compiler/lib.c
Normal file
8
backup-compiler/lib.c
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
#include <stdint.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
|
||||||
|
int64_t print_int(int64_t value)
|
||||||
|
{
|
||||||
|
printf("%ld\n", value);
|
||||||
|
return 0;
|
||||||
|
}
|
@ -11,6 +11,7 @@ export type Fn = {
|
|||||||
mir: mir.Fn;
|
mir: mir.Fn;
|
||||||
lines: Line[];
|
lines: Line[];
|
||||||
frameSize: number;
|
frameSize: number;
|
||||||
|
localOffsets: Map<number, number>;
|
||||||
};
|
};
|
||||||
|
|
||||||
export type Line = {
|
export type Line = {
|
||||||
@ -27,9 +28,10 @@ export type Ins =
|
|||||||
| { tag: "push"; reg: Reg }
|
| { tag: "push"; reg: Reg }
|
||||||
| { tag: "pop"; reg: Reg }
|
| { tag: "pop"; reg: Reg }
|
||||||
| { tag: "load"; reg: Reg; offset: number }
|
| { tag: "load"; reg: Reg; offset: number }
|
||||||
| { tag: "store"; offset: number; reg: Reg }
|
| { tag: "store_reg"; offset: number; reg: Reg }
|
||||||
|
| { tag: "store_imm"; offset: number; val: number }
|
||||||
| { tag: "call_reg"; reg: Reg; args: number }
|
| { tag: "call_reg"; reg: Reg; args: number }
|
||||||
| { tag: "call_fn"; fn: Fn; args: number }
|
| { tag: "call_imm"; fn: Fn; args: number }
|
||||||
| { tag: "jmp"; target: Label }
|
| { tag: "jmp"; target: Label }
|
||||||
| { tag: "jnz_reg"; reg: Reg; target: Label }
|
| { tag: "jnz_reg"; reg: Reg; target: Label }
|
||||||
| { tag: "ret" }
|
| { tag: "ret" }
|
||||||
@ -52,7 +54,7 @@ export class ProgramStringifyer {
|
|||||||
.map((label) =>
|
.map((label) =>
|
||||||
`${
|
`${
|
||||||
label.labels
|
label.labels
|
||||||
.map((label) => `.${label}:\n`)
|
.map((label) => `.L${label}:\n`)
|
||||||
.join()
|
.join()
|
||||||
} ${this.ins(label.ins)}\n`
|
} ${this.ins(label.ins)}\n`
|
||||||
)
|
)
|
||||||
@ -80,11 +82,13 @@ export class ProgramStringifyer {
|
|||||||
return `pop %${ins.reg}`;
|
return `pop %${ins.reg}`;
|
||||||
case "load":
|
case "load":
|
||||||
return `load %${ins.reg}, ${ins.offset}`;
|
return `load %${ins.reg}, ${ins.offset}`;
|
||||||
case "store":
|
case "store_reg":
|
||||||
return `store ${ins.offset}, %${ins.reg}`;
|
return `store_reg ${ins.offset}, %${ins.reg}`;
|
||||||
|
case "store_imm":
|
||||||
|
return `store_val ${ins.offset}, ${ins.val}`;
|
||||||
case "call_reg":
|
case "call_reg":
|
||||||
return `call_reg %${ins.reg}, ${ins.args}`;
|
return `call_reg %${ins.reg}, ${ins.args}`;
|
||||||
case "call_fn":
|
case "call_imm":
|
||||||
return `call_fn ${ins.fn.label}, ${ins.args}`;
|
return `call_fn ${ins.fn.label}, ${ins.args}`;
|
||||||
case "jmp":
|
case "jmp":
|
||||||
return `jmp .b${ins.target}`;
|
return `jmp .b${ins.target}`;
|
||||||
|
@ -31,7 +31,14 @@ export class LirGen {
|
|||||||
const mir = this.mirGen.fnMir(stmt, stmt.kind);
|
const mir = this.mirGen.fnMir(stmt, stmt.kind);
|
||||||
const id = this.fnIds++;
|
const id = this.fnIds++;
|
||||||
const label = `sbc__${stmt.kind.ident}`;
|
const label = `sbc__${stmt.kind.ident}`;
|
||||||
const fn: Fn = { id, label, mir, lines: [], frameSize: 0 };
|
const fn: Fn = {
|
||||||
|
id,
|
||||||
|
label,
|
||||||
|
mir,
|
||||||
|
lines: [],
|
||||||
|
frameSize: 0,
|
||||||
|
localOffsets: new Map(),
|
||||||
|
};
|
||||||
this.fns.set(id, fn);
|
this.fns.set(id, fn);
|
||||||
this.stmtFns.set(stmt.id, fn);
|
this.stmtFns.set(stmt.id, fn);
|
||||||
}
|
}
|
||||||
@ -69,8 +76,6 @@ class FnGen {
|
|||||||
|
|
||||||
private currentLabels: Label[] = [];
|
private currentLabels: Label[] = [];
|
||||||
|
|
||||||
private nextOffset = -8;
|
|
||||||
private frameSize = 0;
|
|
||||||
private localOffsets = new Map<number, number>();
|
private localOffsets = new Map<number, number>();
|
||||||
|
|
||||||
public constructor(
|
public constructor(
|
||||||
@ -84,12 +89,33 @@ class FnGen {
|
|||||||
const label = this.labelIds++;
|
const label = this.labelIds++;
|
||||||
this.blockLabels.set(block.id, label);
|
this.blockLabels.set(block.id, label);
|
||||||
}
|
}
|
||||||
for (const local of this.fn.mir.locals) {
|
|
||||||
this.localOffsets.set(local.id, this.nextOffset);
|
let currentOffset = 8 + this.fn.mir.paramLocals.size * 8;
|
||||||
this.nextOffset -= 8;
|
let frameSize = 0;
|
||||||
this.frameSize += 8;
|
|
||||||
|
for (const local of this.fn.mir.paramLocals.values()) {
|
||||||
|
this.localOffsets.set(local.id, currentOffset);
|
||||||
|
currentOffset -= 8;
|
||||||
}
|
}
|
||||||
this.fn.frameSize = this.frameSize;
|
// return address
|
||||||
|
currentOffset -= 8;
|
||||||
|
// old rbp
|
||||||
|
currentOffset -= 8;
|
||||||
|
// return value
|
||||||
|
this.localOffsets.set(this.fn.mir.returnLocal.id, currentOffset);
|
||||||
|
currentOffset -= 8;
|
||||||
|
frameSize += 8;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
this.fn.frameSize = frameSize;
|
||||||
|
this.fn.localOffsets = this.localOffsets;
|
||||||
|
|
||||||
for (const block of this.fn.mir.blocks) {
|
for (const block of this.fn.mir.blocks) {
|
||||||
this.currentLabels.push(this.blockLabels.get(block.id)!);
|
this.currentLabels.push(this.blockLabels.get(block.id)!);
|
||||||
for (const stmt of block.stmts) {
|
for (const stmt of block.stmts) {
|
||||||
@ -158,7 +184,7 @@ class FnGen {
|
|||||||
const reg = this.reg();
|
const reg = this.reg();
|
||||||
const offset = this.localOffsets.get(k.local.id)!;
|
const offset = this.localOffsets.get(k.local.id)!;
|
||||||
this.pushIns({ tag: "pop", reg });
|
this.pushIns({ tag: "pop", reg });
|
||||||
this.pushIns({ tag: "store", offset, reg });
|
this.pushIns({ tag: "store_reg", offset, reg });
|
||||||
this.pushIns({ tag: "kill", reg });
|
this.pushIns({ tag: "kill", reg });
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -175,8 +201,8 @@ class FnGen {
|
|||||||
case "mul": {
|
case "mul": {
|
||||||
const dst = this.reg();
|
const dst = this.reg();
|
||||||
const src = this.reg();
|
const src = this.reg();
|
||||||
this.pushIns({ tag: "pop", reg: src });
|
|
||||||
this.pushIns({ tag: "pop", reg: dst });
|
this.pushIns({ tag: "pop", reg: dst });
|
||||||
|
this.pushIns({ tag: "pop", reg: src });
|
||||||
this.pushIns({ tag: k.tag, dst, src });
|
this.pushIns({ tag: k.tag, dst, src });
|
||||||
this.pushIns({ tag: "push", reg: dst });
|
this.pushIns({ tag: "push", reg: dst });
|
||||||
this.pushIns({ tag: "kill", reg: src });
|
this.pushIns({ tag: "kill", reg: src });
|
||||||
|
185
backup-compiler/lir_optimize.ts
Normal file
185
backup-compiler/lir_optimize.ts
Normal file
@ -0,0 +1,185 @@
|
|||||||
|
import {
|
||||||
|
Fn,
|
||||||
|
Ins,
|
||||||
|
Label,
|
||||||
|
Line,
|
||||||
|
Program,
|
||||||
|
ProgramStringifyer,
|
||||||
|
Reg,
|
||||||
|
} from "./lir.ts";
|
||||||
|
|
||||||
|
export function lirOptimize(program: Program) {
|
||||||
|
console.log("=== BEFORE OPTIMIZATION ===");
|
||||||
|
console.log(new ProgramStringifyer(program).stringify());
|
||||||
|
for (const fn of program.fns) {
|
||||||
|
eliminatePushPop(fn);
|
||||||
|
eliminateMovFnCall(fn);
|
||||||
|
eliminateMovIntStoreReg(fn);
|
||||||
|
}
|
||||||
|
console.log("=== AFTER OPTIMIZATION ===");
|
||||||
|
console.log(new ProgramStringifyer(program).stringify());
|
||||||
|
}
|
||||||
|
|
||||||
|
function eliminatePushPop(fn: Fn) {
|
||||||
|
const candidates: number[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < fn.lines.length - 2; ++i) {
|
||||||
|
const [push, kill, pop] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
push.ins.tag === "push" &&
|
||||||
|
kill.ins.tag === "kill" &&
|
||||||
|
pop.ins.tag === "pop" &&
|
||||||
|
kill.labels.length === 0 &&
|
||||||
|
pop.labels.length === 0 &&
|
||||||
|
push.ins.reg === kill.ins.reg
|
||||||
|
) {
|
||||||
|
candidates.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of candidates.toReversed()) {
|
||||||
|
if (i + 3 >= fn.lines.length) {
|
||||||
|
fn.lines[i + 3].labels.push(...fn.lines[i].labels);
|
||||||
|
}
|
||||||
|
const [push, kill, pop] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
push.ins.tag === "push" &&
|
||||||
|
kill.ins.tag === "kill" &&
|
||||||
|
pop.ins.tag === "pop"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const toRemove = pop.ins.reg;
|
||||||
|
const replacement = push.ins.reg;
|
||||||
|
fn.lines.splice(i, 3);
|
||||||
|
replaceReg(fn, toRemove, replacement);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function eliminateMovFnCall(fn: Fn) {
|
||||||
|
const candidates: number[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < fn.lines.length - 2; ++i) {
|
||||||
|
const [movFn, callReg, kill] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
movFn.ins.tag === "mov_fn" &&
|
||||||
|
callReg.ins.tag === "call_reg" &&
|
||||||
|
kill.ins.tag === "kill" &&
|
||||||
|
callReg.labels.length === 0 &&
|
||||||
|
kill.labels.length === 0 &&
|
||||||
|
movFn.ins.reg === callReg.ins.reg &&
|
||||||
|
movFn.ins.reg === kill.ins.reg
|
||||||
|
) {
|
||||||
|
candidates.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of candidates.toReversed()) {
|
||||||
|
const [movFn, callReg, kill] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
movFn.ins.tag === "mov_fn" &&
|
||||||
|
callReg.ins.tag === "call_reg" &&
|
||||||
|
kill.ins.tag === "kill"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const fnVal = movFn.ins.fn;
|
||||||
|
const args = callReg.ins.args;
|
||||||
|
fn.lines.splice(i + 1, 2);
|
||||||
|
fn.lines[i].ins = { tag: "call_imm", fn: fnVal, args };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function eliminateMovIntStoreReg(fn: Fn) {
|
||||||
|
const candidates: number[] = [];
|
||||||
|
|
||||||
|
for (let i = 0; i < fn.lines.length - 2; ++i) {
|
||||||
|
const [movInt, storeReg, kill] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
movInt.ins.tag === "mov_int" &&
|
||||||
|
storeReg.ins.tag === "store_reg" &&
|
||||||
|
kill.ins.tag === "kill" &&
|
||||||
|
storeReg.labels.length === 0 &&
|
||||||
|
kill.labels.length === 0 &&
|
||||||
|
movInt.ins.reg === storeReg.ins.reg &&
|
||||||
|
movInt.ins.reg === kill.ins.reg
|
||||||
|
) {
|
||||||
|
candidates.push(i);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (const i of candidates.toReversed()) {
|
||||||
|
const [movInt, storeReg, kill] = fn.lines.slice(i);
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
movInt.ins.tag === "mov_int" &&
|
||||||
|
storeReg.ins.tag === "store_reg" &&
|
||||||
|
kill.ins.tag === "kill"
|
||||||
|
)
|
||||||
|
) {
|
||||||
|
throw new Error();
|
||||||
|
}
|
||||||
|
const offset = storeReg.ins.offset;
|
||||||
|
const val = movInt.ins.val;
|
||||||
|
fn.lines.splice(i + 1, 2);
|
||||||
|
fn.lines[i].ins = { tag: "store_imm", offset, val };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function replaceReg(fn: Fn, cand: Reg, replacement: Reg) {
|
||||||
|
const r = (reg: Reg): Reg => reg === cand ? replacement : reg;
|
||||||
|
|
||||||
|
for (const { ins } of fn.lines) {
|
||||||
|
switch (ins.tag) {
|
||||||
|
case "error":
|
||||||
|
break;
|
||||||
|
case "nop":
|
||||||
|
break;
|
||||||
|
case "mov_int":
|
||||||
|
case "mov_string":
|
||||||
|
case "mov_fn":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
case "push":
|
||||||
|
case "pop":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
case "load":
|
||||||
|
case "store_reg":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
case "store_imm":
|
||||||
|
break;
|
||||||
|
case "call_reg":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
case "call_imm":
|
||||||
|
break;
|
||||||
|
case "jmp":
|
||||||
|
break;
|
||||||
|
case "jnz_reg":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
case "ret":
|
||||||
|
break;
|
||||||
|
case "lt":
|
||||||
|
case "eq":
|
||||||
|
case "add":
|
||||||
|
case "mul":
|
||||||
|
ins.dst = r(ins.dst);
|
||||||
|
ins.src = r(ins.src);
|
||||||
|
break;
|
||||||
|
case "kill":
|
||||||
|
ins.reg = r(ins.reg);
|
||||||
|
break;
|
||||||
|
default: {
|
||||||
|
const _: never = ins;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -5,35 +5,40 @@ import { FnStringifyer } from "./mir.ts";
|
|||||||
import { LirGen } from "./lir_gen.ts";
|
import { LirGen } from "./lir_gen.ts";
|
||||||
import { ProgramStringifyer } from "./lir.ts";
|
import { ProgramStringifyer } from "./lir.ts";
|
||||||
import { AsmGen } from "./asm_gen.ts";
|
import { AsmGen } from "./asm_gen.ts";
|
||||||
|
import { lirOptimize } from "./lir_optimize.ts";
|
||||||
|
|
||||||
async function main() {
|
async function main() {
|
||||||
const text = await Deno.readTextFile(Deno.args[0]);
|
const text = await Deno.readTextFile(Deno.args[0]);
|
||||||
|
|
||||||
const ast = new Parser(text).parse();
|
const ast = new Parser(text).parse();
|
||||||
console.log("=== AST ===");
|
// console.log("=== AST ===");
|
||||||
console.log(yaml.stringify(ast));
|
// console.log(yaml.stringify(ast));
|
||||||
|
|
||||||
const re = new Resolver(ast).resolve();
|
const re = new Resolver(ast).resolve();
|
||||||
const ch = new Checker(re);
|
const ch = new Checker(re);
|
||||||
|
|
||||||
const mirGen = new MirGen(re, ch);
|
const mirGen = new MirGen(re, ch);
|
||||||
|
|
||||||
console.log("=== MIR ===");
|
// console.log("=== MIR ===");
|
||||||
for (const stmt of ast) {
|
// for (const stmt of ast) {
|
||||||
if (stmt.kind.tag !== "fn") {
|
// if (stmt.kind.tag !== "fn") {
|
||||||
throw new Error("only functions can compile top level");
|
// throw new Error("only functions can compile top level");
|
||||||
}
|
// }
|
||||||
const fnMir = mirGen.fnMir(stmt, stmt.kind);
|
// const fnMir = mirGen.fnMir(stmt, stmt.kind);
|
||||||
console.log(new FnStringifyer(fnMir).stringify());
|
// console.log(new FnStringifyer(fnMir).stringify());
|
||||||
}
|
// }
|
||||||
|
|
||||||
const lir = new LirGen(ast, mirGen).generate();
|
const lir = new LirGen(ast, mirGen).generate();
|
||||||
console.log("=== LIR ===");
|
// console.log("=== LIR ===");
|
||||||
console.log(new ProgramStringifyer(lir).stringify());
|
// console.log(new ProgramStringifyer(lir).stringify());
|
||||||
|
|
||||||
|
lirOptimize(lir);
|
||||||
|
|
||||||
const asm = new AsmGen(lir).generate();
|
const asm = new AsmGen(lir).generate();
|
||||||
console.log("=== ASM ===");
|
// console.log("=== ASM ===");
|
||||||
console.log(asm);
|
// console.log(asm);
|
||||||
|
|
||||||
|
await Deno.writeTextFile("out.nasm", asm);
|
||||||
}
|
}
|
||||||
|
|
||||||
main();
|
main();
|
||||||
|
@ -51,11 +51,12 @@ export class FnMirGen {
|
|||||||
|
|
||||||
const entry = this.block();
|
const entry = this.block();
|
||||||
const exit = this.block();
|
const exit = this.block();
|
||||||
|
this.returnBlock = exit;
|
||||||
|
|
||||||
this.currentBlock = entry;
|
this.currentBlock = entry;
|
||||||
this.lowerBlock(this.stmtKind.body);
|
this.lowerBlock(this.stmtKind.body);
|
||||||
|
|
||||||
entry.ter = Ter({ tag: "goto", target: exit });
|
this.currentBlock.ter = Ter({ tag: "goto", target: exit });
|
||||||
exit.ter = Ter({ tag: "return" });
|
exit.ter = Ter({ tag: "return" });
|
||||||
return {
|
return {
|
||||||
stmt: this.stmt,
|
stmt: this.stmt,
|
||||||
@ -251,6 +252,8 @@ export class FnMirGen {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
case "binary": {
|
case "binary": {
|
||||||
|
this.lowerExpr(k.left);
|
||||||
|
this.lowerExpr(k.right);
|
||||||
switch (k.op) {
|
switch (k.op) {
|
||||||
case "<":
|
case "<":
|
||||||
this.pushStmt({ tag: "lt" });
|
this.pushStmt({ tag: "lt" });
|
||||||
@ -290,4 +293,3 @@ export class FnMirGen {
|
|||||||
this.currentBlock.stmts.push(Stmt(kind));
|
this.currentBlock.stmts.push(Stmt(kind));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,13 +2,15 @@
|
|||||||
#[c_function("print_int")]
|
#[c_function("print_int")]
|
||||||
fn print_int(value) {}
|
fn print_int(value) {}
|
||||||
|
|
||||||
// #[c_function("println")]
|
fn inner(value) {
|
||||||
// fn println(value) {}
|
print_int(value);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// println("hello\ world");
|
|
||||||
let a = 4;
|
let a = 4;
|
||||||
print_int(a + 2);
|
inner(a + 2);
|
||||||
|
return a;
|
||||||
}
|
}
|
||||||
|
|
||||||
// vim: syntax=rust commentstring=//\ %s
|
// vim: syntax=rust commentstring=//\ %s
|
||||||
|
Loading…
x
Reference in New Issue
Block a user