diff options
Diffstat (limited to 'atk16_asm/optimizer.py')
| -rw-r--r-- | atk16_asm/optimizer.py | 189 |
1 files changed, 189 insertions, 0 deletions
diff --git a/atk16_asm/optimizer.py b/atk16_asm/optimizer.py new file mode 100644 index 0000000..0ee2837 --- /dev/null +++ b/atk16_asm/optimizer.py @@ -0,0 +1,189 @@ +from tokenizer import tokenize + +def format_asm_row(asm: str) -> str: + if not (asm.startswith("@") or asm.startswith(";")) and not asm.startswith(" ") and len(asm) > 0: + return " " + asm + else: + return asm + +class Optimizer: + def __init__(self): + pass + + def optimize(self, asm_str: str): + asm = asm_str.split("\n") + asm = [row.strip() for row in asm] + asm = [self.strip_comment(row) for row in asm] + asm = [row for row in asm if not len(row) == 0] + asm = [tokenize(row, retain_curlies=True) for row in asm] + asm = self.compact_spu_spo_pattern(asm) + + # TODO: not safe when setting loading SP and FP + # ldr RA SP + # mov RA FP + # gets optimized to + # ldr RA FP + #asm = self.compact_target_mov_pattern(asm) + #asm = self.compact_target_mov_pattern(asm) + + # TODO: not safe at all. E.g. breaks a while True: pass loop + #asm = self.compact_mov_source_pattern(asm) + #asm = self.compact_mov_source_pattern(asm) + + asm = self.compact_spu_load_spo_pattern(asm) + # asm = self.convert_alr_to_ali(asm) + result = "\n".join([format_asm_row(" ".join(row)) for row in asm]) + + return result + + def strip_comment(self, row: str): + ret: str = "" + for c in row: + if c == ";": break + ret += c + + return ret + + def compact_spu_spo_pattern(self, asm: list[list[str]]) -> list[list[str]]: + i = 0 + result: list[list[str]] = [] + while i < len(asm): + current = asm[i] + next = asm[i + 1] if i + 1 < len(asm) else None + i += 1 + if current[0].startswith("@") or next is None: + result.append(current) + continue + + if current[0] == "spu" and next[0] == "spo": + print("=== compact_spu_spo_pattern") + print(current) + print(next) + + arg_current = current[1] + arg_next = next[1] + + print("=== arg_current:", arg_current) + print("=== arg_next:", arg_next) + + if arg_current == arg_next: + print("=== pass") + pass # remove both spu and spo + else: + print("=== mov") + mov = ["mov", arg_current, arg_next] + result.append(mov) + print("=== mov:", mov) + + print("=== last of result:", result[len(result) - 1]) + print() + i += 1 + continue + + result.append(current) + + return result + + def compact_target_mov_pattern(self, asm: list[list[str]]) -> list[list[str]]: + ops_with_target = ["ldi", "ldr", "add", "sub", "addi", "subi", "and", "or", "xor", "sll", "slr", "sar", "slli", "slri", "sari", "inc", "dec", "mov", "ali", "alr", "lpc"] + i = 0 + result: list[list[str]] = [] + while i < len(asm): + current = asm[i] + next = asm[i + 1] if i + 1 < len(asm) else None + i += 1 + if current[0].startswith("@") or next is None: + result.append(current) + continue + + if current[0] in ops_with_target and next[0] == "mov": + + op_op, op_operands, op_target_reg = current[0], current[1:len(current) - 1], current[len(current) - 1] + mov_from_reg, mov_to_reg = next[1], next[2] + + if op_target_reg == mov_from_reg: + ret = [op_op, *op_operands, mov_to_reg] + result.append(ret) + i += 1 + continue + + result.append(current) + + return result + + def compact_mov_source_pattern(self, asm: list[list[str]]) -> list[list[str]]: + ops_with_source = ["str", "ldr", "add", "sub", "addi", "subi", "and", "or", "xor", "sll", "slr", "sar", "slli", "slri", "sari", "mov", "ali", "alr"] + i = 0 + result: list[list[str]] = [] + while i < len(asm): + current = asm[i] + next = asm[i + 1] if i + 1 < len(asm) else None + i += 1 + if current[0].startswith("@") or next is None: + result.append(current) + continue + + if current[0] == "mov" and next[0] in ops_with_source: + mov_from_reg, mov_to_reg = current[1], current[2] + op_op, op_source_reg, op_operands = next[0], next[1], next[2:] + + if op_source_reg == mov_to_reg: + ret = [op_op, op_source_reg, *op_operands] + result.append(ret) + i += 1 + continue + + result.append(current) + + return result + + def compact_spu_load_spo_pattern(self, asm: list[list[str]]) -> list[list[str]]: + # spu RA + # ldi int_7 RA + # ldr RA RB + # spo RA + # OR + # spu RA + # ldi 3 RB + # spo RA + + i = 0 + result: list[list[str]] = [] + while i < len(asm): + instr0 = asm[i] + instr1 = asm[i + 1] if i + 1 < len(asm) else None + instr2 = asm[i + 2] if i + 2 < len(asm) else None + instr3 = asm[i + 3] if i + 3 < len(asm) else None + i += 1 + if instr0[0].startswith("@") or instr1 is None or instr2 is None or instr3 is None: + result.append(instr0) + continue + + if instr0[0] == "spu" and instr1[0] == "ldi" and instr2[0] == "ldr" and instr3[0] == "spo": + spu_op, spu_reg = instr0 + ldi_op, ldi_imm, ldi_target_reg = instr1 + ldr_op, ldr_from_reg, ldr_to_reg = instr2 + spo_op, spo_reg = instr3 + + if spu_reg == spo_reg and ldi_target_reg == ldr_from_reg and ldr_from_reg != ldr_to_reg: + ret0 = f"ldi {ldi_imm} {ldr_to_reg}".split() + ret1 = f"ldr {ldr_to_reg} {ldr_to_reg}".split() + result.append(ret0) + result.append(ret1) + i += 3 + continue + + elif instr0[0] == "spu" and instr1[0] == "ldi" and instr2[0] == "spo": + spu_op, spu_reg = instr0 + ldi_op, ldi_imm, ldi_target_reg = instr1 + spo_op, spo_reg = instr2 + + if spu_reg == spo_reg and ldi_target_reg != spu_reg: + ret0 = f"ldi {ldi_imm} {ldi_target_reg}".split() + result.append(ret0) + i += 2 + continue + + result.append(instr0) + + return result |
