mirror of
				https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
				synced 2025-10-30 07:17:01 +01: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`); | ||||
|         for (const fn of this.lir.fns) { | ||||
|             this.writeln(`align 8`); | ||||
|             this.writeln(`global ${fn.label}:`); | ||||
|             this.writeln(`${fn.label}:`); | ||||
|             this.generateFn(fn); | ||||
|         } | ||||
| 
 | ||||
|         this.writeln(`; vim: syntax=nasm commentstring=;\\ %s`); | ||||
|         this.writeln(""); | ||||
|         return this.writer.finalize(); | ||||
|     } | ||||
| 
 | ||||
|     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); | ||||
|     } | ||||
| 
 | ||||
|         return this.writer.finalize(); | ||||
|     } | ||||
| 
 | ||||
|     private generateFnBody(fn: lir.Fn) { | ||||
|     private queryCFunction( | ||||
|         fn: lir.Fn, | ||||
|     ): { found: false } | { found: true; label: string; args: number } { | ||||
|         const stmtKind = fn.mir.stmt.kind; | ||||
|         if (stmtKind.tag !== "fn") { | ||||
|             throw new Error(); | ||||
| @ -45,12 +56,41 @@ export class AsmGen { | ||||
|             if (!arg || arg.kind.tag !== "string") { | ||||
|                 throw new Error("incorrect args for attribute"); | ||||
|             } | ||||
|             const label = arg.kind.val; | ||||
|             this.generateCFunctionBody(label, fn.mir.paramLocals.size); | ||||
|             return; | ||||
|             return { | ||||
|                 found: true, | ||||
|                 label: arg.kind.val, | ||||
|                 args: fn.mir.paramLocals.size, | ||||
|             }; | ||||
|         } | ||||
|         return { found: false }; | ||||
|     } | ||||
| 
 | ||||
|         this.writeIns(`push r12`); | ||||
|     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`); | ||||
|         } | ||||
| 
 | ||||
|         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(`mov rbp, rsp`); | ||||
|         this.writeIns(`sub rsp, ${fn.frameSize}`); | ||||
| @ -64,30 +104,11 @@ export class AsmGen { | ||||
|         } | ||||
| 
 | ||||
|         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(`pop rbp`); | ||||
|         this.writeIns(`pop r12`); | ||||
|     } | ||||
| 
 | ||||
|     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`); | ||||
|         this.writeIns(`ret`); | ||||
|     } | ||||
| 
 | ||||
|     private generateIns(ins: lir.Ins) { | ||||
| @ -115,16 +136,27 @@ export class AsmGen { | ||||
|                 this.writeIns(`pop ${r(ins.reg)}`); | ||||
|                 return; | ||||
|             case "load": | ||||
|                 this.writeIns(`mov QWORD [rbp${ins.offset}], ${r(ins.reg)}`); | ||||
|                 this.writeIns( | ||||
|                     `mov ${r(ins.reg)}, QWORD ${this.relative(ins.offset)}`, | ||||
|                 ); | ||||
|                 return; | ||||
|             case "store": | ||||
|                 this.writeIns(`mov ${r(ins.reg)}, QWORD [rbp${ins.offset}]`); | ||||
|             case "store_reg": | ||||
|                 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; | ||||
|             case "call_reg": | ||||
|                 this.generateCall(r(ins.reg), ins.args); | ||||
|                 this.writeIns(`call ${r(ins.reg)}`); | ||||
|                 this.writeIns(`push rax`); | ||||
|                 return; | ||||
|             case "call_fn": | ||||
|                 this.generateCall(ins.fn.label, ins.args); | ||||
|             case "call_imm": | ||||
|                 this.writeIns(`call ${ins.fn.label}`); | ||||
|                 this.writeIns(`push rax`); | ||||
|                 return; | ||||
|             case "jmp": | ||||
|                 this.writeIns(`jmp .L${ins.target}`); | ||||
| @ -153,27 +185,7 @@ export class AsmGen { | ||||
|                 this.kill(ins.reg); | ||||
|                 return; | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     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`); | ||||
|         const _: never = ins; | ||||
|     } | ||||
| 
 | ||||
