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

feat[ir]: add sanity check #3862

Open
wants to merge 9 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all 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
25 changes: 25 additions & 0 deletions vyper/codegen/ir_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -139,6 +139,9 @@ class IRnode:
func_ir: Any
common_ir: Any

_id: int
_next_id: int = -1

def __init__(
self,
value: Union[str, int],
Expand All @@ -153,6 +156,7 @@ def __init__(
encoding: Encoding = Encoding.VYPER,
is_self_call: bool = False,
passthrough_metadata: dict[str, Any] = None,
_id: int = None,
):
if args is None:
args = []
Expand All @@ -175,6 +179,12 @@ def __init__(
self.func_ir = None
self.common_ir = None

self._id = _id # type: ignore[assignment]
self.ensure_id()

# helpful for debugging:
# self._origin = traceback.extract_stack()

assert self.value is not None, "None is not allowed as IRnode value"

# Determine this node's valency (1 if it pushes a value on the stack,
Expand Down Expand Up @@ -358,6 +368,15 @@ def __deepcopy__(self, memo):
ret.args = [copy.deepcopy(arg) for arg in ret.args]
return ret

@classmethod
def generate_id(cls):
cls._next_id += 1
return cls._next_id

def ensure_id(self):
if self._id is None:
self._id = self.generate_id()

# TODO would be nice to rename to `gas_estimate` or `gas_bound`
@property
def gas(self):
Expand Down Expand Up @@ -489,6 +508,8 @@ def repr_value(self):
return hex(self.value)
if not isinstance(self.value, str):
return str(self.value)
# useful for debugging
# return f"{self._id}:{self.value}"
return self.value

@staticmethod
Expand Down Expand Up @@ -559,11 +580,13 @@ def from_list(
is_self_call: bool = False,
passthrough_metadata: dict[str, Any] = None,
encoding: Encoding = Encoding.VYPER,
_id=None,
) -> "IRnode":
if isinstance(typ, str): # pragma: nocover
raise CompilerPanic(f"Expected type, not string: {typ}")

if isinstance(obj, IRnode):
assert _id is None
# note: this modify-and-returnclause is a little weird since
# the input gets modified. CC 20191121.
if typ is not None:
Expand Down Expand Up @@ -592,6 +615,7 @@ def from_list(
error_msg=error_msg,
is_self_call=is_self_call,
passthrough_metadata=passthrough_metadata,
_id=_id,
)
else:
return cls(
Expand All @@ -607,4 +631,5 @@ def from_list(
error_msg=error_msg,
is_self_call=is_self_call,
passthrough_metadata=passthrough_metadata,
_id=_id,
)
13 changes: 13 additions & 0 deletions vyper/ir/compile_ir.py
Original file line number Diff line number Diff line change
Expand Up @@ -211,11 +211,24 @@
return apply_line_no_wrapper


def check_duplicated_nodes(ir_node, seen=None):
seen = seen or set()

if ir_node.is_complex_ir and ir_node._id in seen:
raise CompilerPanic(f"bad code {ir_node}", ir_node.ast_source)

Check warning on line 218 in vyper/ir/compile_ir.py

View check run for this annotation

Codecov / codecov/patch

vyper/ir/compile_ir.py#L218

Added line #L218 was not covered by tests
seen.add(ir_node._id)

for arg in ir_node.args:
check_duplicated_nodes(arg, seen)


@apply_line_numbers
def compile_to_assembly(code, optimize=OptimizationLevel.GAS):
global _revert_label
_revert_label = mksymbol("revert")

check_duplicated_nodes(code)

# don't overwrite ir since the original might need to be output, e.g. `-f ir,asm`
code = copy.deepcopy(code)
_rewrite_return_sequences(code)
Expand Down
2 changes: 2 additions & 0 deletions vyper/ir/optimizer.py
Original file line number Diff line number Diff line change
Expand Up @@ -442,6 +442,7 @@ def _optimize(node: IRnode, parent: Optional[IRnode]) -> Tuple[bool, IRnode]:
add_gas_estimate = node.add_gas_estimate
is_self_call = node.is_self_call
passthrough_metadata = node.passthrough_metadata
_id = node._id

changed = False

Expand All @@ -466,6 +467,7 @@ def finalize(val, args):
add_gas_estimate=add_gas_estimate,
is_self_call=is_self_call,
passthrough_metadata=passthrough_metadata,
_id=_id,
)

if should_check_symbols:
Expand Down
Loading