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

feat[venom]: make cfg scheduler "stack aware" #4356

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 3 additions & 3 deletions tests/unit/compiler/venom/test_branch_optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,9 +22,9 @@ def test_simple_jump_case():
jnz_input = bb.append_instruction("iszero", op3)
bb.append_instruction("jnz", jnz_input, br1.label, br2.label)

br1.append_instruction("add", op3, 10)
br1.append_instruction("add", op3, p1)
br1.append_instruction("stop")
br2.append_instruction("add", op3, p1)
br2.append_instruction("add", op3, 10)
br2.append_instruction("stop")

term_inst = bb.instructions[-1]
Expand All @@ -47,6 +47,6 @@ def test_simple_jump_case():

# Test that the dfg is updated correctly
dfg = ac.request_analysis(DFGAnalysis)
assert dfg is old_dfg, "DFG should not be invalidated by BranchOptimizationPass"
assert dfg is not old_dfg, "DFG should be invalidated by BranchOptimizationPass"
assert term_inst in dfg.get_uses(op3), "jnz not using the new condition"
assert term_inst not in dfg.get_uses(jnz_input), "jnz still using the old condition"
30 changes: 22 additions & 8 deletions vyper/venom/passes/branch_optimization.py
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
from vyper.venom.analysis import DFGAnalysis
from vyper.venom.analysis import CFGAnalysis, DFGAnalysis, LivenessAnalysis
from vyper.venom.basicblock import IRInstruction
from vyper.venom.passes.base_pass import IRPass


Expand All @@ -14,17 +15,30 @@ def _optimize_branches(self) -> None:
if term_inst.opcode != "jnz":
continue

prev_inst = self.dfg.get_producing_instruction(term_inst.operands[0])
if prev_inst.opcode == "iszero":
fst, snd = bb.cfg_out

fst_liveness = fst.instructions[0].liveness
snd_liveness = snd.instructions[0].liveness

cost_a, cost_b = len(fst_liveness), len(snd_liveness)

cond = term_inst.operands[0]
prev_inst = self.dfg.get_producing_instruction(cond)
if cost_a >= cost_b and prev_inst.opcode == "iszero":
new_cond = prev_inst.operands[0]
term_inst.operands = [new_cond, term_inst.operands[2], term_inst.operands[1]]

# Since the DFG update is simple we do in place to avoid invalidating the DFG
# and having to recompute it (which is expensive(er))
self.dfg.remove_use(prev_inst.output, term_inst)
self.dfg.add_use(new_cond, term_inst)
elif cost_a > cost_b:
new_cond = fn.get_next_variable()
inst = IRInstruction("iszero", [term_inst.operands[0]], output=new_cond)
bb.insert_instruction(inst, index=-1)
term_inst.operands = [new_cond, term_inst.operands[2], term_inst.operands[1]]

def run_pass(self):
self.liveness = self.analyses_cache.request_analysis(LivenessAnalysis)
self.cfg = self.analyses_cache.request_analysis(CFGAnalysis)
self.dfg = self.analyses_cache.request_analysis(DFGAnalysis)

self._optimize_branches()

self.analyses_cache.invalidate_analysis(LivenessAnalysis)
self.analyses_cache.invalidate_analysis(CFGAnalysis)
Loading