mirror of
				https://github.com/Mercantec-GHC/h4-projekt-gruppe-0-sm.git
				synced 2025-10-31 07:37:01 +01:00 
			
		
		
		
	
		
			
				
	
	
		
			186 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
			
		
		
	
	
			186 lines
		
	
	
		
			5.1 KiB
		
	
	
	
		
			TypeScript
		
	
	
	
	
	
| 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;
 | |
|             }
 | |
|         }
 | |
|     }
 | |
| }
 | |
| 
 |