AArch64: Migrate calls and returns to ISLE. (#4788)
This commit is contained in:
@@ -994,6 +994,129 @@ macro_rules! isle_prelude_methods {
|
||||
fn preg_to_reg(&mut self, preg: PReg) -> Reg {
|
||||
preg.into()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn gen_move(&mut self, ty: Type, dst: WritableReg, src: Reg) -> MInst {
|
||||
MInst::gen_move(dst, src, ty)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Helpers specifically for machines that use ABICaller.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! isle_prelude_caller_methods {
|
||||
($abispec:ty, $abicaller:ty) => {
|
||||
fn gen_call(
|
||||
&mut self,
|
||||
sig_ref: SigRef,
|
||||
extname: ExternalName,
|
||||
dist: RelocDistance,
|
||||
args @ (inputs, off): ValueSlice,
|
||||
) -> InstOutput {
|
||||
let caller_conv = self.lower_ctx.abi().call_conv();
|
||||
let sig = &self.lower_ctx.dfg().signatures[sig_ref];
|
||||
let num_rets = sig.returns.len();
|
||||
let abi = ABISig::from_func_sig::<$abispec>(sig, self.flags).unwrap();
|
||||
let caller =
|
||||
<$abicaller>::from_func(sig, &extname, dist, caller_conv, self.flags).unwrap();
|
||||
|
||||
assert_eq!(
|
||||
inputs.len(&self.lower_ctx.dfg().value_lists) - off,
|
||||
sig.params.len()
|
||||
);
|
||||
|
||||
self.gen_call_common(abi, num_rets, caller, args)
|
||||
}
|
||||
|
||||
fn gen_call_indirect(
|
||||
&mut self,
|
||||
sig_ref: SigRef,
|
||||
val: Value,
|
||||
args @ (inputs, off): ValueSlice,
|
||||
) -> InstOutput {
|
||||
let caller_conv = self.lower_ctx.abi().call_conv();
|
||||
let ptr = self.put_in_reg(val);
|
||||
let sig = &self.lower_ctx.dfg().signatures[sig_ref];
|
||||
let num_rets = sig.returns.len();
|
||||
let abi = ABISig::from_func_sig::<$abispec>(sig, self.flags).unwrap();
|
||||
let caller =
|
||||
<$abicaller>::from_ptr(sig, ptr, Opcode::CallIndirect, caller_conv, self.flags)
|
||||
.unwrap();
|
||||
|
||||
assert_eq!(
|
||||
inputs.len(&self.lower_ctx.dfg().value_lists) - off,
|
||||
sig.params.len()
|
||||
);
|
||||
|
||||
self.gen_call_common(abi, num_rets, caller, args)
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// Helpers for the above ISLE prelude implementations. Meant to go
|
||||
/// inside the `impl` for the context type, not the trait impl.
|
||||
#[macro_export]
|
||||
#[doc(hidden)]
|
||||
macro_rules! isle_prelude_method_helpers {
|
||||
($abicaller:ty) => {
|
||||
fn gen_call_common(
|
||||
&mut self,
|
||||
abi: ABISig,
|
||||
num_rets: usize,
|
||||
mut caller: $abicaller,
|
||||
(inputs, off): ValueSlice,
|
||||
) -> InstOutput {
|
||||
caller.emit_stack_pre_adjust(self.lower_ctx);
|
||||
|
||||
assert_eq!(
|
||||
inputs.len(&self.lower_ctx.dfg().value_lists) - off,
|
||||
abi.num_args()
|
||||
);
|
||||
let mut arg_regs = vec![];
|
||||
for i in 0..abi.num_args() {
|
||||
let input = inputs
|
||||
.get(off + i, &self.lower_ctx.dfg().value_lists)
|
||||
.unwrap();
|
||||
arg_regs.push(self.lower_ctx.put_value_in_regs(input));
|
||||
}
|
||||
for (i, arg_regs) in arg_regs.iter().enumerate() {
|
||||
caller.emit_copy_regs_to_buffer(self.lower_ctx, i, *arg_regs);
|
||||
}
|
||||
for (i, arg_regs) in arg_regs.iter().enumerate() {
|
||||
caller.emit_copy_regs_to_arg(self.lower_ctx, i, *arg_regs);
|
||||
}
|
||||
caller.emit_call(self.lower_ctx);
|
||||
|
||||
let mut outputs = InstOutput::new();
|
||||
for i in 0..num_rets {
|
||||
let ret = abi.get_ret(i);
|
||||
let retval_regs = self.abi_arg_slot_regs(&ret).unwrap();
|
||||
caller.emit_copy_retval_to_regs(self.lower_ctx, i, retval_regs.clone());
|
||||
outputs.push(valueregs::non_writable_value_regs(retval_regs));
|
||||
}
|
||||
caller.emit_stack_post_adjust(self.lower_ctx);
|
||||
|
||||
outputs
|
||||
}
|
||||
|
||||
fn abi_arg_slot_regs(&mut self, arg: &ABIArg) -> Option<WritableValueRegs> {
|
||||
match arg {
|
||||
&ABIArg::Slots { ref slots, .. } => match slots.len() {
|
||||
1 => {
|
||||
let a = self.temp_writable_reg(slots[0].get_type());
|
||||
Some(WritableValueRegs::one(a))
|
||||
}
|
||||
2 => {
|
||||
let a = self.temp_writable_reg(slots[0].get_type());
|
||||
let b = self.temp_writable_reg(slots[1].get_type());
|
||||
Some(WritableValueRegs::two(a, b))
|
||||
}
|
||||
_ => panic!("Expected to see one or two slots only from {:?}", arg),
|
||||
},
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -11,8 +11,8 @@ use crate::inst_predicates::{has_lowering_side_effect, is_constant_64bit};
|
||||
use crate::ir::{
|
||||
types::{FFLAGS, IFLAGS},
|
||||
ArgumentPurpose, Block, Constant, ConstantData, DataFlowGraph, Function, GlobalValue,
|
||||
GlobalValueData, Immediate, Inst, InstructionData, MemFlags, Opcode, Signature, Type, Value,
|
||||
ValueDef, ValueLabelAssignments, ValueLabelStart,
|
||||
GlobalValueData, Immediate, Inst, InstructionData, MemFlags, Opcode, Type, Value, ValueDef,
|
||||
ValueLabelAssignments, ValueLabelStart,
|
||||
};
|
||||
use crate::ir::{ExternalName, RelSourceLoc};
|
||||
use crate::machinst::{
|
||||
@@ -1026,34 +1026,6 @@ impl<'func, I: VCodeInst> Lower<'func, I> {
|
||||
&self.f.dfg[ir_inst]
|
||||
}
|
||||
|
||||
/// Get the target for a call instruction, as an `ExternalName`. Returns a tuple
|
||||
/// providing this name and the "relocation distance", i.e., whether the backend
|
||||
/// can assume the target will be "nearby" (within some small offset) or an
|
||||
/// arbitrary address. (This comes from the `colocated` bit in the CLIF.)
|
||||
pub fn call_target<'b>(&'b self, ir_inst: Inst) -> Option<(&'b ExternalName, RelocDistance)> {
|
||||
match &self.f.dfg[ir_inst] {
|
||||
&InstructionData::Call { func_ref, .. }
|
||||
| &InstructionData::FuncAddr { func_ref, .. } => {
|
||||
let funcdata = &self.f.dfg.ext_funcs[func_ref];
|
||||
let dist = funcdata.reloc_distance();
|
||||
Some((&funcdata.name, dist))
|
||||
}
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the signature for a call or call-indirect instruction.
|
||||
pub fn call_sig<'b>(&'b self, ir_inst: Inst) -> Option<&'b Signature> {
|
||||
match &self.f.dfg[ir_inst] {
|
||||
&InstructionData::Call { func_ref, .. } => {
|
||||
let funcdata = &self.f.dfg.ext_funcs[func_ref];
|
||||
Some(&self.f.dfg.signatures[funcdata.signature])
|
||||
}
|
||||
&InstructionData::CallIndirect { sig_ref, .. } => Some(&self.f.dfg.signatures[sig_ref]),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
||||
/// Get the symbol name, relocation distance estimate, and offset for a
|
||||
/// symbol_value instruction.
|
||||
pub fn symbol_value<'b>(
|
||||
|
||||
Reference in New Issue
Block a user