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: optimize literal bytestrings #3501

Open
wants to merge 5 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
41 changes: 27 additions & 14 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@
from vyper import ast as vy_ast
from vyper.codegen import external_call, self_call
from vyper.codegen.core import (
_freshname,
add_ofst,
append_dyn_array,
check_assign,
clamp,
Expand Down Expand Up @@ -154,21 +156,32 @@ def _parse_bytes(self):

def _make_bytelike(self, btype, bytez, bytez_length):
placeholder = self.context.new_internal_variable(btype)
seq = []
seq.append(["mstore", placeholder, bytez_length])
for i in range(0, len(bytez), 32):
seq.append(
[
"mstore",
["add", placeholder, i + 32],
bytes_to_int((bytez + b"\x00" * 31)[i : i + 32]),
]
)
ret = ["seq"]
assert isinstance(bytez, bytes)
# NOTE: addl opportunities for optimization:
# - intern repeated bytestrings
# - instantiate into memory lazily, pass around bytestring
# literals in IR
# -
length = len(bytez)
if length <= 32:
# in this case, a single mstore is cheaper than
# codecopy.
bytes_as_int = bytes_to_int(bytez) # PUSH data
# bytes are left justified. "Hello" gets written to the
# first 6 bytes of the data buffer of the bytestring
dst = add_ofst(placeholder, length)
ret.append(["mstore", dst, bytes_as_int])
else:
# codecopy
label = _freshname("bytesdata")
ret.append(["data", label, bytez])
ret.append(["codecopy", add_ofst(placeholder, 32), ["symbol", label], length])
# write out the length
ret.append(["mstore", placeholder, length])
ret.append(placeholder)
return IRnode.from_list(
["seq"] + seq + [placeholder],
typ=btype,
location=MEMORY,
annotation=f"Create {btype}: {bytez}",
ret, typ=btype, location=MEMORY, annotation=f"Create {btype}: {repr(bytez)}"
)

# True, False, None constants
Expand Down
5 changes: 1 addition & 4 deletions vyper/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -330,10 +330,7 @@ def hex_to_int(inp):

# Converts bytes to an integer
def bytes_to_int(bytez):
o = 0
for b in bytez:
o = o * 256 + b
return o
return int.from_bytes(bytez, "big")


def is_checksum_encoded(addr):
Expand Down
Loading