diff --git a/tests/functional/codegen/features/iteration/test_for_in_list.py b/tests/functional/codegen/features/iteration/test_for_in_list.py index 036e7c0647..4b9eea3c27 100644 --- a/tests/functional/codegen/features/iteration/test_for_in_list.py +++ b/tests/functional/codegen/features/iteration/test_for_in_list.py @@ -214,6 +214,21 @@ def data() -> int128: assert c.data() == sum(xs) +def test_constant_list_iter(get_contract): + code = """ +MY_LIST: constant(uint24[4]) = [1, 2, 3, 4] + +@external +def foo() -> uint24: + x: uint24 = 0 + for s: uint24 in MY_LIST: + x += s + return x + """ + c = get_contract(code) + assert c.foo() == sum([1, 2, 3, 4]) + + def test_basic_for_list_storage_address(get_contract): code = """ addresses: address[3] diff --git a/tests/unit/compiler/venom/test_memmerging.py b/tests/unit/compiler/venom/test_memmerging.py index d309752621..3da09f76fb 100644 --- a/tests/unit/compiler/venom/test_memmerging.py +++ b/tests/unit/compiler/venom/test_memmerging.py @@ -3,7 +3,7 @@ from tests.venom_utils import assert_ctx_eq, parse_from_basic_block, parse_venom from vyper.evm.opcodes import version_check from vyper.venom.analysis import IRAnalysesCache -from vyper.venom.passes import SCCP, MemMergePass +from vyper.venom.passes import SCCP, MemMergePass, RemoveUnusedVariablesPass def _check_pre_post(pre, post): @@ -11,6 +11,7 @@ def _check_pre_post(pre, post): for fn in ctx.functions.values(): ac = IRAnalysesCache(fn) MemMergePass(ac, fn).run_pass() + RemoveUnusedVariablesPass(ac, fn).run_pass() assert_ctx_eq(ctx, parse_from_basic_block(post)) @@ -853,8 +854,6 @@ def test_memzeroing_2(): post = """ _global: - %1 = calldatasize - %2 = calldatasize %3 = calldatasize calldatacopy 64, %3, 256 stop @@ -881,8 +880,6 @@ def test_memzeroing_3(): post = """ _global: - %1 = calldatasize - %2 = calldatasize %3 = calldatasize calldatacopy 0, %3, 264 stop @@ -905,7 +902,6 @@ def test_memzeroing_small_calldatacopy(): post = """ _global: - %1 = calldatasize mstore 0, 0 stop """ @@ -935,13 +931,8 @@ def test_memzeroing_smaller_calldatacopy(): post = """ _global: - %1 = calldatasize - %2 = calldatasize %6 = calldatasize calldatacopy 0, %6, 24 - %3 = calldatasize - %4 = calldatasize - %5 = calldatasize mstore 100, 0 stop """ @@ -966,7 +957,6 @@ def test_memzeroing_overlap(): post = """ _global: - %1 = calldatasize %2 = calldatasize calldatacopy 100, %2, 64 stop diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py index 55d5443a8f..629ab684a8 100644 --- a/vyper/builtins/functions.py +++ b/vyper/builtins/functions.py @@ -2293,19 +2293,12 @@ def build_IR(self, expr, args, kwargs, context): else: method_id = method_id_int("log(string,bytes)") - schema = args_abi_t.selector_name().encode("utf-8") - if len(schema) > 32: - raise CompilerPanic(f"print signature too long: {schema}") + schema = args_abi_t.selector_name().encode("utf-8") schema_t = StringT(len(schema)) - schema_buf = context.new_internal_variable(schema_t) - ret = ["seq"] - ret.append(["mstore", schema_buf, len(schema)]) + schema_buf = Expr._make_bytelike(context, StringT, schema) - # TODO use Expr.make_bytelike, or better have a `bytestring` IRnode type - ret.append( - ["mstore", add_ofst(schema_buf, 32), bytes_to_int(schema.ljust(32, b"\x00"))] - ) + ret = ["seq"] payload_buflen = args_abi_t.size_bound() payload_t = BytesT(payload_buflen) diff --git a/vyper/codegen/core.py b/vyper/codegen/core.py index aaf6f35047..789cc77524 100644 --- a/vyper/codegen/core.py +++ b/vyper/codegen/core.py @@ -560,7 +560,7 @@ def _get_element_ptr_array(parent, key, array_bounds_check): return IRnode.from_list("~empty", subtype) if parent.value == "multi": - assert isinstance(key.value, int) + assert isinstance(key.value, int), key return parent.args[key.value] ix = unwrap_location(key) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index d3059e4245..a712a09f96 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -130,21 +130,22 @@ def parse_Hex(self): # String literals def parse_Str(self): bytez = self.expr.value.encode("utf-8") - return self._make_bytelike(StringT, bytez) + return self._make_bytelike(self.context, StringT, bytez) # Byte literals def parse_Bytes(self): - return self._make_bytelike(BytesT, self.expr.value) + return self._make_bytelike(self.context, BytesT, self.expr.value) def parse_HexBytes(self): # HexBytes already has value as bytes assert isinstance(self.expr.value, bytes) - return self._make_bytelike(BytesT, self.expr.value) + return self._make_bytelike(self.context, BytesT, self.expr.value) - def _make_bytelike(self, typeclass, bytez): + @classmethod + def _make_bytelike(cls, context, typeclass, bytez): bytez_length = len(bytez) btype = typeclass(bytez_length) - placeholder = self.context.new_internal_variable(btype) + placeholder = context.new_internal_variable(btype) seq = [] seq.append(["mstore", placeholder, bytez_length]) for i in range(0, len(bytez), 32): diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py index b1e26d7d5f..b306d83376 100644 --- a/vyper/codegen/stmt.py +++ b/vyper/codegen/stmt.py @@ -258,7 +258,7 @@ def _parse_For_list(self): ret = ["seq"] # list literal, force it to memory first - if isinstance(self.stmt.iter, vy_ast.List): + if iter_list.is_literal: tmp_list = self.context.new_internal_variable(iter_list.typ) ret.append(make_setter(tmp_list, iter_list)) iter_list = tmp_list diff --git a/vyper/venom/basicblock.py b/vyper/venom/basicblock.py index 0cdf849d51..015a065f50 100644 --- a/vyper/venom/basicblock.py +++ b/vyper/venom/basicblock.py @@ -469,8 +469,6 @@ def __init__(self, label: IRLabel, parent: "IRFunction") -> None: self.out_vars = OrderedSet() self.is_reachable = False - self._garbage_instructions: set[IRInstruction] = set() - def add_cfg_in(self, bb: "IRBasicBlock") -> None: self.cfg_in.add(bb) @@ -545,15 +543,9 @@ def insert_instruction(self, instruction: IRInstruction, index: Optional[int] = instruction.error_msg = self.parent.error_msg self.instructions.insert(index, instruction) - def mark_for_removal(self, instruction: IRInstruction) -> None: - self._garbage_instructions.add(instruction) - - def clear_dead_instructions(self) -> None: - if len(self._garbage_instructions) > 0: - self.instructions = [ - inst for inst in self.instructions if inst not in self._garbage_instructions - ] - self._garbage_instructions.clear() + def clear_nops(self) -> None: + if any(inst.opcode == "nop" for inst in self.instructions): + self.instructions = [inst for inst in self.instructions if inst.opcode != "nop"] def remove_instruction(self, instruction: IRInstruction) -> None: assert isinstance(instruction, IRInstruction), "instruction must be an IRInstruction" diff --git a/vyper/venom/passes/memmerging.py b/vyper/venom/passes/memmerging.py index 2e5ee46b84..f9be679d74 100644 --- a/vyper/venom/passes/memmerging.py +++ b/vyper/venom/passes/memmerging.py @@ -155,7 +155,7 @@ def _optimize_copy(self, bb: IRBasicBlock, copy_opcode: str, load_opcode: str): if not all(use in copy.insts for use in uses): continue - bb.mark_for_removal(inst) + inst.make_nop() self._copies.clear() self._loads.clear() @@ -285,7 +285,6 @@ def _barrier(): _barrier() _barrier() - bb.clear_dead_instructions() # optimize memzeroing operations def _optimize_memzero(self, bb: IRBasicBlock): @@ -304,7 +303,7 @@ def _optimize_memzero(self, bb: IRBasicBlock): inst.operands = [IRLiteral(copy.length), calldatasize, IRLiteral(copy.dst)] for inst in copy.insts[:-1]: - bb.mark_for_removal(inst) + inst.make_nop() self._copies.clear() self._loads.clear() @@ -350,7 +349,6 @@ def _barrier(): continue _barrier() - bb.clear_dead_instructions() def _volatile_memory(inst): diff --git a/vyper/venom/passes/remove_unused_variables.py b/vyper/venom/passes/remove_unused_variables.py index 73fe2112d7..f6de08b156 100644 --- a/vyper/venom/passes/remove_unused_variables.py +++ b/vyper/venom/passes/remove_unused_variables.py @@ -25,6 +25,9 @@ def run_pass(self): inst = work_list.pop() self._process_instruction(inst) + for bb in self.function.get_basic_blocks(): + bb.clear_nops() + self.analyses_cache.invalidate_analysis(LivenessAnalysis) self.analyses_cache.invalidate_analysis(DFGAnalysis)