From 24db80b520a53cfc9557afc00ec3e458a37a014d Mon Sep 17 00:00:00 2001 From: SpookyDervish <78246495+SpookyDervish@users.noreply.github.com> Date: Mon, 8 Sep 2025 20:21:36 +1000 Subject: [PATCH] we have a basic optimizer going! lets goo!!!!! --- generators/x86_64.py | 2 +- optimizers/optimizer.py | 78 +++++++++++++++++++++++++++++++++++++--- optimizers/x86_64.py | 66 +++++++++++++++++++++++++++++----- out | Bin 4736 -> 9024 bytes out.asm | 51 ++++++++++++++------------ test2.grnd | 14 ++++---- 6 files changed, 169 insertions(+), 42 deletions(-) diff --git a/generators/x86_64.py b/generators/x86_64.py index e6d11e4..e704b08 100644 --- a/generators/x86_64.py +++ b/generators/x86_64.py @@ -429,4 +429,4 @@ class X86_64Generator(Generator): f.write("section .text\n") optimizer = X86_64Optimizer(self.lines) - f.write(optimizer.peephole()) \ No newline at end of file + f.writelines(optimizer.peephole()) \ No newline at end of file diff --git a/optimizers/optimizer.py b/optimizers/optimizer.py index e334197..05a3c2c 100644 --- a/optimizers/optimizer.py +++ b/optimizers/optimizer.py @@ -1,11 +1,81 @@ +from typing import List, Dict, NamedTuple, Union +import re + + +class Instruction(NamedTuple): + opcode: str + operands: List[str] + +class PeepholeRule(NamedTuple): + match: List[Instruction] + replace: List[Instruction] + class Optimizer: - def __init__(self, lines: list[str]): + def __init__(self, lines: list[str], window_size: int = 5): self.lines = lines self.final_str = "" - # sliding window pos - self.pos = 0 + # sliding window + self.window_size = window_size + self.rules: list[PeepholeRule] = [] + + def match_instruction(self, pattern: Instruction, instr: Instruction, bindings: Dict[str, str]) -> bool: + if pattern.opcode != instr.opcode: + return False + if len(pattern.operands) != len(instr.operands): + return False + + for p_op, i_op in zip(pattern.operands, instr.operands): + if p_op.isidentifier(): # wildcard like 'x' + if p_op in bindings: + if bindings[p_op] != i_op: + return False + else: + bindings[p_op] = i_op + else: + if p_op != i_op: + return False + return True + + def match_window(self, patterns: List[Instruction], window: List[Instruction]) -> Union[Dict[str, str], None]: + if len(patterns) != len(window): + return None + bindings = {} + for p, i in zip(patterns, window): + if not self.match_instruction(p, i, bindings): + return None + return bindings + def parse_instruction(self, line: str) -> Instruction: + # Assumes format: OPCODE operand1, operand2 + parts = line.strip().split(None, 1) + opcode = parts[0] + operands = re.split(r'\s*,\s*', parts[1]) if len(parts) > 1 else [] + return Instruction(opcode, operands) + + def apply_replacement(self, replacements: List[Instruction], bindings: dict[str, str]) -> List[Instruction]: + result = [] + for pattern in replacements: + operands = [bindings.get(op, op) for op in pattern.operands] + result.append(Instruction(pattern.opcode, operands)) + return result def peephole(self): - pass \ No newline at end of file + self.lines = [self.parse_instruction(line) for line in self.lines] + + i = 0 + while i < len(self.lines): + matched = False + for rule in self.rules: + window = self.lines[i:i+len(rule.match)] + bindings = self.match_window(rule.match, window) + if bindings is not None: + replacement_instrs = self.apply_replacement(rule.replace, bindings) + self.lines[i:i + len(rule.match)] = replacement_instrs + matched = True + break + if not matched: + i += 1 + + self.lines = [f"{line.opcode} {', '.join(line.operands)}\n" for line in self.lines] + return self.lines \ No newline at end of file diff --git a/optimizers/x86_64.py b/optimizers/x86_64.py index bda678f..709b628 100644 --- a/optimizers/x86_64.py +++ b/optimizers/x86_64.py @@ -1,11 +1,59 @@ -from optimizers.optimizer import Optimizer +from optimizers.optimizer import Optimizer, PeepholeRule, Instruction class X86_64Optimizer(Optimizer): - def peephole(self): - lines = [] - - for line in self.lines: - lines.append(line) - - self.final_str = ''.join(lines) - return self.final_str \ No newline at end of file + def __init__(self, lines, window_size = 5): + super().__init__(lines, window_size) + self.rules = [ + PeepholeRule( + match=[ + Instruction("setg",["al"]), + Instruction("movzx", ["rax", "al"]), + Instruction("push", ["rax"]), + Instruction("mov", ["eax", "x"]), + Instruction("test", ["eax", "eax"]), + Instruction("jnz", ["y"]) + ], + replace=[ + Instruction("jg", ["y"]) + ] + ), + PeepholeRule( + match=[ + Instruction("setl",["al"]), + Instruction("movzx", ["rax", "al"]), + Instruction("push", ["rax"]), + Instruction("mov", ["eax", "x"]), + Instruction("test", ["eax", "eax"]), + Instruction("jnz", ["y"]) + ], + replace=[ + Instruction("jl", ["y"]) + ] + ), + PeepholeRule( + match=[ + Instruction("sete",["al"]), + Instruction("movzx", ["rax", "al"]), + Instruction("push", ["rax"]), + Instruction("mov", ["eax", "x"]), + Instruction("test", ["eax", "eax"]), + Instruction("jnz", ["y"]) + ], + replace=[ + Instruction("je", ["y"]) + ] + ), + PeepholeRule( + match=[ + Instruction("setne",["al"]), + Instruction("movzx", ["rax", "al"]), + Instruction("push", ["rax"]), + Instruction("mov", ["eax", "x"]), + Instruction("test", ["eax", "eax"]), + Instruction("jnz", ["y"]) + ], + replace=[ + Instruction("jne", ["y"]) + ] + ), + ] \ No newline at end of file diff --git a/out b/out index 07f4e0fc66689b5f62c3df2dc9a5798c31c4df2a..a9a5b34db08154aef01e8d912c2a38580d59fcd3 100644 GIT binary patch literal 9024 zcmeI2F-yZx5XY}+Q*0L_bPyCwK@c2DRRl$mf+$4_I=M+nX~Cr}G!ZNg{Qz!$n$n^A zF<*8~#|!=H*yY3bh`s>z60{}in zPN=Ycl+Z6x_oyl%pDr{&n)iQV1U z-4hpCi`(f!z1|2zy9(4>%^(WUbeaIAu-}e?2HL1+?X7rG>pp^#iRJzO)~w+I^lnW} z1uZ7rxGtkX+FX-z4UvlIP<~nj;pJOlR)@j!$@fdS4$sXS&$lC=0M)=7g`|z delta 310 zcmX@$)}T5;L)<}-0S+7(EEt#=92i&`SSH#la&CZ1Y?!!Ecw&tVrwf$tvhk)m|0G5W zryU@H00`;P?V`fr(R_f>qZ7#3!SL`at4DVXP{{HI|NH|U{M!zAbh4;)v#7KlD80PH z2B^`a+eT$_f`HuQ1|^osIto(4j0`*i4j?1pKx*