Skip to content

Commit a5caad1

Browse files
feat[venom]: add calloca instruction
this instruction is meant to help match call-site allocations with pallocas (inside the callee).
1 parent 3a9428b commit a5caad1

File tree

5 files changed

+39
-4
lines changed

5 files changed

+39
-4
lines changed

vyper/codegen/self_call.py

+22-1
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
import copy
2+
13
from vyper.codegen.core import _freshname, eval_once_check, make_setter
24
from vyper.codegen.ir_node import IRnode
35
from vyper.evm.address_space import MEMORY
@@ -66,7 +68,26 @@ def ir_for_self_call(stmt_expr, context):
6668

6769
# note: dst_tuple_t != args_tuple_t
6870
dst_tuple_t = TupleT(tuple(func_t.argument_types))
69-
args_dst = IRnode(func_t._ir_info.frame_info.frame_start, typ=dst_tuple_t, location=MEMORY)
71+
if context.settings.experimental_codegen:
72+
arg_items = ["multi"]
73+
frame_info = func_t._ir_info.frame_info
74+
75+
for var in frame_info.frame_vars.values():
76+
var = copy.copy(var)
77+
alloca = var.alloca
78+
assert alloca is not None
79+
assert isinstance(var.pos, str) # help mypy
80+
if not var.pos.startswith("$palloca"):
81+
continue
82+
newname = var.pos.replace("$palloca", "$calloca")
83+
var.pos = newname
84+
irnode = var.as_ir_node()
85+
irnode.passthrough_metadata["alloca"] = alloca
86+
arg_items.append(irnode)
87+
args_dst = IRnode.from_list(arg_items, typ=dst_tuple_t)
88+
else:
89+
# legacy
90+
args_dst = IRnode(func_t._ir_info.frame_info.frame_start, typ=dst_tuple_t, location=MEMORY)
7091

7192
# if one of the arguments is a self call, the argument
7293
# buffer could get borked. to prevent against that,

vyper/venom/README.md

+5
Original file line numberDiff line numberDiff line change
@@ -221,6 +221,11 @@ Assembly can be inspected with `-f asm`, whereas an opcode view of the final byt
221221
out = palloca size, offset, id
222222
```
223223
- Like the `alloca` instruction but only used for parameters of internal functions which are passed by memory.
224+
- `calloca`
225+
- ```
226+
out = calloca size, offset, id
227+
```
228+
- Similar to the `calloca` instruction but only used for parameters of internal functions which are passed by memory. Used at the call-site of a call.
224229
- `iload`
225230
- ```
226231
out = iload offset

vyper/venom/ir_node_to_venom.py

+9
Original file line numberDiff line numberDiff line change
@@ -542,6 +542,15 @@ def emit_body_blocks():
542542
_alloca_table[alloca._id] = ptr
543543
return _alloca_table[alloca._id]
544544

545+
elif ir.value.startswith("$calloca"):
546+
alloca = ir.passthrough_metadata["alloca"]
547+
if alloca._id not in _alloca_table:
548+
ptr = fn.get_basic_block().append_instruction(
549+
"calloca", alloca.offset, alloca.size, alloca._id
550+
)
551+
_alloca_table[alloca._id] = ptr
552+
return _alloca_table[alloca._id]
553+
545554
return symbols.get(ir.value)
546555
elif ir.is_literal:
547556
return IRLiteral(ir.value)

vyper/venom/passes/sccp/sccp.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -177,7 +177,7 @@ def _visit_phi(self, inst: IRInstruction):
177177

178178
def _visit_expr(self, inst: IRInstruction):
179179
opcode = inst.opcode
180-
if opcode in ["store", "alloca", "palloca"]:
180+
if opcode in ["store", "alloca", "palloca", "calloca"]:
181181
assert inst.output is not None, "Got store/alloca without output"
182182
out = self._eval_from_lattice(inst.operands[0])
183183
self._set_lattice(inst.output, out)

vyper/venom/venom_to_assembly.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -364,7 +364,7 @@ def _generate_evm_for_instruction(
364364

365365
if opcode in ["jmp", "djmp", "jnz", "invoke"]:
366366
operands = list(inst.get_non_label_operands())
367-
elif opcode in ("alloca", "palloca"):
367+
elif opcode in ("alloca", "palloca", "calloca"):
368368
offset, _size = inst.operands
369369
operands = [offset]
370370

@@ -464,7 +464,7 @@ def _generate_evm_for_instruction(
464464
# Step 5: Emit the EVM instruction(s)
465465
if opcode in _ONE_TO_ONE_INSTRUCTIONS:
466466
assembly.append(opcode.upper())
467-
elif opcode in ("alloca", "palloca"):
467+
elif opcode in ("alloca", "palloca", "calloca"):
468468
pass
469469
elif opcode == "param":
470470
pass

0 commit comments

Comments
 (0)