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

fix[venom]: fix invalid phis after SCCP #4181

Merged
Merged
Show file tree
Hide file tree
Changes from 4 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
2 changes: 2 additions & 0 deletions vyper/venom/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@
from vyper.venom.passes.sccp import SCCP
from vyper.venom.passes.simplify_cfg import SimplifyCFGPass
from vyper.venom.passes.store_elimination import StoreElimination
from vyper.venom.passes.remove_invalid_phi_nodes import RemoveInvalidPhiPass
from vyper.venom.venom_to_assembly import VenomCompiler

DEFAULT_OPT_LEVEL = OptimizationLevel.default()
Expand Down Expand Up @@ -50,6 +51,7 @@ def _run_passes(fn: IRFunction, optimize: OptimizationLevel) -> None:
Mem2Var(ac, fn).run_pass()
MakeSSA(ac, fn).run_pass()
SCCP(ac, fn).run_pass()
RemoveInvalidPhiPass(ac, fn).run_pass()
StoreElimination(ac, fn).run_pass()
SimplifyCFGPass(ac, fn).run_pass()
AlgebraicOptimizationPass(ac, fn).run_pass()
Expand Down
36 changes: 36 additions & 0 deletions vyper/venom/passes/remove_invalid_phi_nodes.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
from vyper.venom.basicblock import IRBasicBlock, IRLabel, IRInstruction, IRVariable
Fixed Show fixed Hide fixed
from vyper.venom.passes.base_pass import IRPass
from vyper.venom.analysis.dfg import DFGAnalysis
from vyper.venom.analysis.cfg import CFGAnalysis

class RemoveInvalidPhiPass(IRPass):
dfg : DFGAnalysis

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

for bb in self.function.get_basic_blocks():
for inst in bb.instructions.copy():
if inst.opcode == "phi":
self._handle_phi(inst)

def _handle_phi(self, phi_inst : IRInstruction) -> bool:
if len(phi_inst.parent.cfg_in) != 1:
return False

src_bb : IRBasicBlock = phi_inst.parent.cfg_in.first()
assert isinstance(src_bb, IRBasicBlock)

from_src_bb = filter(lambda x : x[0] == src_bb.label, phi_inst.phi_operands)
operands = list(map(lambda x : x[1], from_src_bb))

assert len(operands) == 1
assert isinstance(operands[0], IRVariable)
phi_inst.output.value = operands[0]
phi_inst.parent.remove_instruction(phi_inst)

return True



25 changes: 11 additions & 14 deletions vyper/venom/passes/simplify_cfg.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,21 @@ class SimplifyCFGPass(IRPass):
def _merge_blocks(self, a: IRBasicBlock, b: IRBasicBlock):
a.instructions.pop()
for inst in b.instructions:
assert inst.opcode != "phi", "Not implemented yet"
if inst.opcode == "phi":
a.instructions.insert(0, inst)
else:
inst.parent = a
a.instructions.append(inst)
assert inst.opcode != "phi", f"Instruction should never be phi {inst}"
inst.parent = a
a.instructions.append(inst)

# Update CFG
a.cfg_out = b.cfg_out
if len(b.cfg_out) > 0:
next_bb = b.cfg_out.first()
next_bb.remove_cfg_in(b)
next_bb.add_cfg_in(a)

for inst in next_bb.instructions:
if inst.opcode != "phi":
break
inst.operands[inst.operands.index(b.label)] = a.label
for next_bb in b.cfg_out:
next_bb.remove_cfg_in(b)
next_bb.add_cfg_in(a)

for inst in next_bb.instructions:
if inst.opcode != "phi":
break
inst.operands[inst.operands.index(b.label)] = a.label

self.function.remove_basic_block(b)

Expand Down
Loading