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:
Jakob Stoklund Olesen
2016-10-18 09:48:05 -07:00
parent b8a76822cf
commit bdc95990d4
8 changed files with 74 additions and 30 deletions

View File

@@ -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 Functions that are called directly must be declared in the :term:`function
preamble`: preamble`:
.. inst:: F = function NAME signature .. inst:: FN = function NAME signature
Declare a function so it can be called directly. Declare a function so it can be called directly.
:arg NAME: Name of the function, passed to the linker for resolution. :arg NAME: Name of the function, passed to the linker for resolution.
:arg signature: Function signature. See below. :arg signature: Function signature. See below.
:result F: A function identifier that can be used with :inst:`call`. :result FN: 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.
.. autoinst:: call
.. autoinst:: x_return .. autoinst:: x_return
This simple example illustrates direct function calls and signatures:: 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`. :arg signature: Function signature. See :token:`signature`.
:result SIG: A signature identifier. :result SIG: A signature identifier.
.. inst:: a, b, ... = call_indirect SIG, x(args...) .. autoinst:: call_indirect
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.
.. todo:: Define safe indirect function calls. .. todo:: Define safe indirect function calls.

View File

@@ -712,6 +712,9 @@ class InstructionFormat(object):
:py:class:`Instruction` arguments of the same name, except they must be :py:class:`Instruction` arguments of the same name, except they must be
tuples of :py:`Operand` objects. tuples of :py:`Operand` objects.
""" """
if len(outs) == 1:
multiple_results = outs[0].kind == variable_args
else:
multiple_results = len(outs) > 1 multiple_results = len(outs) > 1
sig = (multiple_results,) + tuple(op.kind for op in ins) sig = (multiple_results,) + tuple(op.kind for op in ins)
if sig not in InstructionFormat._registry: if sig not in InstructionFormat._registry:

View File

@@ -15,6 +15,7 @@ instructions = InstructionGroup("base", "Shared base instruction set")
Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True) Int = TypeVar('Int', 'A scalar or vector integer type', ints=True, simd=True)
iB = TypeVar('iB', 'A scalar integer type', ints=True) iB = TypeVar('iB', 'A scalar integer type', ints=True)
iPtr = TypeVar('iB', 'An integer address type', ints=(32, 64))
Testable = TypeVar( Testable = TypeVar(
'Testable', 'A scalar boolean or integer type', 'Testable', 'A scalar boolean or integer type',
ints=True, bools=True) ints=True, bools=True)
@@ -109,6 +110,35 @@ x_return = Instruction(
""", """,
ins=rvals) 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. # Materializing constants.
# #

View File

@@ -8,7 +8,7 @@ in this module.
from __future__ import absolute_import from __future__ import absolute_import
from . import InstructionFormat, value, variable_args from . import InstructionFormat, value, variable_args
from .immediates import imm64, uimm8, ieee32, ieee64, immvector, intcc, floatcc 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() Nullary = InstructionFormat()
@@ -47,6 +47,9 @@ BranchTable = InstructionFormat(value, jump_table)
Call = InstructionFormat( Call = InstructionFormat(
func_ref, variable_args, multiple_results=True, boxed_storage=True) 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) Return = InstructionFormat(variable_args, boxed_storage=True)

View File

@@ -5,7 +5,7 @@
use ir::{types, instructions}; use ir::{types, instructions};
use ir::{InstructionData, DataFlowGraph, Cursor}; 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::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
use ir::condcodes::{IntCC, FloatCC}; use ir::condcodes::{IntCC, FloatCC};

View File

@@ -10,7 +10,7 @@ use std::fmt::{self, Display, Formatter};
use std::str::FromStr; use std::str::FromStr;
use std::ops::{Deref, DerefMut}; 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::immediates::{Imm64, Uimm8, Ieee32, Ieee64, ImmVector};
use ir::condcodes::*; use ir::condcodes::*;
use ir::types; use ir::types;
@@ -207,6 +207,12 @@ pub enum InstructionData {
second_result: Value, second_result: Value,
data: Box<CallData>, data: Box<CallData>,
}, },
IndirectCall {
opcode: Opcode,
ty: Type,
second_result: Value,
data: Box<IndirectCallData>,
},
Return { Return {
opcode: Opcode, opcode: Opcode,
ty: Type, ty: Type,
@@ -342,10 +348,15 @@ pub struct CallData {
pub varargs: VariableArgs, pub varargs: VariableArgs,
} }
impl Display for CallData { /// Payload of an indirect call instruction.
fn fmt(&self, f: &mut Formatter) -> fmt::Result { #[derive(Clone, Debug)]
write!(f, "TBD({})", self.varargs) 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. /// Payload of a return instruction.

View File

@@ -199,7 +199,10 @@ fn write_instruction(w: &mut Write,
Jump { ref data, .. } => writeln!(w, " {}", data), Jump { ref data, .. } => writeln!(w, " {}", data),
Branch { ref data, .. } => writeln!(w, " {}", data), Branch { ref data, .. } => writeln!(w, " {}", data),
BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), 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, .. } => { Return { ref data, .. } => {
if data.varargs.is_empty() { if data.varargs.is_empty() {
writeln!(w, "") writeln!(w, "")

View File

@@ -158,6 +158,11 @@ impl Context {
try!(self.map.rewrite_values(&mut data.varargs, loc)); 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, .. } => { InstructionData::Return { ref mut data, .. } => {
try!(self.map.rewrite_values(&mut data.varargs, loc)); try!(self.map.rewrite_values(&mut data.varargs, loc));
} }
@@ -1171,6 +1176,12 @@ impl<'a> Parser<'a> {
args: [lhs, rhs], args: [lhs, rhs],
} }
} }
InstructionFormat::Call => {
unimplemented!();
}
InstructionFormat::IndirectCall => {
unimplemented!();
}
InstructionFormat::Return => { InstructionFormat::Return => {
let args = try!(self.parse_value_list()); let args = try!(self.parse_value_list());
InstructionData::Return { InstructionData::Return {
@@ -1190,9 +1201,6 @@ impl<'a> Parser<'a> {
table: table, table: table,
} }
} }
InstructionFormat::Call => {
unimplemented!();
}
}) })
} }
} }