Skip to content

Commit

Permalink
clean-out call-conv implementation
Browse files Browse the repository at this point in the history
  • Loading branch information
harkal committed Feb 18, 2025
1 parent d3a7b32 commit e98dc17
Show file tree
Hide file tree
Showing 3 changed files with 12 additions and 144 deletions.
111 changes: 6 additions & 105 deletions vyper/venom/ir_node_to_venom.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,7 @@
IRVariable,
)
from vyper.venom.context import IRContext
from vyper.venom.function import IRFunction, IRParameter

ENABLE_NEW_CALL_CONV = True
from vyper.venom.function import IRFunction

# Instructions that are mapped to their inverse
INVERSE_MAPPED_IR_INSTRUCTIONS = {"ne": "eq", "le": "gt", "sle": "sgt", "ge": "lt", "sge": "slt"}
Expand Down Expand Up @@ -175,18 +173,13 @@ def _handle_self_call(fn: IRFunction, ir: IRnode, symbols: SymbolTable) -> Optio
func_t = ir.passthrough_metadata["func_t"]
assert func_t is not None, "func_t not found in passthrough metadata"

returns_word = _returns_word(func_t)

stack_args: list[IROperand] = []

if setup_ir != goto_ir:
_convert_ir_bb(fn, setup_ir, symbols)

converted_args = _convert_ir_bb_list(fn, goto_ir.args[1:], symbols)

callsite_op = converted_args[-1]
assert isinstance(callsite_op, IRLabel), converted_args
callsite = callsite_op.value

bb = fn.get_basic_block()
return_buf = None
Expand All @@ -195,27 +188,7 @@ def _handle_self_call(fn: IRFunction, ir: IRnode, symbols: SymbolTable) -> Optio
return_buf = converted_args[0]

if return_buf is not None:
if not ENABLE_NEW_CALL_CONV or not returns_word:
ret_args.append(return_buf) # type: ignore

callsite_args = _callsites[callsite]
stack_args = []
if ENABLE_NEW_CALL_CONV:
for alloca in callsite_args:
if not _is_word_type(alloca.typ):
continue
ptr = _alloca_table[alloca._id]
stack_arg = bb.append_instruction("mload", ptr)
assert stack_arg is not None
stack_args.append(stack_arg)
ret_args.extend(stack_args)

if returns_word:
ret_value = bb.append_invoke_instruction(ret_args, returns=True) # type: ignore
assert ret_value is not None
assert isinstance(return_buf, IROperand)
bb.append_instruction("mstore", ret_value, return_buf)
return return_buf
ret_args.append(return_buf) # type: ignore

bb.append_invoke_instruction(ret_args, returns=False) # type: ignore

