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

perf: lazy eval of f-strings in IRnode ctor #3602

Merged
merged 3 commits into from
Nov 21, 2023
Merged
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
95 changes: 42 additions & 53 deletions vyper/codegen/ir_node.py
Original file line number Diff line number Diff line change
Expand Up @@ -202,27 +202,23 @@ def __init__(
self.encoding = encoding
self.as_hex = AS_HEX_DEFAULT

def _check(condition, err):
if not condition:
raise CompilerPanic(str(err))

_check(self.value is not None, "None is not allowed as IRnode value")
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,
# 0 otherwise) and checks to make sure the number and valencies of
# children are correct. Also, find an upper bound on gas consumption
# Numbers
if isinstance(self.value, int):
_check(len(self.args) == 0, "int can't have arguments")
assert len(self.args) == 0, "int can't have arguments"

# integers must be in the range (MIN_INT256, MAX_UINT256)
_check(-(2**255) <= self.value < 2**256, "out of range")
assert -(2**255) <= self.value < 2**256, "out of range"

self.valency = 1
self._gas = 5
elif isinstance(self.value, bytes):
# a literal bytes value, probably inside a "data" node.
_check(len(self.args) == 0, "bytes can't have arguments")
assert len(self.args) == 0, "bytes can't have arguments"

self.valency = 0
self._gas = 0
Expand All @@ -232,10 +228,9 @@ def _check(condition, err):
if self.value.upper() in get_ir_opcodes():
_, ins, outs, gas = get_ir_opcodes()[self.value.upper()]
self.valency = outs
_check(
len(self.args) == ins,
f"Number of arguments mismatched: {self.value} {self.args}",
)
assert (
len(self.args) == ins
), f"Number of arguments mismatched: {self.value} {self.args}"
# We add 2 per stack height at push time and take it back
# at pop time; this makes `break` easier to handle
self._gas = gas + 2 * (outs - ins)
Expand All @@ -244,10 +239,10 @@ def _check(condition, err):
# consumed for internal functions, therefore we whitelist this as a zero valency
# allowed argument.
zero_valency_whitelist = {"pass", "pop"}
_check(
arg.valency == 1 or arg.value in zero_valency_whitelist,
f"invalid argument to `{self.value}`: {arg}",
)
assert (
arg.valency == 1 or arg.value in zero_valency_whitelist
), f"invalid argument to `{self.value}`: {arg}"

self._gas += arg.gas
# Dynamic gas cost: 8 gas for each byte of logging data
if self.value.upper()[0:3] == "LOG" and isinstance(self.args[1].value, int):
Expand Down Expand Up @@ -275,44 +270,40 @@ def _check(condition, err):
self._gas = self.args[0].gas + max(self.args[1].gas, self.args[2].gas) + 3
if len(self.args) == 2:
self._gas = self.args[0].gas + self.args[1].gas + 17
_check(
self.args[0].valency > 0,
f"zerovalent argument as a test to an if statement: {self.args[0]}",
)
_check(len(self.args) in (2, 3), "if statement can only have 2 or 3 arguments")
assert (
self.args[0].valency > 0
), f"zerovalent argument as a test to an if statement: {self.args[0]}"
assert len(self.args) in (2, 3), "if statement can only have 2 or 3 arguments"
self.valency = self.args[1].valency
# With statements: with <var> <initial> <statement>
elif self.value == "with":
_check(len(self.args) == 3, self)
_check(
len(self.args[0].args) == 0 and isinstance(self.args[0].value, str),
f"first argument to with statement must be a variable name: {self.args[0]}",
)
_check(
self.args[1].valency == 1 or self.args[1].value == "pass",
f"zerovalent argument to with statement: {self.args[1]}",
)
assert len(self.args) == 3, self
assert len(self.args[0].args) == 0 and isinstance(
self.args[0].value, str
), f"first argument to with statement must be a variable name: {self.args[0]}"
assert (
self.args[1].valency == 1 or self.args[1].value == "pass"
), f"zerovalent argument to with statement: {self.args[1]}"
self.valency = self.args[2].valency
self._gas = sum([arg.gas for arg in self.args]) + 5
# Repeat statements: repeat <index_name> <startval> <rounds> <rounds_bound> <body>
elif self.value == "repeat":
_check(
len(self.args) == 5, "repeat(index_name, startval, rounds, rounds_bound, body)"
)
assert (
len(self.args) == 5
), "repeat(index_name, startval, rounds, rounds_bound, body)"

counter_ptr = self.args[0]
start = self.args[1]
repeat_count = self.args[2]
repeat_bound = self.args[3]
body = self.args[4]

_check(
isinstance(repeat_bound.value, int) and repeat_bound.value > 0,
f"repeat bound must be a compile-time positive integer: {self.args[2]}",
)
_check(repeat_count.valency == 1, repeat_count)
_check(counter_ptr.valency == 1, counter_ptr)
_check(start.valency == 1, start)
assert (
isinstance(repeat_bound.value, int) and repeat_bound.value > 0
), f"repeat bound must be a compile-time positive integer: {self.args[2]}"
assert repeat_count.valency == 1, repeat_count
assert counter_ptr.valency == 1, counter_ptr
assert start.valency == 1, start

self.valency = 0

Expand All @@ -335,19 +326,17 @@ def _check(condition, err):
# then JUMP to my_label.
elif self.value in ("goto", "exit_to"):
for arg in self.args:
_check(
arg.valency == 1 or arg.value == "pass",
f"zerovalent argument to goto {arg}",
)
assert (
arg.valency == 1 or arg.value == "pass"
), f"zerovalent argument to goto {arg}"

self.valency = 0
self._gas = sum([arg.gas for arg in self.args])
elif self.value == "label":
_check(
self.args[1].value == "var_list",
f"2nd argument to label must be var_list, {self}",
)
_check(len(args) == 3, f"label should have 3 args but has {len(args)}, {self}")
assert (
self.args[1].value == "var_list"
), f"2nd argument to label must be var_list, {self}"
assert len(args) == 3, f"label should have 3 args but has {len(args)}, {self}"
self.valency = 0
self._gas = 1 + sum(t.gas for t in self.args)
elif self.value == "unique_symbol":
Expand All @@ -371,14 +360,14 @@ def _check(condition, err):
# Multi statements: multi <expr> <expr> ...
elif self.value == "multi":
for arg in self.args:
_check(
arg.valency > 0, f"Multi expects all children to not be zerovalent: {arg}"
)
assert (
arg.valency > 0
), f"Multi expects all children to not be zerovalent: {arg}"
self.valency = sum([arg.valency for arg in self.args])
self._gas = sum([arg.gas for arg in self.args])
elif self.value == "deploy":
self.valency = 0
_check(len(self.args) == 3, f"`deploy` should have three args {self}")
assert len(self.args) == 3, f"`deploy` should have three args {self}"
self._gas = NullAttractor() # unknown
# Stack variables
else:
Expand Down
Loading