diff --git a/docs/langref.rst b/docs/langref.rst index b2ced79300..8acc2b4ef2 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -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. diff --git a/lib/cretonne/meta/cretonne/__init__.py b/lib/cretonne/meta/cretonne/__init__.py index a6cef5397b..a38126f98f 100644 --- a/lib/cretonne/meta/cretonne/__init__.py +++ b/lib/cretonne/meta/cretonne/__init__.py @@ -712,7 +712,10 @@ class InstructionFormat(object): :py:class:`Instruction` arguments of the same name, except they must be tuples of :py:`Operand` objects. """ - multiple_results = len(outs) > 1 + 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: raise RuntimeError( diff --git a/lib/cretonne/meta/cretonne/base.py b/lib/cretonne/meta/cretonne/base.py index b665cf5d71..f507526626 100644 --- a/lib/cretonne/meta/cretonne/base.py +++ b/lib/cretonne/meta/cretonne/base.py @@ -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. # diff --git a/lib/cretonne/meta/cretonne/formats.py b/lib/cretonne/meta/cretonne/formats.py index 8e5d4e25cb..cb8aed3f98 100644 --- a/lib/cretonne/meta/cretonne/formats.py +++ b/lib/cretonne/meta/cretonne/formats.py @@ -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) diff --git a/lib/cretonne/src/ir/builder.rs b/lib/cretonne/src/ir/builder.rs index e31be0f2ca..f8510bb7f4 100644 --- a/lib/cretonne/src/ir/builder.rs +++ b/lib/cretonne/src/ir/builder.rs @@ -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}; diff --git a/lib/cretonne/src/ir/instructions.rs b/lib/cretonne/src/ir/instructions.rs index 37b1106d36..f7fb6f3d94 100644 --- a/lib/cretonne/src/ir/instructions.rs +++ b/lib/cretonne/src/ir/instructions.rs @@ -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, }, + IndirectCall { + opcode: Opcode, + ty: Type, + second_result: Value, + data: Box, + }, 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. diff --git a/lib/cretonne/src/write.rs b/lib/cretonne/src/write.rs index 3ef72d7178..dfae305933 100644 --- a/lib/cretonne/src/write.rs +++ b/lib/cretonne/src/write.rs @@ -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, "") diff --git a/lib/reader/src/parser.rs b/lib/reader/src/parser.rs index 89786ed2b3..186fd6df1e 100644 --- a/lib/reader/src/parser.rs +++ b/lib/reader/src/parser.rs @@ -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!(); - } }) } }