Add a return_reg instruction to the base instruction set.
Register-style return is used by all RISC architectures, so it is natural to have a shared instruction representation.
This commit is contained in:
@@ -384,6 +384,7 @@ preamble`:
|
|||||||
|
|
||||||
.. autoinst:: call
|
.. autoinst:: call
|
||||||
.. autoinst:: x_return
|
.. autoinst:: x_return
|
||||||
|
.. autoinst:: return_reg
|
||||||
|
|
||||||
This simple example illustrates direct function calls and signatures::
|
This simple example illustrates direct function calls and signatures::
|
||||||
|
|
||||||
|
|||||||
@@ -52,7 +52,7 @@ IndirectCall = InstructionFormat(
|
|||||||
sig_ref, VALUE, VARIABLE_ARGS,
|
sig_ref, VALUE, VARIABLE_ARGS,
|
||||||
multiple_results=True, boxed_storage=True)
|
multiple_results=True, boxed_storage=True)
|
||||||
Return = InstructionFormat(VARIABLE_ARGS, boxed_storage=True)
|
Return = InstructionFormat(VARIABLE_ARGS, boxed_storage=True)
|
||||||
|
ReturnReg = InstructionFormat(VALUE, 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())
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ GROUP = 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))
|
iAddr = TypeVar('iAddr', '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)
|
||||||
@@ -113,6 +113,25 @@ x_return = Instruction(
|
|||||||
""",
|
""",
|
||||||
ins=rvals, is_terminator=True)
|
ins=rvals, is_terminator=True)
|
||||||
|
|
||||||
|
raddr = Operand('raddr', iAddr, doc='Return address')
|
||||||
|
|
||||||
|
return_reg = Instruction(
|
||||||
|
'return_reg', r"""
|
||||||
|
Return from the function to a return address held in a register.
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
|
This instruction should only be used by ISA-specific epilogue lowering
|
||||||
|
code. It is equivalent to :inst:`return`, but the return address is
|
||||||
|
provided explicitly in a register. This style of return instruction is
|
||||||
|
used by RISC architectures such as ARM and RISC-V. A normal
|
||||||
|
:inst:`return` will be legalized into this instruction on these
|
||||||
|
architectures.
|
||||||
|
""",
|
||||||
|
ins=(raddr, rvals), is_terminator=True)
|
||||||
|
|
||||||
FN = Operand(
|
FN = Operand(
|
||||||
'FN',
|
'FN',
|
||||||
entities.func_ref,
|
entities.func_ref,
|
||||||
@@ -130,7 +149,7 @@ call = Instruction(
|
|||||||
outs=rvals)
|
outs=rvals)
|
||||||
|
|
||||||
SIG = Operand('SIG', entities.sig_ref, doc='function signature')
|
SIG = Operand('SIG', entities.sig_ref, doc='function signature')
|
||||||
callee = Operand('callee', iPtr, doc='address of function to call')
|
callee = Operand('callee', iAddr, doc='address of function to call')
|
||||||
|
|
||||||
call_indirect = Instruction(
|
call_indirect = Instruction(
|
||||||
'call_indirect', r"""
|
'call_indirect', r"""
|
||||||
|
|||||||
@@ -222,6 +222,11 @@ pub enum InstructionData {
|
|||||||
ty: Type,
|
ty: Type,
|
||||||
data: Box<ReturnData>,
|
data: Box<ReturnData>,
|
||||||
},
|
},
|
||||||
|
ReturnReg {
|
||||||
|
opcode: Opcode,
|
||||||
|
ty: Type,
|
||||||
|
data: Box<ReturnRegData>,
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
/// 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
|
||||||
@@ -406,6 +411,27 @@ pub struct ReturnData {
|
|||||||
pub varargs: VariableArgs,
|
pub varargs: VariableArgs,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Payload of a return instruction.
|
||||||
|
#[derive(Clone, Debug)]
|
||||||
|
pub struct ReturnRegData {
|
||||||
|
/// Return address.
|
||||||
|
pub arg: Value,
|
||||||
|
/// Dynamically sized array containing return values.
|
||||||
|
pub varargs: VariableArgs,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ReturnRegData {
|
||||||
|
/// Get references to the arguments.
|
||||||
|
pub fn arguments(&self) -> [&[Value]; 2] {
|
||||||
|
[ref_slice(&self.arg), &self.varargs]
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Get mutable references to the arguments.
|
||||||
|
pub fn arguments_mut(&mut self) -> [&mut [Value]; 2] {
|
||||||
|
[ref_slice_mut(&mut self.arg), &mut self.varargs]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Analyzing an instruction.
|
/// Analyzing an instruction.
|
||||||
///
|
///
|
||||||
/// Avoid large matches on instruction formats by using the methods defined here to examine
|
/// Avoid large matches on instruction formats by using the methods defined here to examine
|
||||||
|
|||||||
@@ -239,6 +239,13 @@ fn write_instruction(w: &mut Write,
|
|||||||
writeln!(w, " {}", data.varargs)
|
writeln!(w, " {}", data.varargs)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
ReturnReg { ref data, .. } => {
|
||||||
|
if data.varargs.is_empty() {
|
||||||
|
writeln!(w, "{}", data.arg)
|
||||||
|
} else {
|
||||||
|
writeln!(w, "{}, {}", data.arg, data.varargs)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -16,7 +16,7 @@ use cretonne::ir::immediates::{Imm64, Ieee32, Ieee64};
|
|||||||
use cretonne::ir::entities::AnyEntity;
|
use cretonne::ir::entities::AnyEntity;
|
||||||
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
|
use cretonne::ir::instructions::{InstructionFormat, InstructionData, VariableArgs,
|
||||||
TernaryOverflowData, JumpData, BranchData, CallData,
|
TernaryOverflowData, JumpData, BranchData, CallData,
|
||||||
IndirectCallData, ReturnData};
|
IndirectCallData, ReturnData, ReturnRegData};
|
||||||
use cretonne::isa;
|
use cretonne::isa;
|
||||||
use cretonne::settings;
|
use cretonne::settings;
|
||||||
use testfile::{TestFile, Details, Comment};
|
use testfile::{TestFile, Details, Comment};
|
||||||
@@ -197,6 +197,11 @@ impl Context {
|
|||||||
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));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
InstructionData::ReturnReg { ref mut data, .. } => {
|
||||||
|
try!(self.map.rewrite_value(&mut data.arg, loc));
|
||||||
|
try!(self.map.rewrite_values(&mut data.varargs, loc));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1321,6 +1326,19 @@ impl<'a> Parser<'a> {
|
|||||||
data: Box::new(ReturnData { varargs: args }),
|
data: Box::new(ReturnData { varargs: args }),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
InstructionFormat::ReturnReg => {
|
||||||
|
let raddr = try!(self.match_value("expected SSA value return addr operand"));
|
||||||
|
try!(self.match_token(Token::Comma, "expected ',' between operands"));
|
||||||
|
let args = try!(self.parse_value_list());
|
||||||
|
InstructionData::ReturnReg {
|
||||||
|
opcode: opcode,
|
||||||
|
ty: VOID,
|
||||||
|
data: Box::new(ReturnRegData {
|
||||||
|
arg: raddr,
|
||||||
|
varargs: args,
|
||||||
|
}),
|
||||||
|
}
|
||||||
|
}
|
||||||
InstructionFormat::BranchTable => {
|
InstructionFormat::BranchTable => {
|
||||||
let arg = try!(self.match_value("expected SSA value operand"));
|
let arg = try!(self.match_value("expected SSA value operand"));
|
||||||
try!(self.match_token(Token::Comma, "expected ',' between operands"));
|
try!(self.match_token(Token::Comma, "expected ',' between operands"));
|
||||||
|
|||||||
Reference in New Issue
Block a user