diff --git a/docs/cton_domain.py b/docs/cton_domain.py index bd207e994d..aafb7724cf 100644 --- a/docs/cton_domain.py +++ b/docs/cton_domain.py @@ -265,12 +265,17 @@ class InstDocumenter(sphinx.ext.autodoc.Documenter): def format_signature(self): inst = self.object - sig = self.format_name() + sig = inst.name if len(inst.outs) > 0: sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig if len(inst.ins) > 0: - sig = sig + ' ' + inst.ins[0].name + op = inst.ins[0] + sig += ' ' + op.name + # If the first input is variable-args, this is 'return'. No parens. + if op.typ.operand_kind().name == 'variable_args': + sig += '...'.format(op.name) for op in inst.ins[1:]: + # This is a call or branch with args in (...). if op.typ.operand_kind().name == 'variable_args': sig += '({}...)'.format(op.name) else: diff --git a/docs/langref.rst b/docs/langref.rst index 9181f10e26..e323dd617d 100644 --- a/docs/langref.rst +++ b/docs/langref.rst @@ -393,16 +393,7 @@ preamble`: :arg args...: Function arguments matching the signature of F. :result a,b,...: Return values matching the signature of F. -.. inst:: return args... - - Return from function. - - Unconditionally transfer control to the calling function, passing the - provided return values. - - :arg args: Return values. The list of return values must match the list of - return value types in the function signature. - :result: None. This is a terminator instruction. +.. autoinst:: x_return This simple example illustrates direct function calls and signatures:: diff --git a/meta/cretonne/base.py b/meta/cretonne/base.py index 894ac2f505..1f17bab749 100644 --- a/meta/cretonne/base.py +++ b/meta/cretonne/base.py @@ -95,6 +95,18 @@ trapnz = Instruction( """, ins=c) +rvals = Operand('rvals', variable_args, doc='return values') + +x_return = Instruction( + 'return', r""" + Return from the function. + + Unconditionally transfer control to the calling function, passing the + provided return values. The list of return values must match the + function signature's return types. + """, + ins=rvals) + # # Materializing constants. # diff --git a/meta/cretonne/formats.py b/meta/cretonne/formats.py index 5fc6cd7a2d..4798b9ed25 100644 --- a/meta/cretonne/formats.py +++ b/meta/cretonne/formats.py @@ -43,6 +43,8 @@ BranchTable = InstructionFormat(value, jump_table) Call = InstructionFormat( function, variable_args, multiple_results=True, boxed_storage=True) +Return = InstructionFormat(variable_args, boxed_storage=True) + # Finally extract the names of global variables in this module. InstructionFormat.extract_names(globals()) diff --git a/src/libcretonne/instructions.rs b/src/libcretonne/instructions.rs index 9a87e85d71..8ebd63d411 100644 --- a/src/libcretonne/instructions.rs +++ b/src/libcretonne/instructions.rs @@ -210,6 +210,11 @@ pub enum InstructionData { ty: Type, data: Box, }, + Return { + opcode: Opcode, + ty: Type, + data: Box, + }, } /// A variable list of `Value` operands used for function call arguments and passing arguments to @@ -248,7 +253,6 @@ impl DerefMut for VariableArgs { impl Display for VariableArgs { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { - try!(write!(fmt, "(")); for (i, val) in self.0.iter().enumerate() { if i == 0 { try!(write!(fmt, "{}", val)); @@ -256,7 +260,7 @@ impl Display for VariableArgs { try!(write!(fmt, ", {}", val)); } } - write!(fmt, ")") + Ok(()) } } @@ -279,7 +283,7 @@ impl Display for JumpData { if self.arguments.is_empty() { write!(f, "{}", self.destination) } else { - write!(f, "{}{}", self.destination, self.arguments) + write!(f, "{}({})", self.destination, self.arguments) } } } @@ -297,7 +301,7 @@ impl Display for BranchData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { try!(write!(f, "{}, {}", self.arg, self.destination)); if !self.arguments.is_empty() { - try!(write!(f, "{}", self.arguments)); + try!(write!(f, "({})", self.arguments)); } Ok(()) } @@ -310,15 +314,22 @@ pub struct CallData { second_result: Value, // Dynamically sized array containing call argument values. - pub arguments: VariableArgs, + pub args: VariableArgs, } impl Display for CallData { fn fmt(&self, f: &mut Formatter) -> fmt::Result { - write!(f, "TBD{}", self.arguments) + write!(f, "TBD({})", self.args) } } +/// Payload of a return instruction. +#[derive(Debug)] +pub struct ReturnData { + // Dynamically sized array containing return values. + pub args: VariableArgs, +} + impl InstructionData { /// Create data for a call instruction. pub fn call(opc: Opcode, return_type: Type) -> InstructionData { @@ -327,7 +338,7 @@ impl InstructionData { ty: return_type, data: Box::new(CallData { second_result: NO_VALUE, - arguments: VariableArgs::new(), + args: VariableArgs::new(), }), } } diff --git a/src/libcretonne/write.rs b/src/libcretonne/write.rs index 22d87ba103..e49956970a 100644 --- a/src/libcretonne/write.rs +++ b/src/libcretonne/write.rs @@ -203,6 +203,13 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result { Branch { ref data, .. } => writeln!(w, " {}", data), BranchTable { arg, table, .. } => writeln!(w, " {}, {}", arg, table), Call { ref data, .. } => writeln!(w, " {}", data), + Return { ref data, .. } => { + if data.args.is_empty() { + writeln!(w, "") + } else { + writeln!(w, " {}", data.args) + } + } } } diff --git a/src/libreader/parser.rs b/src/libreader/parser.rs index e55a277d18..34dd15f735 100644 --- a/src/libreader/parser.rs +++ b/src/libreader/parser.rs @@ -15,7 +15,7 @@ use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, Argumen use cretonne::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::entities::*; use cretonne::instructions::{Opcode, InstructionFormat, InstructionData, VariableArgs, JumpData, - BranchData}; + BranchData, ReturnData}; use cretonne::repr::{Function, StackSlotData}; pub use lexer::Location; @@ -201,7 +201,11 @@ impl Context { } InstructionData::Call { ref mut data, .. } => { - try!(Self::rewrite_values(&self.values, &mut data.arguments, &loc)); + try!(Self::rewrite_values(&self.values, &mut data.args, &loc)); + } + + InstructionData::Return { ref mut data, .. } => { + try!(Self::rewrite_values(&self.values, &mut data.args, &loc)); } } } @@ -1015,6 +1019,14 @@ impl<'a> Parser<'a> { args: [lhs, rhs], } } + InstructionFormat::Return => { + let args = try!(self.parse_value_list()); + InstructionData::Return { + opcode: opcode, + ty: VOID, + data: Box::new(ReturnData { args: args }), + } + } InstructionFormat::BranchTable | InstructionFormat::Call => { unimplemented!();