Set up return values `outputs` for a call with signature `sig`. This does not emit (or return) any instructions, but returns a `CallRetList` representing the return value constraints. This needs to be added to the actual call instruction. If `try_call_payloads` is non-zero, it is expected to hold exception payload registers for try_call instructions. These will be added as needed to the `CallRe
(
&self,
sigs: &SigSet,
sig: Sig,
outputs: &[ValueRegs<Reg>],
try_call_payloads: Option<&[Writable<Reg>]>,
vregs: &mut VRegAllocator<M::I>,
)
| 1960 | /// exception payload registers for try_call instructions. These |
| 1961 | /// will be added as needed to the `CallRetList` as well. |
| 1962 | pub fn gen_call_rets( |
| 1963 | &self, |
| 1964 | sigs: &SigSet, |
| 1965 | sig: Sig, |
| 1966 | outputs: &[ValueRegs<Reg>], |
| 1967 | try_call_payloads: Option<&[Writable<Reg>]>, |
| 1968 | vregs: &mut VRegAllocator<M::I>, |
| 1969 | ) -> CallRetList { |
| 1970 | let callee_conv = sigs[sig].call_conv; |
| 1971 | let stack_arg_space = sigs[sig].sized_stack_arg_space; |
| 1972 | |
| 1973 | let word_ty = M::word_type(); |
| 1974 | let word_bits = M::word_bits() as usize; |
| 1975 | |
| 1976 | let mut defs: CallRetList = smallvec![]; |
| 1977 | let mut outputs = outputs.into_iter(); |
| 1978 | let num_rets = sigs.num_rets(sig); |
| 1979 | for idx in 0..num_rets { |
| 1980 | let ret = sigs.rets(sig)[idx].clone(); |
| 1981 | match ret { |
| 1982 | ABIArg::Slots { |
| 1983 | ref slots, purpose, .. |
| 1984 | } => { |
| 1985 | // We do not use the returned copy of the return buffer pointer, |
| 1986 | // so skip any StructReturn returns that may be present. |
| 1987 | if purpose == ArgumentPurpose::StructReturn { |
| 1988 | continue; |
| 1989 | } |
| 1990 | let retval_regs = outputs.next().unwrap(); |
| 1991 | assert_eq!(retval_regs.len(), slots.len()); |
| 1992 | for (slot, retval_reg) in slots.iter().zip(retval_regs.regs().iter()) { |
| 1993 | // We do not perform any extension because we're copying out, not in, |
| 1994 | // and we ignore high bits in our own registers by convention. However, |
| 1995 | // we still need to use the proper extended type to access stack slots |
| 1996 | // (this is critical on big-endian systems). |
| 1997 | let (ty, extension) = match *slot { |
| 1998 | ABIArgSlot::Reg { ty, extension, .. } => (ty, extension), |
| 1999 | ABIArgSlot::Stack { ty, extension, .. } => (ty, extension), |
| 2000 | }; |
| 2001 | let ext = M::get_ext_mode(callee_conv, extension); |
| 2002 | let ty = if ext != ir::ArgumentExtension::None && ty_bits(ty) < word_bits { |
| 2003 | word_ty |
| 2004 | } else { |
| 2005 | ty |
| 2006 | }; |
| 2007 | |
| 2008 | match slot { |
| 2009 | &ABIArgSlot::Reg { reg, .. } => { |
| 2010 | defs.push(CallRetPair { |
| 2011 | vreg: Writable::from_reg(*retval_reg), |
| 2012 | location: RetLocation::Reg(reg.into(), ty), |
| 2013 | }); |
| 2014 | } |
| 2015 | &ABIArgSlot::Stack { offset, .. } => { |
| 2016 | let amode = |
| 2017 | StackAMode::OutgoingArg(offset + i64::from(stack_arg_space)); |
| 2018 | defs.push(CallRetPair { |
| 2019 | vreg: Writable::from_reg(*retval_reg), |
no test coverage detected