From b8b49d34f7a1691598e53872706e237df63a325f Mon Sep 17 00:00:00 2001 From: Cursor Agent Date: Mon, 13 Jul 2026 14:16:12 +0000 Subject: [PATCH] Add addi-zero peephole rule and demo assembly sample Implement Topic 13 exercise rule: delete addi rd, rd, 0 no-ops at the assembly peephole layer. Add unit tests and benchmarks/fixtures/peephole_demo.asm for hands-on practice. Co-authored-by: zinoe-1 --- benchmarks/fixtures/peephole_demo.asm | 13 +++++++++++++ scratchv/backend/asm_peephole.py | 18 ++++++++++++++++-- tests/test_asm_peephole.py | 17 ++++++++++++++++- 3 files changed, 45 insertions(+), 3 deletions(-) create mode 100644 benchmarks/fixtures/peephole_demo.asm diff --git a/benchmarks/fixtures/peephole_demo.asm b/benchmarks/fixtures/peephole_demo.asm new file mode 100644 index 0000000..57c3103 --- /dev/null +++ b/benchmarks/fixtures/peephole_demo.asm @@ -0,0 +1,13 @@ +# Peephole optimizer demo (Topic 13) +# Run: python3 -m scratchv.backend.asm_peephole benchmarks/fixtures/peephole_demo.asm --report + +.text +main: + li a0, 5 + addi a0, a0, 3 # li+addi fusion -> li a0, 8 + addi a0, a0, 0 # addi zero elimination -> deleted + mv t0, t1 + mv t2, t0 + beq x0, x0, .Ldone # beq zero-zero -> j .Ldone +.Ldone: + ret diff --git a/scratchv/backend/asm_peephole.py b/scratchv/backend/asm_peephole.py index 5aa35c7..45a2ddb 100644 --- a/scratchv/backend/asm_peephole.py +++ b/scratchv/backend/asm_peephole.py @@ -192,8 +192,16 @@ def _lines_to_asm(lines: list[AsmLine]) -> str: # --------------------------------------------------------------------------- def _default_rules() -> list[PeepholeRule]: - """Return the set of five default peephole optimization rules.""" + """Return the set of default peephole optimization rules.""" return [ + # Rule 0: addi x, x, 0 -> delete (no-op increment) + PeepholeRule( + name="addi zero elimination", + pattern=["addi"], + replacement=[], + register_constraints=[(0, 0, 1)], + ), + # Rule 1: addi x, x, a; addi x, x, b -> addi x, x, a+b PeepholeRule( name="addi+addi fusion", @@ -326,6 +334,12 @@ def _match_rule( if ops[0] not in ("x0", "zero") or ops[1] not in ("x0", "zero"): return None + # addi rd, rd, 0 is a no-op + if rule.name == "addi zero elimination": + ops = window[0].operands + if len(ops) < 3 or ops[2] != "0": + return None + return bindings @@ -339,7 +353,7 @@ class AsmPeepholeOptimizer: Parameters ---------- rules: - List of peephole rules. If None, uses the five default rules. + List of peephole rules. If None, uses the default rule set. Usage:: diff --git a/tests/test_asm_peephole.py b/tests/test_asm_peephole.py index 22dc3bb..6111de7 100644 --- a/tests/test_asm_peephole.py +++ b/tests/test_asm_peephole.py @@ -35,7 +35,22 @@ def test_roundtrip(self): class TestDefaultRules: - """Tests for the five default peephole rules.""" + """Tests for the default peephole rules.""" + + def test_addi_zero_elimination(self): + optimizer = AsmPeepholeOptimizer() + asm = " addi t0, t0, 0\n add t1, t2, t3\n" + result, changes = optimizer.optimize(asm) + assert changes >= 1 + assert "addi" not in result + assert "add" in result + + def test_addi_zero_elimination_preserves_nonzero(self): + optimizer = AsmPeepholeOptimizer() + asm = " addi t0, t0, 1\n add t1, t2, t3\n" + result, changes = optimizer.optimize(asm) + assert "addi t0, t0, 1" in result or "addi" in result + assert "add" in result def test_addi_addi_fusion(self): optimizer = AsmPeepholeOptimizer()