Add a func_addr instruction.

Get the callable address of a function. Use for long distance calls and
for creating arguments to call_indirect in general.
This commit is contained in:
Jakob Stoklund Olesen
2017-09-19 15:54:02 -07:00
parent 0cfea8858a
commit d92686d1cd
8 changed files with 42 additions and 8 deletions

View File

@@ -49,6 +49,7 @@ BranchTable = InstructionFormat(VALUE, entities.jump_table)
Call = InstructionFormat(func_ref, VARIABLE_ARGS)
IndirectCall = InstructionFormat(sig_ref, VALUE, VARIABLE_ARGS)
FuncAddr = InstructionFormat(func_ref)
Load = InstructionFormat(memflags, VALUE, offset32)
Store = InstructionFormat(memflags, VALUE, VALUE, offset32)

View File

@@ -38,6 +38,8 @@ MemTo = TypeVar(
'MemTo', 'Any type that can be stored in memory',
ints=True, floats=True, simd=True)
addr = Operand('addr', iAddr)
#
# Control flow
#
@@ -185,6 +187,18 @@ call_indirect = Instruction(
""",
ins=(SIG, callee, args), outs=rvals, is_call=True)
func_addr = Instruction(
'func_addr', r"""
Get the address of a function.
Compute the absolute address of a function declared in the preamble.
The returned address can be used as a ``callee`` argument to
:inst:`call_indirect`. This is also a method for calling functions that
are too far away to be addressable by a direct :inst:`call`
instruction.
""",
ins=FN, outs=addr)
#
# Memory operations
#
@@ -194,7 +208,6 @@ Offset = Operand('Offset', offset32, 'Byte offset from base address')
x = Operand('x', Mem, doc='Value to be stored')
a = Operand('a', Mem, doc='Value loaded')
p = Operand('p', iAddr)
addr = Operand('addr', iAddr)
Flags = Operand('Flags', memflags)
load = Instruction(

View File

@@ -178,6 +178,7 @@ pub enum InstructionData {
sig_ref: SigRef,
args: ValueList,
},
FuncAddr { opcode: Opcode, func_ref: FuncRef },
StackLoad {
opcode: Opcode,
stack_slot: StackSlot,

View File

@@ -306,6 +306,9 @@ impl<'a> Verifier<'a> {
self.verify_sig_ref(inst, sig_ref)?;
self.verify_value_list(inst, args)?;
}
FuncAddr { func_ref, .. } => {
self.verify_func_ref(inst, func_ref)?;
}
StackLoad { stack_slot, .. } |
StackStore { stack_slot, .. } => {
self.verify_stack_slot(inst, stack_slot)?;

View File

@@ -346,6 +346,7 @@ pub fn write_operands(
DisplayValues(&args[1..])
)
}
FuncAddr { func_ref, .. } => write!(w, " {}", func_ref),
StackLoad { stack_slot, offset, .. } => write!(w, " {}{}", stack_slot, offset),
StackStore {
arg,

View File

@@ -2098,6 +2098,14 @@ impl<'a> Parser<'a> {
args: args.into_value_list(&[callee], &mut ctx.function.dfg.value_lists),
}
}
InstructionFormat::FuncAddr => {
let func_ref = self.match_fn("expected function reference").and_then(
|num| {
ctx.get_fn(num, &self.loc)
},
)?;
InstructionData::FuncAddr { opcode, func_ref }
}
InstructionFormat::BranchTable => {
let arg = self.match_value("expected SSA value operand")?;
self.match_token(