|     private reg(reg: lir.Reg): string { | ||||
| @ -198,7 +210,6 @@ export class AsmGen { | ||||
| 
 | ||||
|     private allocReg(reg: lir.Reg) { | ||||
|         if (!this.liveRegs.has(reg)) { | ||||
|             this.liveRegs.add(reg); | ||||
|             const regSel = [ | ||||
|                 "rax", | ||||
|                 "rdi", | ||||
| @ -213,10 +224,15 @@ export class AsmGen { | ||||
|             if (!regSel) { | ||||
|                 throw new Error("ran out of registers"); | ||||
|             } | ||||
|             this.liveRegs.add(reg); | ||||
|             this.regSelect.set(reg, regSel); | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     private relative(offset: number): string { | ||||
|         return `[rbp${offset >= 0 ? `+${offset}` : `${offset}`}]`; | ||||
|     } | ||||
| 
 | ||||
|     private kill(reg: lir.Reg) { | ||||
|         this.liveRegs.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; | ||||
|     lines: Line[]; | ||||
|     frameSize: number; | ||||
|     localOffsets: Map<number, number>; | ||||
| }; | ||||
| 
 | ||||
| export type Line = { | ||||
| @ -27,9 +28,10 @@ export type Ins = | ||||
|     | { tag: "push"; reg: Reg } | ||||
|     | { tag: "pop"; reg: Reg } | ||||
|     | { 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_fn"; fn: Fn; args: number } | ||||
|     | { tag: "call_imm"; fn: Fn; args: number } | ||||
|     | { tag: "jmp"; target: Label } | ||||
|     | { tag: "jnz_reg"; reg: Reg; target: Label } | ||||
|     | { tag: "ret" } | ||||
| @ -52,7 +54,7 @@ export class ProgramStringifyer { | ||||
|                         .map((label) => | ||||
|                             `${ | ||||
|                                 label.labels | ||||
|                                     .map((label) => `.${label}:\n`) | ||||
|                                     .map((label) => `.L${label}:\n`) | ||||
|                                     .join() | ||||
|                             }    ${this.ins(label.ins)}\n` | ||||
|                         ) | ||||
| @ -80,11 +82,13 @@ export class ProgramStringifyer { | ||||
|                 return `pop %${ins.reg}`; | ||||
|             case "load": | ||||
|                 return `load %${ins.reg}, ${ins.offset}`; | ||||
|             case "store": | ||||
|                 return `store ${ins.offset}, %${ins.reg}`; | ||||
|             case "store_reg": | ||||
|                 return `store_reg ${ins.offset}, %${ins.reg}`; | ||||
|             case "store_imm": | ||||
|                 return `store_val ${ins.offset}, ${ins.val}`; | ||||
|             case "call_reg": | ||||
|                 return `call_reg %${ins.reg}, ${ins.args}`; | ||||
|             case "call_fn": | ||||
|             case "call_imm": | ||||
|                 return `call_fn ${ins.fn.label}, ${ins.args}`; | ||||
|             case "jmp": | ||||
|                 return `jmp .b${ins.target}`; | ||||
|  | ||||
| @ -31,7 +31,14 @@ export class LirGen { | ||||
|             const mir = this.mirGen.fnMir(stmt, stmt.kind); | ||||
|             const id = this.fnIds++; | ||||
|             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.stmtFns.set(stmt.id, fn); | ||||
|         } | ||||
| @ -69,8 +76,6 @@ class FnGen { | ||||
| 
 | ||||
|     private currentLabels: Label[] = []; | ||||
| 
 | ||||
|     private nextOffset = -8; | ||||
|     private frameSize = 0; | ||||
|     private localOffsets = new Map<number, number>(); | ||||
| 
 | ||||
|     public constructor( | ||||
| @ -84,12 +89,33 @@ class FnGen { | ||||
|             const label = this.labelIds++; | ||||
|             this.blockLabels.set(block.id, label); | ||||
|         } | ||||
|         for (const local of this.fn.mir.locals) { | ||||
|             this.localOffsets.set(local.id, this.nextOffset); | ||||
|             this.nextOffset -= 8; | ||||
|             this.frameSize += 8; | ||||
| 
 | ||||
|         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; | ||||
|         } | ||||
|         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) { | ||||
|             this.currentLabels.push(this.blockLabels.get(block.id)!); | ||||
|             for (const stmt of block.stmts) { | ||||
| @ -158,7 +184,7 @@ class FnGen { | ||||
|                 const reg = this.reg(); | ||||
|                 const offset = this.localOffsets.get(k.local.id)!; | ||||
|                 this.pushIns({ tag: "pop", reg }); | ||||
|                 this.pushIns({ tag: "store", offset, reg }); | ||||
|                 this.pushIns({ tag: "store_reg", offset, reg }); | ||||
|                 this.pushIns({ tag: "kill", reg }); | ||||
|                 return; | ||||
|             } | ||||
| @ -175,8 +201,8 @@ class FnGen { | ||||
|             case "mul": { | ||||
|                 const dst = this.reg(); | ||||
|                 const src = this.reg(); | ||||
|                 this.pushIns({ tag: "pop", reg: src }); | ||||
|                 this.pushIns({ tag: "pop", reg: dst }); | ||||
|                 this.pushIns({ tag: "pop", reg: src }); | ||||
|                 this.pushIns({ tag: k.tag, dst, src }); | ||||
|                 this.pushIns({ tag: "push", reg: dst }); | ||||
|                 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 { ProgramStringifyer } from "./lir.ts"; | ||||
| import { AsmGen } from "./asm_gen.ts"; | ||||
| import { lirOptimize } from "./lir_optimize.ts"; | ||||
| 
 | ||||
| async function main() { | ||||
|     const text = await Deno.readTextFile(Deno.args[0]); | ||||
| 
 | ||||
|     const ast = new Parser(text).parse(); | ||||
|     console.log("=== AST ==="); | ||||
|     console.log(yaml.stringify(ast)); | ||||
|     // console.log("=== AST ===");
 | ||||
|     // console.log(yaml.stringify(ast));
 | ||||
| 
 | ||||
|     const re = new Resolver(ast).resolve(); | ||||
|     const ch = new Checker(re); | ||||
| 
 | ||||
|     const mirGen = new MirGen(re, ch); | ||||
| 
 | ||||
|     console.log("=== MIR ==="); | ||||
|     for (const stmt of ast) { | ||||
|         if (stmt.kind.tag !== "fn") { | ||||
|             throw new Error("only functions can compile top level"); | ||||
|         } | ||||
|         const fnMir = mirGen.fnMir(stmt, stmt.kind); | ||||
|         console.log(new FnStringifyer(fnMir).stringify()); | ||||
|     } | ||||
|     // console.log("=== MIR ===");
 | ||||
|     // for (const stmt of ast) {
 | ||||
|     //     if (stmt.kind.tag !== "fn") {
 | ||||
|     //         throw new Error("only functions can compile top level");
 | ||||
|     //     }
 | ||||
|     //     const fnMir = mirGen.fnMir(stmt, stmt.kind);
 | ||||
|     //     console.log(new FnStringifyer(fnMir).stringify());
 | ||||
|     // }
 | ||||
| 
 | ||||
|     const lir = new LirGen(ast, mirGen).generate(); | ||||
|     console.log("=== LIR ==="); | ||||
|     console.log(new ProgramStringifyer(lir).stringify()); | ||||
|     // console.log("=== LIR ===");
 | ||||
|     // console.log(new ProgramStringifyer(lir).stringify());
 | ||||
| 
 | ||||
|     lirOptimize(lir); | ||||
| 
 | ||||
|     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(); | ||||
|  | ||||
| @ -51,11 +51,12 @@ export class FnMirGen { | ||||
| 
 | ||||
|         const entry = this.block(); | ||||
|         const exit = this.block(); | ||||
|         this.returnBlock = exit; | ||||
| 
 | ||||
|         this.currentBlock = entry; | ||||
|         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" }); | ||||
|         return { | ||||
|             stmt: this.stmt, | ||||
| @ -251,6 +252,8 @@ export class FnMirGen { | ||||
|                 return; | ||||
|             } | ||||
|             case "binary": { | ||||
|                 this.lowerExpr(k.left); | ||||
|                 this.lowerExpr(k.right); | ||||
|                 switch (k.op) { | ||||
|                     case "<": | ||||
|                         this.pushStmt({ tag: "lt" }); | ||||
| @ -290,4 +293,3 @@ export class FnMirGen { | ||||
|         this.currentBlock.stmts.push(Stmt(kind)); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -2,13 +2,15 @@ | ||||
| #[c_function("print_int")] | ||||
| fn print_int(value) {} | ||||
| 
 | ||||
| // #[c_function("println")] | ||||
| // fn println(value) {} | ||||
| fn inner(value) { | ||||
|     print_int(value); | ||||
|     return 0;     | ||||
| } | ||||
| 
 | ||||
| fn main() { | ||||
|     // println("hello\ world"); | ||||
|     let a = 4; | ||||
|     print_int(a + 2); | ||||
|     inner(a + 2); | ||||
|     return a; | ||||
| } | ||||
| 
 | ||||
| // vim: syntax=rust commentstring=//\ %s | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user