Define a return instruction.

It is possible to return multiple values from a function, so ReturnData contains
a VariableArgs instance.

We don't want return instructions to appear as 'return (v1)', so tweak the
printing of VariableArgs so the parantheses are added externally.
This commit is contained in:
Jakob Stoklund Olesen
2016-07-08 16:19:26 -07:00
parent 6587784d7d
commit 3839281414
7 changed files with 61 additions and 21 deletions

View File

@@ -265,12 +265,17 @@ class InstDocumenter(sphinx.ext.autodoc.Documenter):
def format_signature(self): def format_signature(self):
inst = self.object inst = self.object
sig = self.format_name() sig = inst.name
if len(inst.outs) > 0: if len(inst.outs) > 0:
sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig sig = ', '.join([op.name for op in inst.outs]) + ' = ' + sig
if len(inst.ins) > 0: 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:]: for op in inst.ins[1:]:
# This is a call or branch with args in (...).
if op.typ.operand_kind().name == 'variable_args': if op.typ.operand_kind().name == 'variable_args':
sig += '({}...)'.format(op.name) sig += '({}...)'.format(op.name)
else: else:

View File

@@ -393,16 +393,7 @@ preamble`:
:arg args...: Function arguments matching the signature of F. :arg args...: Function arguments matching the signature of F.
:result a,b,...: Return values matching the signature of F. :result a,b,...: Return values matching the signature of F.
.. inst:: return args... .. autoinst:: x_return
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.
This simple example illustrates direct function calls and signatures:: This simple example illustrates direct function calls and signatures::

View File

@@ -210,6 +210,11 @@ pub enum InstructionData {
ty: Type, ty: Type,
data: Box<CallData>, data: Box<CallData>,
}, },
Return {
opcode: Opcode,
ty: Type,
data: Box<ReturnData>,
},
} }
/// A variable list of `Value` operands used for function call arguments and passing arguments to /// 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 { impl Display for VariableArgs {
fn fmt(&self, fmt: &mut Formatter) -> fmt::Result { fn fmt(&self, fmt: &mut Formatter) -> fmt::Result {
try!(write!(fmt, "("));
for (i, val) in self.0.iter().enumerate() { for (i, val) in self.0.iter().enumerate() {
if i == 0 { if i == 0 {
try!(write!(fmt, "{}", val)); try!(write!(fmt, "{}", val));
@@ -256,7 +260,7 @@ impl Display for VariableArgs {
try!(write!(fmt, ", {}", val)); try!(write!(fmt, ", {}", val));
} }
} }
write!(fmt, ")") Ok(())
} }
} }
@@ -279,7 +283,7 @@ impl Display for JumpData {
if self.arguments.is_empty() { if self.arguments.is_empty() {
write!(f, "{}", self.destination) write!(f, "{}", self.destination)
} else { } 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 { fn fmt(&self, f: &mut Formatter) -> fmt::Result {
try!(write!(f, "{}, {}", self.arg, self.destination)); try!(write!(f, "{}, {}", self.arg, self.destination));
if !self.arguments.is_empty() { if !self.arguments.is_empty() {
try!(write!(f, "{}", self.arguments)); try!(write!(f, "({})", self.arguments));
} }
Ok(()) Ok(())
} }
@@ -310,15 +314,22 @@ pub struct CallData {
second_result: Value, second_result: Value,
// Dynamically sized array containing call argument values. // Dynamically sized array containing call argument values.
pub arguments: VariableArgs, pub args: VariableArgs,
} }
impl Display for CallData { impl Display for CallData {
fn fmt(&self, f: &mut Formatter) -> fmt::Result { 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 { impl InstructionData {
/// Create data for a call instruction. /// Create data for a call instruction.
pub fn call(opc: Opcode, return_type: Type) -> InstructionData { pub fn call(opc: Opcode, return_type: Type) -> InstructionData {
@@ -327,7 +338,7 @@ impl InstructionData {
ty: return_type, ty: return_type,
data: Box::new(CallData { data: Box::new(CallData {
second_result: NO_VALUE, second_result: NO_VALUE,
arguments: VariableArgs::new(), args: VariableArgs::new(),
}), }),
} }
} }

View File

@@ -203,6 +203,13 @@ pub fn write_instruction(w: &mut Write, func: &Function, inst: Inst) -> Result {
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),
Return { ref data, .. } => {
if data.args.is_empty() {
writeln!(w, "")
} else {
writeln!(w, " {}", data.args)
}
}
} }
} }

View File

@@ -15,7 +15,7 @@ use cretonne::types::{Type, VOID, FunctionName, Signature, ArgumentType, Argumen
use cretonne::immediates::{Imm64, Ieee32, Ieee64}; use cretonne::immediates::{Imm64, Ieee32, Ieee64};
use cretonne::entities::*; use cretonne::entities::*;
use cretonne::instructions::{Opcode, InstructionFormat, InstructionData, VariableArgs, JumpData, use cretonne::instructions::{Opcode, InstructionFormat, InstructionData, VariableArgs, JumpData,
BranchData}; BranchData, ReturnData};
use cretonne::repr::{Function, StackSlotData}; use cretonne::repr::{Function, StackSlotData};
pub use lexer::Location; pub use lexer::Location;
@@ -201,7 +201,11 @@ impl Context {
} }
InstructionData::Call { ref mut data, .. } => { 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], 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::BranchTable |
InstructionFormat::Call => { InstructionFormat::Call => {
unimplemented!(); unimplemented!();

View File

@@ -95,6 +95,18 @@ trapnz = Instruction(
""", """,
ins=c) 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. # Materializing constants.
# #

View File

@@ -43,6 +43,8 @@ BranchTable = InstructionFormat(value, jump_table)
Call = InstructionFormat( Call = InstructionFormat(
function, variable_args, multiple_results=True, boxed_storage=True) 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. # Finally extract the names of global variables in this module.
InstructionFormat.extract_names(globals()) InstructionFormat.extract_names(globals())