Add call and call_indirect instructions.
Add a new IndirectCall instruction format which has a value callee as well as the call arguments. Define call and call_indirect instructions.
This commit is contained in:
@@ -373,22 +373,15 @@ platform. When calling other Cretonne functions, the flags are not necessary.
|
||||
Functions that are called directly must be declared in the :term:`function
|
||||
preamble`:
|
||||
|
||||
.. inst:: F = function NAME signature
|
||||
.. inst:: FN = function NAME signature
|
||||
|
||||
Declare a function so it can be called directly.
|
||||
|
||||
:arg NAME: Name of the function, passed to the linker for resolution.
|
||||
:arg signature: Function signature. See below.
|
||||
:result F: A function identifier that can be used with :inst:`call`.
|
||||
|
||||
.. inst:: a, b, ... = call F(args...)
|
||||
|
||||
Direct function call.
|
||||
|
||||
:arg F: Function identifier to call, declared by :inst:`function`.
|
||||
:arg args...: Function arguments matching the signature of F.
|
||||
:result a,b,...: Return values matching the signature of F.
|
||||
:result FN: A function identifier that can be used with :inst:`call`.
|
||||
|
||||
.. autoinst:: call
|
||||
.. autoinst:: x_return
|
||||
|
||||
This simple example illustrates direct function calls and signatures::
|
||||
@@ -414,14 +407,7 @@ Indirect function calls use a signature declared in the preamble.
|
||||
:arg signature: Function signature. See :token:`signature`.
|
||||
:result SIG: A signature identifier.
|
||||
|
||||
.. inst:: a, b, ... = call_indirect SIG, x(args...)
|
||||
|
||||
Indirect function call.
|
||||
|
||||
:arg SIG: A function signature identifier declared with :inst:`signature`.
|
||||
:arg iPtr x: The address of the function to call.
|
||||
:arg args...: Function arguments matching SIG.
|
||||
:result a,b,...: Return values matching SIG.
|
||||
.. autoinst:: call_indirect
|
||||
|
||||
.. todo:: Define safe indirect function calls.
|
||||
|
||||
|
||||
@@ -712,6 +712,9 @@ class InstructionFormat(object):
|
||||
:py:class:`Instruction` arguments of the same name, except they must be
|
||||
tuples of :py:`Operand` objects.
|
||||
"""
|
||||
if len(outs) == 1:
|
||||
multiple_results = outs[0].kind == variable_args
|
||||
else:
|
||||
multiple_results = len(outs) > 1
|
||||
sig = (multiple_results,) + tuple(op.kind for op in ins)
|
||||
if sig not in InstructionFormat._registry:
|
||||
|
||||
@@ -15,6 +15,7 @@ instructions = InstructionGroup("base", "Shared base instruction set")
|
||||
|
||||
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
|
||||
iB = TypeVar('iB', 'A scalar integer type', ints=True)
|
||||
iPtr = TypeVar('iB', 'An integer address type', ints=(32, 64))
|
||||
Testable = TypeVar(
|
||||
'Testable', 'A scalar boolean or integer type',
|
||||
ints=True, bools=True)
|
||||
@@ -109,6 +110,35 @@ x_return = Instruction(
|
||||
""",
|
||||
ins=rvals)
|
||||
|
||||
FN = Operand(
|
||||
'FN',
|
||||
entities.func_ref,
|
||||
doc='function to call, declared by :inst:`function`')
|
||||
args = Operand('args', variable_args, doc='call arguments')
|
||||
|
||||
call = Instruction(
|
||||
'call', r"""
|
||||
Direct function call.
|
||||
|
||||
Call a function which has been declared in the preamble. The argument
|
||||
types must match the function's signature.
|
||||
""",
|
||||
ins=(FN, args),
|
||||
outs=rvals)
|
||||
|
||||
SIG = Operand('SIG', entities.sig_ref, doc='function signature')
|
||||
callee = Operand('callee', iPtr, doc='address of function to call')
|
||||
|
||||
call_indirect = Instruction(
|
||||
'call_indirect', r"""
|
||||
Indirect function call.
|
||||
|
||||
Call the function pointed to by `callee` with the given arguments. The
|
||||
called function must match the soecified signature.
|
||||
""",
|
||||
ins=(SIG, callee, args),
|
||||
outs=rvals)
|
||||
|
||||
#
|
||||
# Materializing constants.
|
||||
#
|
||||
|
||||
@@ -8,7 +8,7 @@ in this module.
|
||||
from __future__ import absolute_import
|
||||
from . import InstructionFormat, value, variable_args
|
||||
from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc
|
||||
from .entities import ebb, func_ref, jump_table
|
||||
from .entities import ebb, sig_ref, func_ref, jump_table
|
||||
|
||||
Nullary = InstructionFormat()
|
||||
|
||||
@@ -47,6 +47,9 @@ BranchTable = InstructionFormat(value, jump_table)
|
||||
|
||||
Call = InstructionFormat(
|
||||
func_ref, variable_args, multiple_results=True, boxed_storage=True)
|
||||
IndirectCall = InstructionFormat(
|
||||
sig_ref, value, variable_args,
|
||||
multiple_results=True, boxed_storage=True)
|
||||
Return = InstructionFormat(variable_args, boxed_storage=True)
|
||||
|
||||
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
use ir::{types, instructions};
|
||||
use ir::{InstructionData, DataFlowGraph, Cursor};
|
||||
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, VariableArgs, FuncRef};
|
||||
use ir::{Opcode, Type, Inst, Value, Ebb, JumpTable, VariableArgs, SigRef, FuncRef};
|
||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
|
||||
use ir::condcodes::{IntCC, FloatCC};
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ use std::fmt::{self, Display, Formatter};
|
||||
use std::str::FromStr;
|
||||
use std::ops::{Deref, DerefMut};
|
||||
|
||||
use ir::{Value, Type, Ebb, JumpTable, FuncRef};
|
||||
use ir::{Value, Type, Ebb, JumpTable, SigRef, FuncRef};
|
||||
use ir::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
|
||||
use ir::condcodes::*;
|
||||
use ir::types;
|
||||
@@ -207,6 +207,12 @@ pub enum InstructionData {
|
||||
second_result: Value,
|
||||
data: Box<CallData>,
|
||||
},
|
||||
IndirectCall {
|
||||
opcode: Opcode,
|
||||
ty: Type,
|
||||
second_result: Value,
|
||||
data: Box<IndirectCallData>,
|
||||
},
|
||||
Return {
|
||||
opcode: Opcode,
|
||||
ty: Type,
|
||||
@@ -342,10 +348,15 @@ pub struct CallData {
|
||||
pub varargs: VariableArgs,
|
||||
}
|
||||
|
||||
impl Display for CallData {
|
||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
||||
write!(f, "TBD({})", self.varargs)
|
||||
}
|
||||
/// Payload of an indirect call instruction.
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct IndirectCallData {
|
||||
/// Callee function.
|
||||
pub arg: Value,
|
||||
pub sig_ref: SigRef,
|
||||
|
||||
/// Dynamically sized array containing call argument values.
|
||||
pub varargs: VariableArgs,
|
||||
}
|
||||
|
||||
/// Payload of a return instruction.
|
||||
|
||||
@@ -199,7 +199,10 @@ fn write_instruction(w: &mut Write,
|
||||
Jump { ref data, .. } => writeln!(w, " {}", data),
|
||||
Branch { ref data, .. } => writeln!(w, " {}", data),
|
||||
BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table),
|
||||
Call { ref data, .. } => writeln!(w, " {}", data),
|
||||
Call { ref data, .. } => writeln!(w, " {}({})", data.func_ref, data.varargs),
|
||||
IndirectCall { ref data, .. } => {
|
||||
writeln!(w, " {}, {}({})", data.sig_ref, data.arg, data.varargs)
|
||||
}
|
||||
Return { ref data, .. } => {
|
||||
if data.varargs.is_empty() {
|
||||
writeln!(w, "")
|
||||
|
||||
@@ -158,6 +158,11 @@ impl Context {
|
||||
try!(self.map.rewrite_values(&mut data.varargs, loc));
|
||||
}
|
||||
|
||||
InstructionData::IndirectCall { ref mut data, .. } => {
|
||||
try!(self.map.rewrite_value(&mut data.arg, loc));
|
||||
try!(self.map.rewrite_values(&mut data.varargs, loc));
|
||||
}
|
||||
|
||||
InstructionData::Return { ref mut data, .. } => {
|
||||
try!(self.map.rewrite_values(&mut data.varargs, loc));
|
||||
}
|
||||
@@ -1171,6 +1176,12 @@ impl<'a> Parser<'a> {
|
||||
args: [lhs, rhs],
|
||||
}
|
||||
}
|
||||
InstructionFormat::Call => {
|
||||
unimplemented!();
|
||||
}
|
||||
InstructionFormat::IndirectCall => {
|
||||
unimplemented!();
|
||||
}
|
||||
InstructionFormat::Return => {
|
||||
let args = try!(self.parse_value_list());
|
||||
InstructionData::Return {
|
||||
@@ -1190,9 +1201,6 @@ impl<'a> Parser<'a> {
|
||||
table: table,
|
||||
}
|
||||
}
|
||||
InstructionFormat::Call => {
|
||||
unimplemented!();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user