Skip to content
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

venom produces unneeded stack traffic #3950

Closed
charles-cooper opened this issue Apr 14, 2024 · 1 comment
Closed

venom produces unneeded stack traffic #3950

charles-cooper opened this issue Apr 14, 2024 · 1 comment
Assignees

Comments

@charles-cooper
Copy link
Member

Version Information

  • vyper Version (output of vyper --version): 074073f

What's your issue about?

sometimes, venom produces some unneeded stack traffic. this can't be fixed by improved dataflow analysis, because it is an issue in the stack scheduler rather than instruction reordering. what happens is a stack item is produced, but it has a longer lifespan than other things on the stack. i think a lot of it can be solved with a simple heuristic: at the time of stack item production, check the live list for something with "shorter" liveness we can swap it with.

How can it be fixed?

i think something like this does what we want (but in its current form it is borked, it causes some larger contracts to puke):

diff --git a/vyper/venom/venom_to_assembly.py b/vyper/venom/venom_to_assembly.py
index dd4901aaa..8104c205e 100644
--- a/vyper/venom/venom_to_assembly.py
+++ b/vyper/venom/venom_to_assembly.py
@@ -16,6 +16,7 @@ from vyper.venom.analysis import (
     calculate_dup_requirements,
     calculate_liveness,
     input_vars_from,
+    DFG,
 )
 from vyper.venom.basicblock import (
     IRBasicBlock,
@@ -156,6 +157,7 @@ class VenomCompiler:
             calculate_cfg(ctx)
             calculate_liveness(ctx)
             calculate_dup_requirements(ctx)
+            self._dfg = DFG.build_dfg(ctx)
 
             assert ctx.normalized, "Non-normalized CFG!"
 
@@ -532,8 +534,16 @@ class VenomCompiler:
 
         # Step 6: Emit instructions output operands (if any)
         if inst.output is not None:
-            if "call" in inst.opcode and inst.output not in next_liveness:
+            if inst.output not in next_liveness:
                 self.pop(assembly, stack)
+            else:
+                # peek at next_liveness to find the next scheduled item,
+                # and optimistically swap with it
+                bb = inst.parent
+                for s in reversed(list(next_liveness)):
+                    if all(t.parent == bb for t in self._dfg.get_uses(s)):
+                        self.swap_op(assembly, stack, s)
+                        break
 
         return apply_line_numbers(inst, assembly)
@charles-cooper
Copy link
Member Author

completed in #3951

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants