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:
@@ -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:
|
||||||
|
|||||||
@@ -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::
|
||||||
|
|
||||||
|
|||||||
@@ -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(),
|
||||||
}),
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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!();
|
||||||
|
|||||||
@@ -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.
|
||||||
#
|
#
|
||||||
|
|||||||
@@ -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())
|
||||||
|
|||||||
Reference in New Issue
Block a user