Expand Down Expand Up @@ -248,76 +221,32 @@ def _handle_internal_func(

_current_func_t = ir.passthrough_metadata["func_t"]

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable '_current_func_t' is not used.
_current_context = ir.passthrough_metadata["context"]

Check notice

Code scanning / CodeQL

Unused global variable Note

The global variable '_current_context' is not used.
func_t = _current_func_t
context = _current_context

fn = fn.ctx.create_function(ir.args[0].args[0].value)

if ENABLE_NEW_CALL_CONV:
index = 0
if func_t.return_type is not None and not _returns_word(func_t):
index += 1
for arg in func_t.arguments:
var = context.lookup_var(arg.name)
if not _is_word_type(var.typ):
continue
venom_arg = IRParameter(
var.name, index, var.alloca.offset, var.alloca.size, None, None, None
)
fn.args.append(venom_arg)
index += 1

bb = fn.get_basic_block()

_saved_alloca_table = _alloca_table
_alloca_table = {}

returns_word = _returns_word(func_t)

# return buffer
if does_return_data:
if ENABLE_NEW_CALL_CONV and returns_word:
# this alloca should be stripped by mem2var. we can remove
# the hardcoded offset once we have proper memory allocator
# functionality in venom.
buf = bb.append_instruction("alloca", IRLiteral(-1), IRLiteral(-1), IRLiteral(-1))
else:
buf = bb.append_instruction("param")
bb.instructions[-1].annotation = "return_buffer"
buf = bb.append_instruction("param")
bb.instructions[-1].annotation = "return_buffer"

assert buf is not None # help mypy
symbols["return_buffer"] = buf

if ENABLE_NEW_CALL_CONV:
for arg in fn.args:
ret = bb.append_instruction("param")
bb.instructions[-1].annotation = arg.name
assert ret is not None # help mypy
symbols[arg.name] = ret
arg.func_var = ret

# return address
return_pc = bb.append_instruction("param")
assert return_pc is not None # help mypy
symbols["return_pc"] = return_pc

bb.instructions[-1].annotation = "return_pc"

if ENABLE_NEW_CALL_CONV:
for arg in fn.args:
var = IRVariable(arg.name)
bb.append_instruction("store", IRLiteral(arg.offset), ret=var) # type: ignore
arg.addr_var = var

_convert_ir_bb(fn, ir.args[0].args[2], symbols)

_alloca_table = _saved_alloca_table
# if ENABLE_NEW_CALL_CONV:
# for inst in bb.instructions:
# if inst.opcode == "store":
# param = fn.get_param_at_offset(inst.operands[0].value)
# if param is not None:
# inst.operands[0] = param.addr_var # type: ignore

return fn

Expand Down Expand Up @@ -529,12 +458,7 @@ def _convert_ir_bb(fn, ir, symbols):
if label.value == "return_pc":
label = symbols.get("return_pc")
# return label should be top of stack
if _returns_word(_current_func_t) and ENABLE_NEW_CALL_CONV:
buf = symbols["return_buffer"]
val = bb.append_instruction("mload", buf)
bb.append_instruction("ret", val, label)
else:
bb.append_instruction("ret", label)
bb.append_instruction("ret", label)
else:
bb.append_instruction("jmp", label)

Expand All @@ -543,29 +467,11 @@ def _convert_ir_bb(fn, ir, symbols):
# to fix upstream.
val, ptr = _convert_ir_bb_list(fn, reversed(ir.args), symbols)

if ENABLE_NEW_CALL_CONV:
if isinstance(ptr, IRVariable):
# TODO: is this bad code?
param = fn.get_param_by_name(ptr)
if param is not None:
return fn.get_basic_block().append_instruction("store", val, ret=param.func_var)

if isinstance(ptr, IRLabel) and ptr.value.startswith("$palloca"):
symbol = symbols.get(ptr.annotation, None)
if symbol is not None:
return fn.get_basic_block().append_instruction("store", symbol)

return fn.get_basic_block().append_instruction("mstore", val, ptr)
elif ir.value == "mload":
arg = ir.args[0]
ptr = _convert_ir_bb(fn, arg, symbols)

if ENABLE_NEW_CALL_CONV:
if isinstance(arg.value, str) and arg.value.startswith("$palloca"):
symbol = symbols.get(arg.annotation, None)
if symbol is not None:
return fn.get_basic_block().append_instruction("store", symbol)

return fn.get_basic_block().append_instruction("mload", ptr)
elif ir.value == "ceil32":
x = ir.args[0]
Expand Down Expand Up @@ -676,8 +582,6 @@ def emit_body_blocks():

elif ir.value.startswith("$palloca"):
alloca = ir.passthrough_metadata["alloca"]
if ENABLE_NEW_CALL_CONV and fn.get_param_at_offset(alloca.offset) is not None:
return fn.get_param_at_offset(alloca.offset).addr_var
if alloca._id not in _alloca_table:
ptr = fn.get_basic_block().append_instruction(
"palloca", alloca.offset, alloca.size, alloca._id
Expand All @@ -691,10 +595,7 @@ def emit_body_blocks():
assert alloca._callsite is not None
if alloca._id not in _alloca_table:
bb = fn.get_basic_block()

Check notice

Code scanning / CodeQL

Unused local variable Note

Variable bb is not used.
if ENABLE_NEW_CALL_CONV and _is_word_type(alloca.typ):
ptr = bb.append_instruction("alloca", alloca.offset, alloca.size, alloca._id)
else:
ptr = IRLiteral(alloca.offset)
ptr = IRLiteral(alloca.offset)

_alloca_table[alloca._id] = ptr
ret = _alloca_table[alloca._id]
Expand Down
8 changes: 0 additions & 8 deletions vyper/venom/passes/func_inliner.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,5 @@
from typing import List, Optional

from vyper.venom.ir_node_to_venom import ENABLE_NEW_CALL_CONV
from vyper.compiler.settings import OptimizationLevel
from vyper.exceptions import CompilerPanic
from vyper.utils import OrderedSet
Expand Down Expand Up @@ -148,13 +147,6 @@ def _inline_call_site(self, func: IRFunction, call_site: IRInstruction) -> None:
):
inst.make_nop()
elif inst.opcode == "ret":
if len(inst.operands) > 1:
# sanity check (should remove once new callconv stabilizes)
assert ENABLE_NEW_CALL_CONV
ret_value = inst.operands[0]
bb.insert_instruction(
IRInstruction("store", [ret_value], call_site.output), -1
)
inst.opcode = "jmp"
inst.operands = [call_site_return.label]
elif inst.opcode in ["jmp", "jnz", "djmp", "phi"]:
Expand Down
37 changes: 6 additions & 31 deletions vyper/venom/venom_to_assembly.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,6 @@
IRVariable,
)
from vyper.venom.context import IRContext
from vyper.venom.ir_node_to_venom import ENABLE_NEW_CALL_CONV
from vyper.venom.passes import NormalizationPass
from vyper.venom.stack_model import StackModel

