diff --git a/vyper/venom/__init__.py b/vyper/venom/__init__.py index bc66906ae9..71b0074c11 100644 --- a/vyper/venom/__init__.py +++ b/vyper/venom/__init__.py @@ -44,11 +44,12 @@ def _run_passes(fn: IRFunction, optimize: OptimizationLevel) -> None: ac = IRAnalysesCache(fn) SimplifyCFGPass(ac, fn).run_pass() - Mem2Var(ac, fn).run_pass() MakeSSA(ac, fn).run_pass() StoreElimination(ac, fn).run_pass() + Mem2Var(ac, fn).run_pass() MakeSSA(ac, fn).run_pass() SCCP(ac, fn).run_pass() + StoreElimination(ac, fn).run_pass() SimplifyCFGPass(ac, fn).run_pass() RemoveUnusedVariablesPass(ac, fn).run_pass() DFTPass(ac, fn).run_pass() diff --git a/vyper/venom/passes/remove_unused_variables.py b/vyper/venom/passes/remove_unused_variables.py index a4cd737e98..8307bdae40 100644 --- a/vyper/venom/passes/remove_unused_variables.py +++ b/vyper/venom/passes/remove_unused_variables.py @@ -1,22 +1,47 @@ from vyper.venom.analysis.dfg import DFGAnalysis from vyper.venom.analysis.liveness import LivenessAnalysis +from vyper.venom.basicblock import IRBasicBlock from vyper.venom.passes.base_pass import IRPass class RemoveUnusedVariablesPass(IRPass): def run_pass(self): - removeList = set() - self.analyses_cache.request_analysis(LivenessAnalysis) for bb in self.function.get_basic_blocks(): - for i, inst in enumerate(bb.instructions[:-1]): - if inst.volatile: - continue - next_liveness = bb.instructions[i + 1].liveness - if (inst.output and inst.output not in next_liveness) or inst.opcode == "nop": - removeList.add(inst) - - bb.instructions = [inst for inst in bb.instructions if inst not in removeList] + self._remove_unused_variables(bb) self.analyses_cache.invalidate_analysis(DFGAnalysis) + + def _remove_unused_variables(self, bb: IRBasicBlock): + """ + Remove the instructions of a basicblock that produce output that is never used. + """ + i = 0 + while i < len(bb.instructions) - 1: + inst = bb.instructions[i] + i += 1 + + # Skip volatile instructions + if inst.volatile: + continue + + # Skip instructions without output + if inst.output is None: + continue + + # Skip instructions that produce output that is used + next_liveness = bb.instructions[i].liveness + if inst.output in next_liveness: + continue + + # Remove the rest + del bb.instructions[i - 1] + + # backtrack to the *previous* instruction, in case we removed + # an instruction which had prevented the previous instruction + # from being removed + i -= 2 + + # don't go beyond 0 though + i = max(0, i)