diff --git a/vyper/venom/analysis/dfg.py b/vyper/venom/analysis/dfg.py index 328ed47c72..f49b2ac6ac 100644 --- a/vyper/venom/analysis/dfg.py +++ b/vyper/venom/analysis/dfg.py @@ -1,5 +1,6 @@ from typing import Optional +from vyper.utils import OrderedSet from vyper.venom.analysis.analysis import IRAnalysesCache, IRAnalysis from vyper.venom.analysis.liveness import LivenessAnalysis from vyper.venom.basicblock import IRInstruction, IRVariable @@ -7,7 +8,7 @@ class DFGAnalysis(IRAnalysis): - _dfg_inputs: dict[IRVariable, list[IRInstruction]] + _dfg_inputs: dict[IRVariable, OrderedSet[IRInstruction]] _dfg_outputs: dict[IRVariable, IRInstruction] def __init__(self, analyses_cache: IRAnalysesCache, function: IRFunction): @@ -16,19 +17,19 @@ def __init__(self, analyses_cache: IRAnalysesCache, function: IRFunction): self._dfg_outputs = dict() # return uses of a given variable - def get_uses(self, op: IRVariable) -> list[IRInstruction]: - return self._dfg_inputs.get(op, []) + def get_uses(self, op: IRVariable) -> OrderedSet[IRInstruction]: + return self._dfg_inputs.get(op, OrderedSet()) # the instruction which produces this variable. def get_producing_instruction(self, op: IRVariable) -> Optional[IRInstruction]: return self._dfg_outputs.get(op) def add_use(self, op: IRVariable, inst: IRInstruction): - uses = self._dfg_inputs.setdefault(op, []) - uses.append(inst) + uses = self._dfg_inputs.setdefault(op, OrderedSet()) + uses.add(inst) def remove_use(self, op: IRVariable, inst: IRInstruction): - uses = self._dfg_inputs.get(op, []) + uses: OrderedSet = self._dfg_inputs.get(op, OrderedSet()) uses.remove(inst) @property @@ -48,10 +49,11 @@ def analyze(self): res = inst.get_outputs() for op in operands: - inputs = self._dfg_inputs.setdefault(op, []) - inputs.append(inst) + inputs = self._dfg_inputs.setdefault(op, OrderedSet()) + inputs.add(inst) for op in res: # type: ignore + assert isinstance(op, IRVariable) self._dfg_outputs[op] = inst def as_graph(self) -> str: diff --git a/vyper/venom/passes/sccp/sccp.py b/vyper/venom/passes/sccp/sccp.py index 19d373f81a..d85e09c9b4 100644 --- a/vyper/venom/passes/sccp/sccp.py +++ b/vyper/venom/passes/sccp/sccp.py @@ -5,7 +5,7 @@ from vyper.exceptions import CompilerPanic, StaticAssertionException from vyper.utils import OrderedSet -from vyper.venom.analysis import CFGAnalysis, DominatorTreeAnalysis, IRAnalysesCache +from vyper.venom.analysis import CFGAnalysis, DFGAnalysis, DominatorTreeAnalysis, IRAnalysesCache from vyper.venom.basicblock import ( IRBasicBlock, IRInstruction, @@ -51,7 +51,7 @@ class SCCP(IRPass): fn: IRFunction dom: DominatorTreeAnalysis - uses: dict[IRVariable, OrderedSet[IRInstruction]] + dfg: DFGAnalysis lattice: Lattice work_list: list[WorkListItem] cfg_in_exec: dict[IRBasicBlock, OrderedSet[IRBasicBlock]] @@ -67,7 +67,7 @@ def __init__(self, analyses_cache: IRAnalysesCache, function: IRFunction): def run_pass(self): self.fn = self.function self.dom = self.analyses_cache.request_analysis(DominatorTreeAnalysis) - self._compute_uses() + self.dfg = self.analyses_cache.request_analysis(DFGAnalysis) self._calculate_sccp(self.fn.entry) self._propagate_constants() @@ -75,6 +75,8 @@ def run_pass(self): self.analyses_cache.force_analysis(CFGAnalysis) self._fix_phi_nodes() + self.analyses_cache.invalidate_analysis(DFGAnalysis) + def _calculate_sccp(self, entry: IRBasicBlock): """ This method is the main entry point for the SCCP algorithm. It @@ -92,7 +94,7 @@ def _calculate_sccp(self, entry: IRBasicBlock): self.work_list.append(FlowWorkItem(dummy, entry)) # Initialize the lattice with TOP values for all variables - for v in self.uses.keys(): + for v in self.dfg._dfg_outputs: self.lattice[v] = LatticeEnum.TOP # Iterate over the work list until it is empty @@ -258,25 +260,9 @@ def _eval(self, inst) -> LatticeItem: return ret # type: ignore def _add_ssa_work_items(self, inst: IRInstruction): - for target_inst in self._get_uses(inst.output): # type: ignore + for target_inst in self.dfg.get_uses(inst.output): # type: ignore self.work_list.append(SSAWorkListItem(target_inst)) - def _compute_uses(self): - """ - This method computes the uses for each variable in the IR. - It iterates over the dominator tree and collects all the - instructions that use each variable. - """ - self.uses = {} - for bb in self.dom.dfs_walk: - for var, insts in bb.get_uses().items(): - self._get_uses(var).update(insts) - - def _get_uses(self, var: IRVariable): - if var not in self.uses: - self.uses[var] = OrderedSet() - return self.uses[var] - def _propagate_constants(self): """ This method iterates over the IR and replaces constant values