Skip to content

Commit

Permalink
feat[venom]: add effects to instructions (#4264)
Browse files Browse the repository at this point in the history
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 <harkal@nlogn.eu>
Co-authored-by: HodanPlodky <36966616+HodanPlodky@users.noreply.github.com>
  • Loading branch information
3 people authored Oct 5, 2024
1 parent ebe3c0c commit 02f8654
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 0 deletions.
7 changes: 7 additions & 0 deletions vyper/venom/basicblock.py
Original file line number Diff line number Diff line change
@@ -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

Expand Down Expand Up @@ -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.
Expand Down
85 changes: 85 additions & 0 deletions vyper/venom/effects.py
Original file line number Diff line number Diff line change
@@ -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

0 comments on commit 02f8654

Please sign in to comment.