From 59ccc92089200dd020edcdfabc4d617aec7c66cb Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Tue, 24 Dec 2024 14:29:05 +0200 Subject: [PATCH 01/19] phi fix --- vyper/venom/passes/make_ssa.py | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/vyper/venom/passes/make_ssa.py b/vyper/venom/passes/make_ssa.py index 56d3e1b7d3..9dba297549 100644 --- a/vyper/venom/passes/make_ssa.py +++ b/vyper/venom/passes/make_ssa.py @@ -35,10 +35,14 @@ def _add_phi_nodes(self): Add phi nodes to the function. """ self._compute_defs() - work = {var: 0 for var in self.dom.dfs_walk} - has_already = {var: 0 for var in self.dom.dfs_walk} + work = {bb: 0 for bb in self.dom.dfs_walk} + has_already = {bb: 0 for bb in self.dom.dfs_walk} i = 0 + # for bb in self.dom.dfs_walk: + # if len(bb.get_phi_assignments()) > 0: + # has_already[bb] = 1 + # Iterate over all variables for var, d in self.defs.items(): i += 1 @@ -58,6 +62,9 @@ def _add_phi_nodes(self): def _place_phi(self, var: IRVariable, basic_block: IRBasicBlock): if var not in basic_block.liveness_in_vars: return + + if var in basic_block.get_phi_assignments(): + return args: list[IROperand] = [] for bb in basic_block.cfg_in: @@ -106,8 +113,9 @@ def _rename_vars(self, basic_block: IRBasicBlock): assert inst.output is not None, "Phi instruction without output" for i, op in enumerate(inst.operands): if op == basic_block.label: + var = inst.operands[i + 1] inst.operands[i + 1] = IRVariable( - inst.output.name, version=self.var_name_stacks[inst.output.name][-1] + var.name, version=self.var_name_stacks[var.name][-1] ) for bb in self.dom.dominated[basic_block]: @@ -153,4 +161,4 @@ def _compute_defs(self): for var in assignments: if var not in self.defs: self.defs[var] = OrderedSet() - self.defs[var].add(bb) + self.defs[var].add(bb) \ No newline at end of file From ad8d8fe3d3891341bb3952ae127493949419ffa9 Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Tue, 24 Dec 2024 14:31:31 +0200 Subject: [PATCH 02/19] remove test code --- vyper/venom/passes/make_ssa.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/vyper/venom/passes/make_ssa.py b/vyper/venom/passes/make_ssa.py index 9dba297549..1e3de4e406 100644 --- a/vyper/venom/passes/make_ssa.py +++ b/vyper/venom/passes/make_ssa.py @@ -63,9 +63,6 @@ def _place_phi(self, var: IRVariable, basic_block: IRBasicBlock): if var not in basic_block.liveness_in_vars: return - if var in basic_block.get_phi_assignments(): - return - args: list[IROperand] = [] for bb in basic_block.cfg_in: if bb == basic_block: From 421c9977c5d9d73f373934fa91013c9372d161eb Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Tue, 24 Dec 2024 14:32:29 +0200 Subject: [PATCH 03/19] lint --- vyper/venom/passes/make_ssa.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vyper/venom/passes/make_ssa.py b/vyper/venom/passes/make_ssa.py index 1e3de4e406..3182bbbe1a 100644 --- a/vyper/venom/passes/make_ssa.py +++ b/vyper/venom/passes/make_ssa.py @@ -62,7 +62,7 @@ def _add_phi_nodes(self): def _place_phi(self, var: IRVariable, basic_block: IRBasicBlock): if var not in basic_block.liveness_in_vars: return - + args: list[IROperand] = [] for bb in basic_block.cfg_in: if bb == basic_block: @@ -158,4 +158,4 @@ def _compute_defs(self): for var in assignments: if var not in self.defs: self.defs[var] = OrderedSet() - self.defs[var].add(bb) \ No newline at end of file + self.defs[var].add(bb) From 6f58d73193ea76183976b205a0f04840fe23d0bf Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Tue, 24 Dec 2024 14:39:46 +0200 Subject: [PATCH 04/19] cleanup --- vyper/venom/passes/make_ssa.py | 4 ---- 1 file changed, 4 deletions(-) diff --git a/vyper/venom/passes/make_ssa.py b/vyper/venom/passes/make_ssa.py index 3182bbbe1a..33d6f7ba58 100644 --- a/vyper/venom/passes/make_ssa.py +++ b/vyper/venom/passes/make_ssa.py @@ -39,10 +39,6 @@ def _add_phi_nodes(self): has_already = {bb: 0 for bb in self.dom.dfs_walk} i = 0 - # for bb in self.dom.dfs_walk: - # if len(bb.get_phi_assignments()) > 0: - # has_already[bb] = 1 - # Iterate over all variables for var, d in self.defs.items(): i += 1 From bcbb5fe1d147dd6e426184052bb6cbb32fc971ef Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 09:07:01 -0500 Subject: [PATCH 05/19] add phi parse test --- tests/functional/venom/parser/test_parsing.py | 121 +++++++++++++++++- 1 file changed, 120 insertions(+), 1 deletion(-) diff --git a/tests/functional/venom/parser/test_parsing.py b/tests/functional/venom/parser/test_parsing.py index f18a51fe76..bd536a8cfa 100644 --- a/tests/functional/venom/parser/test_parsing.py +++ b/tests/functional/venom/parser/test_parsing.py @@ -1,4 +1,4 @@ -from tests.venom_utils import assert_ctx_eq +from tests.venom_utils import assert_bb_eq, assert_ctx_eq from vyper.venom.basicblock import IRBasicBlock, IRLabel, IRLiteral, IRVariable from vyper.venom.context import DataItem, DataSection, IRContext from vyper.venom.function import IRFunction @@ -231,3 +231,122 @@ def test_multi_function_and_data(): ] assert_ctx_eq(parsed_ctx, expected_ctx) + + +def test_phis(): + # @external + # def _loop() -> uint256: + # res: uint256 = 9 + # for i: uint256 in range(res, bound=10): + # res = res + i + # return res + source = """ + function __main_entry { + __main_entry: ; IN=[] OUT=[fallback, 1_then] => {} + %27 = 0 + %1 = calldataload %27 + %28 = %1 + %29 = 224 + %2 = shr %29, %28 + %31 = %2 + %30 = 1729138561 + %4 = xor %30, %31 + %32 = %4 + jnz %32, @fallback, @1_then + ; (__main_entry) + + + 1_then: ; IN=[__main_entry] OUT=[4_condition] => {%11, %var8_0} + %6 = callvalue + %33 = %6 + %7 = iszero %33 + %34 = %7 + assert %34 + %var8_0 = 9 + %11 = 0 + nop + jmp @4_condition + ; (__main_entry) + + + 4_condition: ; IN=[1_then, 5_body] OUT=[5_body, 7_exit] => {%11:3, %var8_0:2} + %var8_0:2 = phi @1_then, %var8_0, @5_body, %var8_0:3 + %11:3 = phi @1_then, %11, @5_body, %11:4 + %35 = %11:3 + %36 = 9 + %15 = xor %36, %35 + %37 = %15 + jnz %37, @5_body, @7_exit + ; (__main_entry) + + + 5_body: ; IN=[4_condition] OUT=[4_condition] => {%11:4, %var8_0:3} + %38 = %11:3 + %39 = %var8_0:2 + %22 = add %39, %38 + %41 = %22 + %40 = %var8_0:2 + %24 = gt %40, %41 + %42 = %24 + %25 = iszero %42 + %43 = %25 + assert %43 + %var8_0:3 = %22 + %44 = %11:3 + %45 = 1 + %11:4 = add %45, %44 + jmp @4_condition + ; (__main_entry) + + + 7_exit: ; IN=[4_condition] OUT=[] => {} + %46 = %var8_0:2 + %47 = 64 + mstore %47, %46 + %48 = 32 + %49 = 64 + return %49, %48 + ; (__main_entry) + + + fallback: ; IN=[__main_entry] OUT=[] => {} + %50 = 0 + %51 = 0 + revert %51, %50 + stop + ; (__main_entry) + } ; close function __main_entry + """ + ctx = parse_venom(source) + + expected_ctx = IRContext() + expected_ctx.add_function(entry_fn := IRFunction(IRLabel("__main_entry"))) + + expect_bb = IRBasicBlock(IRLabel("4_condition"), entry_fn) + entry_fn.append_basic_block(expect_bb) + + expect_bb.append_instruction( + "phi", + IRLabel("1_then"), + IRVariable("%var8_0"), + IRLabel("5_body"), + IRVariable("%var8_0:3"), + ret=IRVariable("var8_0:2"), + ) + expect_bb.append_instruction( + "phi", + IRLabel("1_then"), + IRVariable("%11"), + IRLabel("5_body"), + IRVariable("%11:4"), + ret=IRVariable("11:3"), + ) + expect_bb.append_instruction("store", IRVariable("11:3"), ret=IRVariable("%35")) + expect_bb.append_instruction("store", IRLiteral(9), ret=IRVariable("%36")) + expect_bb.append_instruction("xor", IRVariable("%35"), IRVariable("%36"), ret=IRVariable("%15")) + expect_bb.append_instruction("store", IRVariable("%15"), ret=IRVariable("%37")) + expect_bb.append_instruction("jnz", IRVariable("%37"), IRLabel("5_body"), IRLabel("7_exit")) + # other basic blocks omitted for brevity + + parsed_fn = next(iter(ctx.functions.values())) + assert_bb_eq(parsed_fn.get_basic_block(expect_bb.label.name), expect_bb) From 1728bee6050fe10a501e33c096e91294d012ab4d Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 09:08:17 -0500 Subject: [PATCH 06/19] test that parsed venom can go to bytecode --- tests/functional/venom/test_venom_repr.py | 39 +++++++++++++++++++++-- 1 file changed, 37 insertions(+), 2 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index c25ce381d8..85f71d055a 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -1,9 +1,12 @@ import glob +import textwrap import pytest from tests.venom_utils import assert_ctx_eq, parse_venom from vyper.compiler import compile_code +from vyper.compiler.phases import generate_bytecode +from vyper.venom import generate_assembly_experimental, run_passes_on from vyper.venom.context import IRContext """ @@ -16,15 +19,47 @@ def get_example_vy_filenames(): @pytest.mark.parametrize("vy_filename", get_example_vy_filenames()) -def test_round_trip(vy_filename, optimize, request): +def test_round_trip_example(vy_filename, optimize): + """ + Check all examples round trip + """ path = f"examples/{vy_filename}" with open(path) as f: vyper_source = f.read() - out = compile_code(vyper_source, output_formats=["bb_runtime"]) + _round_trip_helper(vyper_source, optimize) + +vyper_sources = [""" + @external + def _loop() -> uint256: + res: uint256 = 9 + for i: uint256 in range(res, bound=10): + res = res + i + return res + """] + +@pytest.mark.parametrize("vyper_source", vyper_sources) +def test_round_trip_source(vyper_source, optimize): + vyper_source = textwrap.dedent(vyper_source) + _round_trip_helper(vyper_source, optimize) + + +def _round_trip_helper(vyper_source, optimize): + out = compile_code(vyper_source, output_formats=["bb_runtime", "bytecode_runtime"]) bb_runtime = out["bb_runtime"] venom_code = IRContext.__repr__(bb_runtime) ctx = parse_venom(venom_code) assert_ctx_eq(bb_runtime, ctx) + + # check it's valid to run venom passes+analyses + run_passes_on(ctx, optimize) + + asm = generate_assembly_experimental(ctx) + bytecode = generate_bytecode(asm, compiler_metadata=None) + bytecode = f"0x{bytecode.hex()}" + + # TODO investigate: bytecodes should be equal (even without + # `run_passes_on`) but not for some reason + # assert bytecode == out["bytecode_runtime"] From 74c2446b7bb9c31f64d656f1f12224cf3706ba03 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 09:50:50 -0500 Subject: [PATCH 07/19] fix IRVariable constructor, clean up other IROperand constructors --- vyper/venom/basicblock.py | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/vyper/venom/basicblock.py b/vyper/venom/basicblock.py index b0f0b00341..4c75c67700 100644 --- a/vyper/venom/basicblock.py +++ b/vyper/venom/basicblock.py @@ -117,7 +117,7 @@ class IROperand: """ value: Any - _hash: Optional[int] + _hash: Optional[int] = None def __init__(self, value: Any) -> None: self.value = value @@ -149,9 +149,8 @@ class IRLiteral(IROperand): value: int def __init__(self, value: int) -> None: - super().__init__(value) assert isinstance(value, int), "value must be an int" - self.value = value + super().__init__(value) class IRVariable(IROperand): @@ -163,17 +162,17 @@ class IRVariable(IROperand): version: Optional[int] def __init__(self, name: str, version: int = 0) -> None: - super().__init__(name) assert isinstance(name, str) - assert isinstance(version, int | None) + # TODO: allow version to be None + assert isinstance(version, int) if not name.startswith("%"): name = f"%{name}" self._name = name self.version = version + value = name if version > 0: - self.value = f"{name}:{version}" - else: - self.value = name + value = f"{name}:{version}" + super().__init__(value) @property def name(self) -> str: @@ -193,8 +192,8 @@ class IRLabel(IROperand): def __init__(self, value: str, is_symbol: bool = False) -> None: assert isinstance(value, str), f"not a str: {value} ({type(value)})" assert len(value) > 0 - super().__init__(value) self.is_symbol = is_symbol + super().__init__(value) _IS_IDENTIFIER = re.compile("[0-9a-zA-Z_]*") From 907af7d563edfd3b1f3d32f34e4de7265d8a5ad3 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 09:52:53 -0500 Subject: [PATCH 08/19] lint --- tests/functional/venom/test_venom_repr.py | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 85f71d055a..e37c9d3eaf 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -1,6 +1,6 @@ import glob - import textwrap + import pytest from tests.venom_utils import assert_ctx_eq, parse_venom @@ -29,14 +29,18 @@ def test_round_trip_example(vy_filename, optimize): _round_trip_helper(vyper_source, optimize) -vyper_sources = [""" + +vyper_sources = [ + """ @external def _loop() -> uint256: res: uint256 = 9 for i: uint256 in range(res, bound=10): res = res + i return res - """] + """ +] + @pytest.mark.parametrize("vyper_source", vyper_sources) def test_round_trip_source(vyper_source, optimize): From 105654c23d94af48447b26302dcca571e2951ef0 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 09:55:39 -0500 Subject: [PATCH 09/19] comments --- tests/functional/venom/test_venom_repr.py | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index e37c9d3eaf..24e96e798e 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -19,7 +19,7 @@ def get_example_vy_filenames(): @pytest.mark.parametrize("vy_filename", get_example_vy_filenames()) -def test_round_trip_example(vy_filename, optimize): +def test_round_trip_examples(vy_filename, optimize): """ Check all examples round trip """ @@ -43,7 +43,10 @@ def _loop() -> uint256: @pytest.mark.parametrize("vyper_source", vyper_sources) -def test_round_trip_source(vyper_source, optimize): +def test_round_trip_sources(vyper_source, optimize): + """ + Test vyper_sources round trip + """ vyper_source = textwrap.dedent(vyper_source) _round_trip_helper(vyper_source, optimize) @@ -58,6 +61,8 @@ def _round_trip_helper(vyper_source, optimize): assert_ctx_eq(bb_runtime, ctx) # check it's valid to run venom passes+analyses + # (note this breaks bytecode equality, in the future we should + # test that separately) run_passes_on(ctx, optimize) asm = generate_assembly_experimental(ctx) From 120c09365a3b73ab48d9c91fc3ea6d700af84f44 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 10:26:26 -0500 Subject: [PATCH 10/19] update phi test with new machinery --- tests/unit/compiler/venom/test_make_ssa.py | 87 ++++++++++++---------- 1 file changed, 46 insertions(+), 41 deletions(-) diff --git a/tests/unit/compiler/venom/test_make_ssa.py b/tests/unit/compiler/venom/test_make_ssa.py index aa3fead6bf..6d4bbf90b8 100644 --- a/tests/unit/compiler/venom/test_make_ssa.py +++ b/tests/unit/compiler/venom/test_make_ssa.py @@ -1,48 +1,53 @@ +from tests.venom_utils import assert_ctx_eq, parse_venom from vyper.venom.analysis import IRAnalysesCache -from vyper.venom.basicblock import IRBasicBlock, IRLabel -from vyper.venom.context import IRContext from vyper.venom.passes import MakeSSA -def test_phi_case(): - ctx = IRContext() - fn = ctx.create_function("_global") - - bb = fn.get_basic_block() - - bb_cont = IRBasicBlock(IRLabel("condition"), fn) - bb_then = IRBasicBlock(IRLabel("then"), fn) - bb_else = IRBasicBlock(IRLabel("else"), fn) - bb_if_exit = IRBasicBlock(IRLabel("if_exit"), fn) - fn.append_basic_block(bb_cont) - fn.append_basic_block(bb_then) - fn.append_basic_block(bb_else) - fn.append_basic_block(bb_if_exit) - - v = bb.append_instruction("mload", 64) - bb_cont.append_instruction("jnz", v, bb_then.label, bb_else.label) +def _check_pre_post(pre, post): + ctx = parse_venom(pre) + for fn in ctx.functions.values(): + ac = IRAnalysesCache(fn) + MakeSSA(ac, fn).run_pass() + assert_ctx_eq(ctx, parse_venom(post)) - bb_if_exit.append_instruction("add", v, 1, ret=v) - bb_if_exit.append_instruction("jmp", bb_cont.label) - bb_then.append_instruction("assert", bb_then.append_instruction("mload", 96)) - bb_then.append_instruction("jmp", bb_if_exit.label) - bb_else.append_instruction("jmp", bb_if_exit.label) - - bb.append_instruction("jmp", bb_cont.label) - - ac = IRAnalysesCache(fn) - MakeSSA(ac, fn).run_pass() - - condition_block = fn.get_basic_block("condition") - assert len(condition_block.instructions) == 2 +def test_phi_case(): + pre = """ + function loop { + main: + %v = mload 64 + jmp @test + test: + jnz %v, @then, @else + then: + %t = mload 96 + assert %t + jmp @if_exit + else: + jmp @if_exit + if_exit: + %v = add %v, 1 + jmp @test + } + """ + post = """ + function loop { + main: + %v = mload 64 + jmp @test + test: + %v:1 = phi @main, %v, @if_exit, %v:2 + jnz %v:1, @then, @else + then: + %t = mload 96 + assert %t + jmp @if_exit + else: + jmp @if_exit + if_exit: + %v:2 = add %v:1, 1 + jmp @test + } + """ + _check_pre_post(pre, post) - phi_inst = condition_block.instructions[0] - assert phi_inst.opcode == "phi" - assert phi_inst.operands[0].name == "_global" - assert phi_inst.operands[1].name == "%1" - assert phi_inst.operands[2].name == "if_exit" - assert phi_inst.operands[3].name == "%1" - assert phi_inst.output.name == "%1" - assert phi_inst.output.value != phi_inst.operands[1].value - assert phi_inst.output.value != phi_inst.operands[3].value From 2e085ccf1a55cb1e28463e8e6b22cf59603fa072 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 10:41:53 -0500 Subject: [PATCH 11/19] more lint --- tests/unit/compiler/venom/test_make_ssa.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/unit/compiler/venom/test_make_ssa.py b/tests/unit/compiler/venom/test_make_ssa.py index 6d4bbf90b8..7f6b2c0cba 100644 --- a/tests/unit/compiler/venom/test_make_ssa.py +++ b/tests/unit/compiler/venom/test_make_ssa.py @@ -50,4 +50,3 @@ def test_phi_case(): } """ _check_pre_post(pre, post) - From 8bc96dd7628de87369ad976743529fc75200474b Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 10:56:13 -0500 Subject: [PATCH 12/19] remove an old comment --- vyper/venom/passes/make_ssa.py | 1 - 1 file changed, 1 deletion(-) diff --git a/vyper/venom/passes/make_ssa.py b/vyper/venom/passes/make_ssa.py index 33d6f7ba58..ee013e0f1d 100644 --- a/vyper/venom/passes/make_ssa.py +++ b/vyper/venom/passes/make_ssa.py @@ -96,7 +96,6 @@ def _rename_vars(self, basic_block: IRBasicBlock): self.var_name_counters[v_name] = i + 1 inst.output = IRVariable(v_name, version=i) - # note - after previous line, inst.output.name != v_name outs.append(inst.output.name) for bb in basic_block.cfg_out: From fdb2cb967819f5dd40a14b4e8d61626dfbbc09b2 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 12:14:31 -0500 Subject: [PATCH 13/19] delete bytecode generation as it modifies the bb_runtime output --- tests/functional/venom/test_venom_repr.py | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 24e96e798e..3d48d9f52b 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -52,7 +52,7 @@ def test_round_trip_sources(vyper_source, optimize): def _round_trip_helper(vyper_source, optimize): - out = compile_code(vyper_source, output_formats=["bb_runtime", "bytecode_runtime"]) + out = compile_code(vyper_source, output_formats=["bb_runtime"]) bb_runtime = out["bb_runtime"] venom_code = IRContext.__repr__(bb_runtime) @@ -65,10 +65,10 @@ def _round_trip_helper(vyper_source, optimize): # test that separately) run_passes_on(ctx, optimize) + # test we can generate assembly+bytecode asm = generate_assembly_experimental(ctx) - bytecode = generate_bytecode(asm, compiler_metadata=None) - bytecode = f"0x{bytecode.hex()}" + _bytecode = generate_bytecode(asm, compiler_metadata=None) # TODO investigate: bytecodes should be equal (even without # `run_passes_on`) but not for some reason - # assert bytecode == out["bytecode_runtime"] + # assert "0x" + _bytecode.hex() == out["bytecode_runtime"] From be46fbc4a5f1b12a1bc6613559a8a591c6d8c1f4 Mon Sep 17 00:00:00 2001 From: Harry Kalogirou Date: Tue, 24 Dec 2024 19:19:28 +0200 Subject: [PATCH 14/19] lint --- tests/functional/venom/test_venom_repr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 3d48d9f52b..87a87be2a1 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -67,7 +67,7 @@ def _round_trip_helper(vyper_source, optimize): # test we can generate assembly+bytecode asm = generate_assembly_experimental(ctx) - _bytecode = generate_bytecode(asm, compiler_metadata=None) + generate_bytecode(asm, compiler_metadata=None) # TODO investigate: bytecodes should be equal (even without # `run_passes_on`) but not for some reason From 01ce67427774de684d3f5afcbe0e25aef7e92fc5 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 13:02:36 -0500 Subject: [PATCH 15/19] add a note --- tests/functional/venom/test_venom_repr.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 87a87be2a1..2f8a49bcad 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -52,7 +52,11 @@ def test_round_trip_sources(vyper_source, optimize): def _round_trip_helper(vyper_source, optimize): + # note: compiling any later stage than bb_runtime like `asm` or + # `bytecode` modifies the bb_runtime data structure in place and results + # in normalization of the venom cfg (which breaks again make_ssa) out = compile_code(vyper_source, output_formats=["bb_runtime"]) + bb_runtime = out["bb_runtime"] venom_code = IRContext.__repr__(bb_runtime) From 48ec7a1f4b5d651cfc2938568114a2bfcb91f25b Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 13:12:44 -0500 Subject: [PATCH 16/19] expand tests so that we test bytecode equality as well --- tests/functional/venom/test_venom_repr.py | 36 +++++++++++++++++++++-- 1 file changed, 33 insertions(+), 3 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 2f8a49bcad..7ebfbce729 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -30,6 +30,7 @@ def test_round_trip_examples(vy_filename, optimize): _round_trip_helper(vyper_source, optimize) +# pure vyper sources vyper_sources = [ """ @external @@ -52,6 +53,18 @@ def test_round_trip_sources(vyper_source, optimize): def _round_trip_helper(vyper_source, optimize): + # different tests that we round-trip. + # split into two helpers because run_passes_on and + # generate_assembly_experimental are both destructive (mutating) on + # the IRContext + _helper1(vyper_source, optimize) + _helper2(vyper_source, optimize) + +def _helper1(vyper_source, optimize): + """ + Check that we are able to run passes on the round-tripped venom code + and that it is valid (generates bytecode) + """ # note: compiling any later stage than bb_runtime like `asm` or # `bytecode` modifies the bb_runtime data structure in place and results # in normalization of the venom cfg (which breaks again make_ssa) @@ -73,6 +86,23 @@ def _round_trip_helper(vyper_source, optimize): asm = generate_assembly_experimental(ctx) generate_bytecode(asm, compiler_metadata=None) - # TODO investigate: bytecodes should be equal (even without - # `run_passes_on`) but not for some reason - # assert "0x" + _bytecode.hex() == out["bytecode_runtime"] + +def _helper2(vyper_source, optimize): + """ + Check that we can compile to bytecode, and without running venom passes, + that the output bytecode is equal to going through the normal vyper pipeline + """ + out = compile_code(vyper_source, output_formats=["bb_runtime"]) + bb_runtime = out["bb_runtime"] + venom_code = IRContext.__repr__(bb_runtime) + + ctx = parse_venom(venom_code) + + assert_ctx_eq(bb_runtime, ctx) + + # test we can generate assembly+bytecode + asm = generate_assembly_experimental(ctx) + bytecode = generate_bytecode(asm, compiler_metadata=None) + + out = compile_code(vyper_source, output_formats=["bytecode_runtime"]) + assert "0x" + bytecode.hex() == out["bytecode_runtime"] From 52591ed2ee63b57dbd5b9165eef28d3bea62182e Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 16:18:28 -0500 Subject: [PATCH 17/19] fix lint --- tests/functional/venom/test_venom_repr.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 7ebfbce729..ccd652105e 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -60,6 +60,7 @@ def _round_trip_helper(vyper_source, optimize): _helper1(vyper_source, optimize) _helper2(vyper_source, optimize) + def _helper1(vyper_source, optimize): """ Check that we are able to run passes on the round-tripped venom code From 10f15dfa866bc32276cfb368670b83879d32d266 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 16:29:13 -0500 Subject: [PATCH 18/19] fix: pass through settings even if test suite is run without --experimental-codegen --- tests/functional/venom/test_venom_repr.py | 27 ++++++++++++++--------- 1 file changed, 16 insertions(+), 11 deletions(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index ccd652105e..975968001f 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -1,3 +1,4 @@ +import copy import glob import textwrap @@ -19,7 +20,7 @@ def get_example_vy_filenames(): @pytest.mark.parametrize("vy_filename", get_example_vy_filenames()) -def test_round_trip_examples(vy_filename, optimize): +def test_round_trip_examples(vy_filename, optimize, compiler_settings): """ Check all examples round trip """ @@ -27,7 +28,7 @@ def test_round_trip_examples(vy_filename, optimize): with open(path) as f: vyper_source = f.read() - _round_trip_helper(vyper_source, optimize) + _round_trip_helper(vyper_source, optimize, compiler_settings) # pure vyper sources @@ -44,21 +45,21 @@ def _loop() -> uint256: @pytest.mark.parametrize("vyper_source", vyper_sources) -def test_round_trip_sources(vyper_source, optimize): +def test_round_trip_sources(vyper_source, optimize, compiler_settings): """ Test vyper_sources round trip """ vyper_source = textwrap.dedent(vyper_source) - _round_trip_helper(vyper_source, optimize) + _round_trip_helper(vyper_source, optimize, compiler_settings) -def _round_trip_helper(vyper_source, optimize): - # different tests that we round-trip. - # split into two helpers because run_passes_on and +def _round_trip_helper(vyper_source, optimize, compiler_settings): + # helper function to test venom round-tripping thru the parser + # use two helpers because run_passes_on and # generate_assembly_experimental are both destructive (mutating) on # the IRContext _helper1(vyper_source, optimize) - _helper2(vyper_source, optimize) + _helper2(vyper_source, optimize, compiler_settings) def _helper1(vyper_source, optimize): @@ -88,12 +89,16 @@ def _helper1(vyper_source, optimize): generate_bytecode(asm, compiler_metadata=None) -def _helper2(vyper_source, optimize): +def _helper2(vyper_source, optimize, compiler_settings): """ Check that we can compile to bytecode, and without running venom passes, that the output bytecode is equal to going through the normal vyper pipeline """ - out = compile_code(vyper_source, output_formats=["bb_runtime"]) + settings = copy.copy(compiler_settings) + # bytecode equivalence only makes sense if we use venom pipeline + settings.experimental_codegen = True + + out = compile_code(vyper_source, settings=settings, output_formats=["bb_runtime"]) bb_runtime = out["bb_runtime"] venom_code = IRContext.__repr__(bb_runtime) @@ -105,5 +110,5 @@ def _helper2(vyper_source, optimize): asm = generate_assembly_experimental(ctx) bytecode = generate_bytecode(asm, compiler_metadata=None) - out = compile_code(vyper_source, output_formats=["bytecode_runtime"]) + out = compile_code(vyper_source, settings=settings, output_formats=["bytecode_runtime"]) assert "0x" + bytecode.hex() == out["bytecode_runtime"] From 33c06cbf8f09ad199a5577da0fc10e2c77858a8b Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Tue, 24 Dec 2024 18:38:14 -0500 Subject: [PATCH 19/19] properly pass thru optimize flag --- tests/functional/venom/test_venom_repr.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/functional/venom/test_venom_repr.py b/tests/functional/venom/test_venom_repr.py index 975968001f..5136672a03 100644 --- a/tests/functional/venom/test_venom_repr.py +++ b/tests/functional/venom/test_venom_repr.py @@ -107,7 +107,7 @@ def _helper2(vyper_source, optimize, compiler_settings): assert_ctx_eq(bb_runtime, ctx) # test we can generate assembly+bytecode - asm = generate_assembly_experimental(ctx) + asm = generate_assembly_experimental(ctx, optimize=optimize) bytecode = generate_bytecode(asm, compiler_metadata=None) out = compile_code(vyper_source, settings=settings, output_formats=["bytecode_runtime"])