|
|
@ -127,9 +127,24 @@ use std::mem; |
|
|
|
#[derive(Clone, Copy, Debug)] |
|
|
|
pub enum ABIArg { |
|
|
|
/// In a real register.
|
|
|
|
Reg(RealReg, ir::Type, ir::ArgumentExtension), |
|
|
|
Reg( |
|
|
|
RealReg, |
|
|
|
ir::Type, |
|
|
|
ir::ArgumentExtension, |
|
|
|
ir::ArgumentPurpose, |
|
|
|
), |
|
|
|
/// Arguments only: on stack, at given offset from SP at entry.
|
|
|
|
Stack(i64, ir::Type, ir::ArgumentExtension), |
|
|
|
Stack(i64, ir::Type, ir::ArgumentExtension, ir::ArgumentPurpose), |
|
|
|
} |
|
|
|
|
|
|
|
impl ABIArg { |
|
|
|
/// Get the purpose of this arg.
|
|
|
|
fn get_purpose(self) -> ir::ArgumentPurpose { |
|
|
|
match self { |
|
|
|
ABIArg::Reg(_, _, _, purpose) => purpose, |
|
|
|
ABIArg::Stack(_, _, _, purpose) => purpose, |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
/// Are we computing information about arguments or return values? Much of the
|
|
|
@ -308,6 +323,7 @@ pub trait ABIMachineSpec { |
|
|
|
/// nominal SP offset; caller will do that.
|
|
|
|
fn gen_clobber_save( |
|
|
|
call_conv: isa::CallConv, |
|
|
|
flags: &settings::Flags, |
|
|
|
clobbers: &Set<Writable<RealReg>>, |
|
|
|
) -> (u64, SmallVec<[Self::I; 16]>); |
|
|
|
|
|
|
@ -317,6 +333,7 @@ pub trait ABIMachineSpec { |
|
|
|
/// clobber-save sequence finished.
|
|
|
|
fn gen_clobber_restore( |
|
|
|
call_conv: isa::CallConv, |
|
|
|
flags: &settings::Flags, |
|
|
|
clobbers: &Set<Writable<RealReg>>, |
|
|
|
) -> SmallVec<[Self::I; 16]>; |
|
|
|
|
|
|
@ -700,8 +717,8 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> { |
|
|
|
match &self.sig.args[idx] { |
|
|
|
// Extension mode doesn't matter (we're copying out, not in; we
|
|
|
|
// ignore high bits by convention).
|
|
|
|
&ABIArg::Reg(r, ty, _) => M::gen_move(into_reg, r.to_reg(), ty), |
|
|
|
&ABIArg::Stack(off, ty, _) => M::gen_load_stack( |
|
|
|
&ABIArg::Reg(r, ty, ..) => M::gen_move(into_reg, r.to_reg(), ty), |
|
|
|
&ABIArg::Stack(off, ty, ..) => M::gen_load_stack( |
|
|
|
StackAMode::FPOffset(M::fp_to_arg_offset(self.call_conv, &self.flags) + off, ty), |
|
|
|
into_reg, |
|
|
|
ty, |
|
|
@ -709,11 +726,21 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> { |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn arg_is_needed_in_body(&self, idx: usize) -> bool { |
|
|
|
match self.sig.args[idx].get_purpose() { |
|
|
|
// Special Baldrdash-specific pseudo-args that are present only to
|
|
|
|
// fill stack slots. Won't ever be used as ordinary values in the
|
|
|
|
// body.
|
|
|
|
ir::ArgumentPurpose::CalleeTLS | ir::ArgumentPurpose::CallerTLS => false, |
|
|
|
_ => true, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
fn gen_copy_reg_to_retval(&self, idx: usize, from_reg: Writable<Reg>) -> Vec<Self::I> { |
|
|
|
let mut ret = Vec::new(); |
|
|
|
let word_bits = M::word_bits() as u8; |
|
|
|
match &self.sig.rets[idx] { |
|
|
|
&ABIArg::Reg(r, ty, ext) => { |
|
|
|
&ABIArg::Reg(r, ty, ext, ..) => { |
|
|
|
let from_bits = ty_bits(ty) as u8; |
|
|
|
let dest_reg = Writable::from_reg(r.to_reg()); |
|
|
|
match (ext, from_bits) { |
|
|
@ -732,7 +759,7 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> { |
|
|
|
_ => ret.push(M::gen_move(dest_reg, from_reg.to_reg(), ty)), |
|
|
|
}; |
|
|
|
} |
|
|
|
&ABIArg::Stack(off, mut ty, ext) => { |
|
|
|
&ABIArg::Stack(off, mut ty, ext, ..) => { |
|
|
|
let from_bits = ty_bits(ty) as u8; |
|
|
|
// A machine ABI implementation should ensure that stack frames
|
|
|
|
// have "reasonable" size. All current ABIs for machinst
|
|
|
@ -937,7 +964,8 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> { |
|
|
|
} |
|
|
|
|
|
|
|
// Save clobbered registers.
|
|
|
|
let (clobber_size, clobber_insts) = M::gen_clobber_save(self.call_conv, &self.clobbered); |
|
|
|
let (clobber_size, clobber_insts) = |
|
|
|
M::gen_clobber_save(self.call_conv, &self.flags, &self.clobbered); |
|
|
|
insts.extend(clobber_insts); |
|
|
|
|
|
|
|
if clobber_size > 0 { |
|
|
@ -952,7 +980,11 @@ impl<M: ABIMachineSpec> ABICallee for ABICalleeImpl<M> { |
|
|
|
let mut insts = vec![]; |
|
|
|
|
|
|
|
// Restore clobbered registers.
|
|
|
|
insts.extend(M::gen_clobber_restore(self.call_conv, &self.clobbered)); |
|
|
|
insts.extend(M::gen_clobber_restore( |
|
|
|
self.call_conv, |
|
|
|
&self.flags, |
|
|
|
&self.clobbered, |
|
|
|
)); |
|
|
|
|
|
|
|
// N.B.: we do *not* emit a nominal SP adjustment here, because (i) there will be no
|
|
|
|
// references to nominal SP offsets before the return below, and (ii) the instruction
|
|
|
@ -1135,7 +1167,7 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> { |
|
|
|
let word_rc = M::word_reg_class(); |
|
|
|
let word_bits = M::word_bits() as usize; |
|
|
|
match &self.sig.args[idx] { |
|
|
|
&ABIArg::Reg(reg, ty, ext) |
|
|
|
&ABIArg::Reg(reg, ty, ext, _) |
|
|
|
if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits => |
|
|
|
{ |
|
|
|
assert_eq!(word_rc, reg.get_class()); |
|
|
@ -1152,10 +1184,10 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> { |
|
|
|
word_bits as u8, |
|
|
|
)); |
|
|
|
} |
|
|
|
&ABIArg::Reg(reg, ty, _) => { |
|
|
|
&ABIArg::Reg(reg, ty, _, _) => { |
|
|
|
ctx.emit(M::gen_move(Writable::from_reg(reg.to_reg()), from_reg, ty)); |
|
|
|
} |
|
|
|
&ABIArg::Stack(off, mut ty, ext) => { |
|
|
|
&ABIArg::Stack(off, mut ty, ext, _) => { |
|
|
|
if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits { |
|
|
|
assert_eq!(word_rc, from_reg.get_class()); |
|
|
|
let signed = match ext { |
|
|
@ -1194,8 +1226,8 @@ impl<M: ABIMachineSpec> ABICaller for ABICallerImpl<M> { |
|
|
|
match &self.sig.rets[idx] { |
|
|
|
// Extension mode doesn't matter because we're copying out, not in,
|
|
|
|
// and we ignore high bits in our own registers by convention.
|
|
|
|
&ABIArg::Reg(reg, ty, _) => ctx.emit(M::gen_move(into_reg, reg.to_reg(), ty)), |
|
|
|
&ABIArg::Stack(off, ty, _) => { |
|
|
|
&ABIArg::Reg(reg, ty, _, _) => ctx.emit(M::gen_move(into_reg, reg.to_reg(), ty)), |
|
|
|
&ABIArg::Stack(off, ty, _, _) => { |
|
|
|
let ret_area_base = self.sig.stack_arg_space; |
|
|
|
ctx.emit(M::gen_load_stack( |
|
|
|
StackAMode::SPOffset(off + ret_area_base, ty), |
|
|
|