Repository navigation
fix[venom]: fix various well formedness issues #5231
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
e3c8523
2b6d944
7809019
06ff659
e42e9a1
038cd56
84c1a5b
26a8a63
4a8f25f
73f093c
da07d23
6da9c9f
c3159ac
4ef25da
770ee21
73616d0
64a85d4
3d4fc91
ad1f1f6
79130e8
7b90af6
a4ba5ba
0262903
0dc1f89
00f04b9
ba12d1b
c061354
9efa351
73a88e0
99b2fa8
9e10c9e
5dc0451
4bd07cf
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,7 +7,7 @@ | |
| from vyper.venom.analysis.fcg import FCGGlobalAnalysis | ||
| from vyper.venom.analysis.readonly_memory_args import ReadonlyMemoryArgsGlobalAnalysis | ||
| from vyper.venom.basicblock import IRBasicBlock, IRInstruction, IRLabel, IROperand, IRVariable | ||
| from vyper.venom.call_layout import InvokeLayout, has_dret | ||
| from vyper.venom.call_layout import FunctionCallLayout, InvokeLayout, has_dret | ||
| from vyper.venom.context import IRContext | ||
| from vyper.venom.function import IRFunction | ||
| from vyper.venom.passes.base_pass import IRGlobalPass | ||
|
|
@@ -132,13 +132,18 @@ def _inline_call_site(self, func: IRFunction, call_site: IRInstruction) -> None: | |
| # operands[1:] + [operands[0]] reorder for raw IR. | ||
| binding_ops = InvokeLayout(self.ctx, call_site).bound_params | ||
|
|
||
| layout = FunctionCallLayout(func_copy) | ||
| retpc_inst = layout.retpc_param_opcode_inst | ||
| assert retpc_inst is not None | ||
| retpc_op = retpc_inst.output | ||
| retpc_inst.make_nop() | ||
| for bb in func_copy.get_basic_blocks(): | ||
| bb.parent = call_site_func | ||
| call_site_func.append_basic_block(bb) | ||
| param_idx = 0 | ||
| for inst in bb.instructions: | ||
| if inst.is_param: | ||
| # NOTE: one of these params is the return pc. | ||
| assert inst.opcode != "retpc_param" | ||
| inst.opcode = "assign" | ||
| val = binding_ops[param_idx] | ||
| inst.operands = [val] | ||
|
|
@@ -156,6 +161,7 @@ def _inline_call_site(self, func: IRFunction, call_site: IRInstruction) -> None: | |
| # host's own reclaim governs the inlined data. Whether the | ||
| # host publishes is determined solely by the host's own | ||
| # terminators (plain `ret` is callee-save). | ||
| assert retpc_op in inst.operands, retpc_op | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a valid raw Venom callee uses a plain Useful? React with 👍 / 👎. There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When a callee declares Useful? React with 👍 / 👎. |
||
| ret_values = [op for op in inst.operands[:-1] if not isinstance(op, IRLabel)] | ||
|
|
||
| # Map each returned value to corresponding callsite outputs | ||
|
|
@@ -173,6 +179,7 @@ def _inline_call_site(self, func: IRFunction, call_site: IRInstruction) -> None: | |
|
|
||
| for inst in bb.instructions: | ||
| if not inst.annotation: | ||
| assert retpc_op not in inst.operands, (inst, retpc_op) | ||
| inst.annotation = f"from {func.name}" | ||
|
|
||
| call_site_bb.instructions = call_site_bb.instructions[:call_idx] | ||
|
|
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -1,13 +1,17 @@ | ||
| from vyper.evm import address_space | ||
| from vyper.utils import OrderedSet, uniq | ||
| from vyper.venom import effects | ||
| from vyper.venom.analysis import BasePtrAnalysis, DFGAnalysis, LivenessAnalysis | ||
| from vyper.venom.analysis.load_analysis import LoadAnalysis | ||
| from vyper.venom.analysis.mem_alias import ( | ||
| MemoryAliasAnalysis, | ||
| StorageAliasAnalysis, | ||
| TransientAliasAnalysis, | ||
| can_create_mem_alias, | ||
| mem_alias_type_factory, | ||
| ) | ||
| from vyper.venom.analysis.mem_ssa import MemSSA, StorageSSA, TransientSSA | ||
| from vyper.venom.basicblock import IRInstruction | ||
| from vyper.venom.effects import EMPTY, FMP | ||
| from vyper.venom.passes.base_pass import IRPass | ||
|
|
||
|
|
||
|
|
@@ -19,8 +23,11 @@ class RemoveUnusedVariablesPass(IRPass): | |
| dfg: DFGAnalysis | ||
| work_list: OrderedSet[IRInstruction] | ||
|
|
||
| invalidate_alias: set[address_space.AddrSpace] | ||
|
|
||
| def run_pass(self): | ||
| self.dfg = self.analyses_cache.request_analysis(DFGAnalysis) | ||
| self.invalidate_alias = set() | ||
|
|
||
| work_list = OrderedSet() | ||
| self.work_list = work_list | ||
|
|
@@ -45,14 +52,16 @@ def run_pass(self): | |
| # invalidations below only cascade to them when the parent is | ||
| # actually cached, but the alias analyses can also be requested | ||
| # (and cached) on their own | ||
| self.analyses_cache.invalidate_analysis(MemoryAliasAnalysis) | ||
| self.analyses_cache.invalidate_analysis(StorageAliasAnalysis) | ||
| self.analyses_cache.invalidate_analysis(TransientAliasAnalysis) | ||
| self.analyses_cache.invalidate_analysis(LoadAnalysis) | ||
| self.analyses_cache.invalidate_analysis(MemSSA) | ||
| self.analyses_cache.invalidate_analysis(StorageSSA) | ||
| self.analyses_cache.invalidate_analysis(TransientSSA) | ||
| self.analyses_cache.invalidate_analysis(LivenessAnalysis) | ||
| for space in self.invalidate_alias: | ||
| alias_analysis = mem_alias_type_factory(space) | ||
| self.analyses_cache.invalidate_analysis(alias_analysis) | ||
|
Comment on lines
+62
to
+64
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When this pass removes only pure dead instructions, such as an unused Useful? React with 👍 / 👎. |
||
|
|
||
| def _process_instruction(self, inst) -> bool: | ||
| outputs = inst.get_outputs() | ||
|
|
@@ -72,5 +81,22 @@ def _process_instruction(self, inst) -> bool: | |
| new_uses = self.dfg.get_uses(operand) | ||
| self.work_list.addmany(new_uses) | ||
|
|
||
| # instructions that handle FMP can be removed if there is no use for the | ||
| # since they either bump or set only at the end of the function so the | ||
| # removal of the instruction will not effect other instructions. | ||
| # Other write effect should not be removed by this analysis | ||
| assert inst.get_write_effects() == EMPTY or inst.get_write_effects() == FMP | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
When Useful? React with 👍 / 👎. |
||
| effs = inst.get_read_effects() | ||
| if effs != EMPTY: | ||
| for eff in effs: | ||
| space = effects.to_addr_space(eff) | ||
| if space is None: | ||
| # sanity check | ||
| continue | ||
|
|
||
| # Mem alias does not use all address spaces | ||
| if can_create_mem_alias(space): | ||
| self.invalidate_alias.add(space) | ||
|
|
||
| inst.make_nop() | ||
| return True | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When valid raw Venom invokes a non-returning callee such as a parameterless function ending in
stoporrevert, itsFunctionCallLayoutlegitimately has no return-PC parameter, yet a single call site selects it for inlining and this assertion aborts compilation. The calling-convention validator explicitly permits callees with no return instructions and expects zero invoke outputs, and the previous inliner could inline this shape because it never required a return-PC binding; only require/remove the parameter when one exists.Useful? React with 👍 / 👎.