From 02f8654c5471334e7ee6f3008353dee1a88860a6 Mon Sep 17 00:00:00 2001 From: Charles Cooper Date: Fri, 4 Oct 2024 20:44:25 -0400 Subject: [PATCH] feat[venom]: add effects to instructions (#4264) this commit adds an `effects.py` file to venom, which describes the effects of opcodes. this is useful for several ongoing efforts, including CSE elimination and DFT pass improvements. --------- Co-authored-by: Harry Kalogirou Co-authored-by: HodanPlodky <36966616+HodanPlodky@users.noreply.github.com> --- vyper/venom/basicblock.py | 7 ++++ vyper/venom/effects.py | 85 +++++++++++++++++++++++++++++++++++++++ 2 files changed, 92 insertions(+) create mode 100644 vyper/venom/effects.py diff --git a/vyper/venom/basicblock.py b/vyper/venom/basicblock.py index 45db8b232f..799dcfb33b 100644 --- a/vyper/venom/basicblock.py +++ b/vyper/venom/basicblock.py @@ -1,5 +1,6 @@ from typing import TYPE_CHECKING, Any, Iterator, Optional, Union +import vyper.venom.effects as effects from vyper.codegen.ir_node import IRnode from vyper.utils import OrderedSet @@ -238,6 +239,12 @@ def is_volatile(self) -> bool: def is_bb_terminator(self) -> bool: return self.opcode in BB_TERMINATORS + def get_read_effects(self): + return effects.reads.get(self.opcode, effects.EMPTY) + + def get_write_effects(self): + return effects.writes.get(self.opcode, effects.EMPTY) + def get_label_operands(self) -> Iterator[IRLabel]: """ Get all labels in instruction. diff --git a/vyper/venom/effects.py b/vyper/venom/effects.py new file mode 100644 index 0000000000..20cc0e4b02 --- /dev/null +++ b/vyper/venom/effects.py @@ -0,0 +1,85 @@ +from enum import Flag, auto + + +class Effects(Flag): + STORAGE = auto() + TRANSIENT = auto() + MEMORY = auto() + MSIZE = auto() + IMMUTABLES = auto() + RETURNDATA = auto() + LOG = auto() + BALANCE = auto() + EXTCODE = auto() + + +EMPTY = Effects(0) +ALL = ~EMPTY +STORAGE = Effects.STORAGE +TRANSIENT = Effects.TRANSIENT +MEMORY = Effects.MEMORY +MSIZE = Effects.MSIZE +IMMUTABLES = Effects.IMMUTABLES +RETURNDATA = Effects.RETURNDATA +LOG = Effects.LOG +BALANCE = Effects.BALANCE +EXTCODE = Effects.EXTCODE + + +_writes = { + "sstore": STORAGE, + "tstore": TRANSIENT, + "mstore": MEMORY, + "istore": IMMUTABLES, + "call": ALL ^ IMMUTABLES, + "delegatecall": ALL ^ IMMUTABLES, + "staticcall": MEMORY | RETURNDATA, + "create": ALL ^ (MEMORY | IMMUTABLES), + "create2": ALL ^ (MEMORY | IMMUTABLES), + "invoke": ALL, # could be smarter, look up the effects of the invoked function + "log": LOG, + "dloadbytes": MEMORY, + "returndatacopy": MEMORY, + "calldatacopy": MEMORY, + "codecopy": MEMORY, + "extcodecopy": MEMORY, + "mcopy": MEMORY, +} + +_reads = { + "sload": STORAGE, + "tload": TRANSIENT, + "iload": IMMUTABLES, + "mload": MEMORY, + "mcopy": MEMORY, + "call": ALL, + "delegatecall": ALL, + "staticcall": ALL, + "create": ALL, + "create2": ALL, + "invoke": ALL, + "returndatasize": RETURNDATA, + "returndatacopy": RETURNDATA, + "balance": BALANCE, + "selfbalance": BALANCE, + "extcodecopy": EXTCODE, + "selfdestruct": BALANCE, # may modify code, but after the transaction + "log": MEMORY, + "revert": MEMORY, + "return": MEMORY, + "sha3": MEMORY, + "msize": MSIZE, +} + +reads = _reads.copy() +writes = _writes.copy() + +for k, v in reads.items(): + if MEMORY in v: + if k not in writes: + writes[k] = EMPTY + writes[k] |= MSIZE + +for k, v in writes.items(): + if MEMORY in v: + writes[k] |= MSIZE