Expand Down Expand Up @@ -303,38 +302,14 @@ def _generate_evm_for_basicblock_r(
if len(basicblock.cfg_in) == 1:
self.clean_stack_from_cfg_in(asm, basicblock, stack)

if ENABLE_NEW_CALL_CONV:
param_insts = [inst for inst in basicblock.instructions if inst.opcode == "param"]
body_insts = [inst for inst in basicblock.instructions if inst.opcode != "param"]

params_to_pop = []
for inst in param_insts:
assert isinstance(inst.output, IRVariable)
stack.push(inst.output)
if len(self.dfg.get_uses(inst.output)) == 0:
params_to_pop.append(inst.output)

for param in params_to_pop:
depth = stack.get_depth(param)
if depth != StackModel.NOT_IN_STACK:
self.swap(asm, stack, depth)
self.pop(asm, stack)

for i, inst in enumerate(body_insts):
next_liveness = (
body_insts[i + 1].liveness if i + 1 < len(body_insts) else basicblock.out_vars
)

asm.extend(self._generate_evm_for_instruction(inst, stack, next_liveness))
else:
all_insts = sorted(basicblock.instructions, key=lambda x: x.opcode != "param")
all_insts = sorted(basicblock.instructions, key=lambda x: x.opcode != "param")

for i, inst in enumerate(all_insts):
next_liveness = (
all_insts[i + 1].liveness if i + 1 < len(all_insts) else basicblock.out_vars
)
for i, inst in enumerate(all_insts):
next_liveness = (
all_insts[i + 1].liveness if i + 1 < len(all_insts) else basicblock.out_vars
)

asm.extend(self._generate_evm_for_instruction(inst, stack, next_liveness))
asm.extend(self._generate_evm_for_instruction(inst, stack, next_liveness))

if DEBUG_SHOW_COST:
print(" ".join(map(str, asm)), file=sys.stderr)
Expand Down

0 comments on commit e98dc17

Please sign in to comment.