diff --git a/cranelift/codegen/src/isa/s390x/lower/isle.rs b/cranelift/codegen/src/isa/s390x/lower/isle.rs index 44ec3994bf..1f6f5ce9ab 100644 --- a/cranelift/codegen/src/isa/s390x/lower/isle.rs +++ b/cranelift/codegen/src/isa/s390x/lower/isle.rs @@ -129,7 +129,7 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> for i in 0..self.lower_ctx.sigs()[*abi].num_rets() { if let &ABIArg::Slots { ref slots, purpose, .. - } = &self.lower_ctx.sigs()[*abi].get_ret(self.lower_ctx.sigs(), i) + } = &self.lower_ctx.sigs().get_ret(*abi, i) { if purpose == ArgumentPurpose::StructReturn { continue; @@ -192,8 +192,10 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> defs: &CallRetList, opcode: &Opcode, ) -> BoxCallInfo { - let clobbers = - self.lower_ctx.sigs()[*abi].call_clobbers::(self.lower_ctx.sigs()); + let clobbers = self + .lower_ctx + .sigs() + .call_clobbers::(*abi); Box::new(CallInfo { dest: name.clone(), uses: uses.clone(), @@ -214,8 +216,10 @@ impl generated_code::Context for IsleContext<'_, '_, MInst, Flags, IsaFlags, 6> defs: &CallRetList, opcode: &Opcode, ) -> BoxCallIndInfo { - let clobbers = - self.lower_ctx.sigs()[*abi].call_clobbers::(self.lower_ctx.sigs()); + let clobbers = self + .lower_ctx + .sigs() + .call_clobbers::(*abi); Box::new(CallIndInfo { rn: target, uses: uses.clone(), diff --git a/cranelift/codegen/src/machinst/abi.rs b/cranelift/codegen/src/machinst/abi.rs index f83b59ea8b..84b4a78642 100644 --- a/cranelift/codegen/src/machinst/abi.rs +++ b/cranelift/codegen/src/machinst/abi.rs @@ -643,114 +643,6 @@ pub struct SigData { } impl SigData { - pub fn from_func_sig( - sigs: &mut SigSet, - sig: &ir::Signature, - flags: &settings::Flags, - ) -> CodegenResult { - let sret = missing_struct_return(sig); - let returns = sret.as_ref().into_iter().chain(&sig.returns); - - // Compute args and retvals from signature. Handle retvals first, - // because we may need to add a return-area arg to the args. - let rets_start = u32::try_from(sigs.abi_args.len()).unwrap(); - let (sized_stack_ret_space, _) = M::compute_arg_locs( - sig.call_conv, - flags, - returns, - ArgsOrRets::Rets, - /* extra ret-area ptr = */ false, - ArgsAccumulator::new(&mut sigs.abi_args), - )?; - let rets_end = u32::try_from(sigs.abi_args.len()).unwrap(); - - let need_stack_return_area = sized_stack_ret_space > 0; - let args_start = u32::try_from(sigs.abi_args.len()).unwrap(); - let (sized_stack_arg_space, stack_ret_arg) = M::compute_arg_locs( - sig.call_conv, - flags, - &sig.params, - ArgsOrRets::Args, - need_stack_return_area, - ArgsAccumulator::new(&mut sigs.abi_args), - )?; - let args_end = u32::try_from(sigs.abi_args.len()).unwrap(); - - let args_length = u16::try_from(args_end - args_start).unwrap(); - let rets_length = u16::try_from(rets_end - rets_start).unwrap(); - - trace!( - "ABISig: sig {:?} => args start = {} args len = {} rets start = {} rets len = {} - arg stack = {} ret stack = {} stack_ret_arg = {:?}", - sig, - args_start, - args_length, - rets_start, - rets_length, - sized_stack_arg_space, - sized_stack_ret_space, - stack_ret_arg, - ); - - let stack_ret_arg = stack_ret_arg.map(|s| u16::try_from(s).unwrap()); - Ok(SigData { - args_start, - args_length, - rets_start, - rets_length, - sized_stack_arg_space, - sized_stack_ret_space, - stack_ret_arg, - call_conv: sig.call_conv, - }) - } - - /// Get this signature's ABI arguments. - pub fn args<'a>(&self, sigs: &'a SigSet) -> &'a [ABIArg] { - let start = usize::try_from(self.args_start).unwrap(); - let end = usize::try_from(self.args_start + u32::from(self.args_length)).unwrap(); - &sigs.abi_args[start..end] - } - - /// Get this signature's ABI returns. - pub fn rets<'a>(&self, sigs: &'a SigSet) -> &'a [ABIArg] { - let start = usize::try_from(self.rets_start).unwrap(); - let end = usize::try_from(self.rets_start + u32::from(self.rets_length)).unwrap(); - &sigs.abi_args[start..end] - } - - /// Return all clobbers for the callsite. - pub fn call_clobbers(&self, sigs: &SigSet) -> PRegSet { - // Get clobbers: all caller-saves. These may include return value - // regs, which we will remove from the clobber set below. - let mut clobbers = M::get_regs_clobbered_by_call(self.call_conv); - - // Remove retval regs from clobbers. Skip StructRets: these - // are not, semantically, returns at the CLIF level, so we - // treat such a value as a clobber instead. - for ret in self.rets(sigs) { - if let &ABIArg::Slots { - ref slots, purpose, .. - } = ret - { - if purpose == ir::ArgumentPurpose::StructReturn { - continue; - } - for slot in slots { - match slot { - &ABIArgSlot::Reg { reg, .. } => { - log::trace!("call_clobbers: retval reg {:?}", reg); - clobbers.remove(PReg::from(reg)); - } - _ => {} - } - } - } - } - - clobbers - } - /// Get the number of arguments expected. pub fn num_args(&self) -> usize { let num = if self.stack_ret_arg.is_some() { @@ -762,11 +654,6 @@ impl SigData { usize::from(num) } - /// Get information specifying how to pass one argument. - pub fn get_arg(&self, sigs: &SigSet, idx: usize) -> ABIArg { - self.args(sigs)[idx].clone() - } - /// Get total stack space required for arguments. pub fn sized_stack_arg_space(&self) -> i64 { self.sized_stack_arg_space @@ -777,23 +664,11 @@ impl SigData { usize::from(self.rets_length) } - /// Get information specifying how to pass one return value. - pub fn get_ret(&self, sigs: &SigSet, idx: usize) -> ABIArg { - self.rets(sigs)[idx].clone() - } - /// Get total stack space required for return values. pub fn sized_stack_ret_space(&self) -> i64 { self.sized_stack_ret_space } - /// Get information specifying how to pass the implicit pointer - /// to the return-value area on the stack, if required. - pub fn get_ret_arg(&self, sigs: &SigSet) -> Option { - let ret_arg = usize::from(self.stack_ret_arg?); - Some(self.args(sigs)[ret_arg].clone()) - } - /// Get calling convention used. pub fn call_conv(&self) -> isa::CallConv { self.call_conv @@ -878,7 +753,7 @@ impl SigSet { // `ir::Signature`. debug_assert!(!self.have_abi_sig_for_signature(&signature)); - let sig_data = SigData::from_func_sig::(self, &signature, flags)?; + let sig_data = self.from_func_sig::(&signature, flags)?; let sig = self.sigs.push(sig_data); self.ir_signature_to_abi_sig.insert(signature, sig); Ok(sig) @@ -897,7 +772,7 @@ impl SigSet { return Ok(sig); } let signature = &dfg.signatures[sig_ref]; - let sig_data = SigData::from_func_sig::(self, signature, flags)?; + let sig_data = self.from_func_sig::(signature, flags)?; let sig = self.sigs.push(sig_data); self.ir_sig_ref_to_abi_sig[sig_ref] = Some(sig); Ok(sig) @@ -920,6 +795,138 @@ impl SigSet { .copied() .expect("must call `make_abi_sig_from_ir_signature` before `get_abi_sig_for_signature`") } + + pub fn from_func_sig( + &mut self, + sig: &ir::Signature, + flags: &settings::Flags, + ) -> CodegenResult { + let sret = missing_struct_return(sig); + let returns = sret.as_ref().into_iter().chain(&sig.returns); + + // Compute args and retvals from signature. Handle retvals first, + // because we may need to add a return-area arg to the args. + let rets_start = u32::try_from(self.abi_args.len()).unwrap(); + let (sized_stack_ret_space, _) = M::compute_arg_locs( + sig.call_conv, + flags, + returns, + ArgsOrRets::Rets, + /* extra ret-area ptr = */ false, + ArgsAccumulator::new(&mut self.abi_args), + )?; + let rets_end = u32::try_from(self.abi_args.len()).unwrap(); + + let need_stack_return_area = sized_stack_ret_space > 0; + let args_start = u32::try_from(self.abi_args.len()).unwrap(); + let (sized_stack_arg_space, stack_ret_arg) = M::compute_arg_locs( + sig.call_conv, + flags, + &sig.params, + ArgsOrRets::Args, + need_stack_return_area, + ArgsAccumulator::new(&mut self.abi_args), + )?; + let args_end = u32::try_from(self.abi_args.len()).unwrap(); + + let args_length = u16::try_from(args_end - args_start).unwrap(); + let rets_length = u16::try_from(rets_end - rets_start).unwrap(); + + trace!( + "ABISig: sig {:?} => args start = {} args len = {} rets start = {} rets len = {} + arg stack = {} ret stack = {} stack_ret_arg = {:?}", + sig, + args_start, + args_length, + rets_start, + rets_length, + sized_stack_arg_space, + sized_stack_ret_space, + need_stack_return_area, + ); + + let stack_ret_arg = stack_ret_arg.map(|s| u16::try_from(s).unwrap()); + Ok(SigData { + args_start, + args_length, + rets_start, + rets_length, + sized_stack_arg_space, + sized_stack_ret_space, + stack_ret_arg, + call_conv: sig.call_conv, + }) + } + + /// Get this signature's ABI arguments. + pub fn args(&self, sig: Sig) -> &[ABIArg] { + let sig_data = &self.sigs[sig]; + let start = usize::try_from(sig_data.args_start).unwrap(); + let end = usize::try_from(sig_data.args_start + u32::from(sig_data.args_length)).unwrap(); + &self.abi_args[start..end] + } + + /// Get information specifying how to pass the implicit pointer + /// to the return-value area on the stack, if required. + pub fn get_ret_arg(&self, sig: Sig) -> Option { + let sig_data = &self.sigs[sig]; + if let Some(i) = sig_data.stack_ret_arg { + Some(self.args(sig)[usize::from(i)].clone()) + } else { + None + } + } + + /// Get information specifying how to pass one argument. + pub fn get_arg(&self, sig: Sig, idx: usize) -> ABIArg { + self.args(sig)[idx].clone() + } + + /// Get this signature's ABI returns. + pub fn rets(&self, sig: Sig) -> &[ABIArg] { + let sig_data = &self.sigs[sig]; + let start = usize::try_from(sig_data.rets_start).unwrap(); + let end = usize::try_from(sig_data.rets_start + u32::from(sig_data.rets_length)).unwrap(); + &self.abi_args[start..end] + } + + /// Get information specifying how to pass one return value. + pub fn get_ret(&self, sig: Sig, idx: usize) -> ABIArg { + self.rets(sig)[idx].clone() + } + + /// Return all clobbers for the callsite. + pub fn call_clobbers(&self, sig: Sig) -> PRegSet { + let sig_data = &self.sigs[sig]; + // Get clobbers: all caller-saves. These may include return value + // regs, which we will remove from the clobber set below. + let mut clobbers = M::get_regs_clobbered_by_call(sig_data.call_conv); + + // Remove retval regs from clobbers. Skip StructRets: these + // are not, semantically, returns at the CLIF level, so we + // treat such a value as a clobber instead. + for ret in self.rets(sig) { + if let &ABIArg::Slots { + ref slots, purpose, .. + } = ret + { + if purpose == ir::ArgumentPurpose::StructReturn { + continue; + } + for slot in slots { + match slot { + &ABIArgSlot::Reg { reg, .. } => { + log::trace!("call_clobbers: retval reg {:?}", reg); + clobbers.remove(PReg::from(reg)); + } + _ => {} + } + } + } + } + + clobbers + } } // NB: we do _not_ implement `IndexMut` because these signatures are @@ -999,11 +1006,11 @@ pub struct Callee { fn get_special_purpose_param_register( f: &ir::Function, sigs: &SigSet, - abi: &SigData, + sig: &Sig, purpose: ir::ArgumentPurpose, ) -> Option { let idx = f.signature.special_param_index(purpose)?; - match &abi.args(sigs)[idx] { + match &sigs.args(*sig)[idx] { &ABIArg::Slots { ref slots, .. } => match &slots[0] { &ABIArgSlot::Reg { reg, .. } => Some(reg.into()), _ => None, @@ -1080,17 +1087,13 @@ impl Callee { // stack limit. This can either be specified as a special-purpose // argument or as a global value which often calculates the stack limit // from the arguments. - let stack_limit = get_special_purpose_param_register( - f, - sigs, - &sigs[sig], - ir::ArgumentPurpose::StackLimit, - ) - .map(|reg| (reg, smallvec![])) - .or_else(|| { - f.stack_limit - .map(|gv| gen_stack_limit::(f, sigs, &sigs[sig], gv)) - }); + let stack_limit = + get_special_purpose_param_register(f, sigs, &sig, ir::ArgumentPurpose::StackLimit) + .map(|reg| (reg, smallvec![])) + .or_else(|| { + f.stack_limit + .map(|gv| gen_stack_limit::(f, sigs, &sig, gv)) + }); // Determine whether a probestack call is required for large enough // frames (and the minimum frame size if so). @@ -1210,25 +1213,25 @@ impl Callee { fn gen_stack_limit( f: &ir::Function, sigs: &SigSet, - abi: &SigData, + sig: &Sig, gv: ir::GlobalValue, ) -> (Reg, SmallInstVec) { let mut insts = smallvec![]; - let reg = generate_gv::(f, sigs, abi, gv, &mut insts); + let reg = generate_gv::(f, sigs, sig, gv, &mut insts); return (reg, insts); } fn generate_gv( f: &ir::Function, sigs: &SigSet, - abi: &SigData, + sig: &Sig, gv: ir::GlobalValue, insts: &mut SmallInstVec, ) -> Reg { match f.global_values[gv] { // Return the direct register the vmcontext is in ir::GlobalValueData::VMContext => { - get_special_purpose_param_register(f, sigs, abi, ir::ArgumentPurpose::VMContext) + get_special_purpose_param_register(f, sigs, sig, ir::ArgumentPurpose::VMContext) .expect("no vmcontext parameter found") } // Load our base value into a register, then load from that register @@ -1239,7 +1242,7 @@ fn generate_gv( global_type: _, readonly: _, } => { - let base = generate_gv::(f, sigs, abi, base, insts); + let base = generate_gv::(f, sigs, sig, base, insts); let into_reg = Writable::from_reg(M::get_stacklimit_reg()); insts.push(M::gen_load_base_offset( into_reg, @@ -1321,7 +1324,7 @@ impl Callee { /// They will be provided to `init()` as the `temps` arg if so. pub fn temps_needed(&self, sigs: &SigSet) -> Vec { let mut temp_tys = vec![]; - for arg in sigs[self.sig].args(sigs) { + for arg in sigs.args(self.sig) { match arg { &ABIArg::ImplicitPtrArg { pointer, .. } => match &pointer { &ABIArgSlot::Reg { .. } => {} @@ -1343,7 +1346,7 @@ impl Callee { /// once the lowering context exists. pub fn init(&mut self, sigs: &SigSet, temps: Vec>) { let mut temps_iter = temps.into_iter(); - for arg in sigs[self.sig].args(sigs) { + for arg in sigs.args(self.sig) { let temp = match arg { &ABIArg::ImplicitPtrArg { pointer, .. } => match &pointer { &ABIArgSlot::Reg { .. } => None, @@ -1441,7 +1444,7 @@ impl Callee { } }; - match &sigs[self.sig].args(sigs)[idx] { + match &sigs.args(self.sig)[idx] { &ABIArg::Slots { ref slots, .. } => { assert_eq!(into_regs.len(), slots.len()); for (slot, into_reg) in slots.iter().zip(into_regs.regs().iter()) { @@ -1518,7 +1521,7 @@ impl Callee { let mut reg_pairs = smallvec![]; let mut ret = smallvec![]; let word_bits = M::word_bits() as u8; - match &sigs[self.sig].rets(sigs)[idx] { + match &sigs.rets(self.sig)[idx] { &ABIArg::Slots { ref slots, .. } => { assert_eq!(from_regs.len(), slots.len()); for (slot, &from_reg) in slots.iter().zip(from_regs.regs().iter()) { @@ -2015,7 +2018,7 @@ impl Caller { flags: settings::Flags, ) -> CodegenResult> { let sig = sigs.abi_sig_for_sig_ref(sig_ref); - let clobbers = sigs[sig].call_clobbers::(sigs); + let clobbers = sigs.call_clobbers::(sig); Ok(Caller { sig, uses: smallvec![], @@ -2040,7 +2043,7 @@ impl Caller { flags: settings::Flags, ) -> CodegenResult> { let sig = sigs.abi_sig_for_signature(sig); - let clobbers = sigs[sig].call_clobbers::(sigs); + let clobbers = sigs.call_clobbers::(sig); Ok(Caller { sig, uses: smallvec![], @@ -2065,7 +2068,7 @@ impl Caller { flags: settings::Flags, ) -> CodegenResult> { let sig = sigs.abi_sig_for_sig_ref(sig_ref); - let clobbers = sigs[sig].call_clobbers::(sigs); + let clobbers = sigs.call_clobbers::(sig); Ok(Caller { sig, uses: smallvec![], @@ -2094,9 +2097,8 @@ fn adjust_stack_and_nominal_sp(ctx: &mut Lower, off: i3 impl Caller { /// Get the number of arguments expected. pub fn num_args(&self, sigs: &SigSet) -> usize { - let data = &sigs[self.sig]; - let len = data.args(sigs).len(); - if data.stack_ret_arg.is_some() { + let len = sigs.args(self.sig).len(); + if sigs[self.sig].stack_ret_arg.is_some() { len - 1 } else { len @@ -2128,7 +2130,7 @@ impl Caller { idx: usize, from_regs: ValueRegs, ) { - match &ctx.sigs()[self.sig].args(ctx.sigs())[idx] { + match &ctx.sigs().args(self.sig)[idx] { &ABIArg::Slots { .. } => {} &ABIArg::StructArg { offset, size, .. } => { let src_ptr = from_regs.only_reg().unwrap(); @@ -2180,7 +2182,7 @@ impl Caller { // How many temps do we need for extends? Allocate them ahead // of time, since we can't do it while we're iterating over // the sig and immutably borrowing `ctx`. - let needed_tmps = match &ctx.sigs()[self.sig].args(ctx.sigs())[idx] { + let needed_tmps = match &ctx.sigs().args(self.sig)[idx] { &ABIArg::Slots { ref slots, .. } => slots .iter() .map(|slot| match slot { @@ -2205,7 +2207,7 @@ impl Caller { .map(|_| ctx.alloc_tmp(M::word_type()).only_reg().unwrap()) .collect(); - match &ctx.sigs()[self.sig].args(ctx.sigs())[idx] { + match &ctx.sigs().args(self.sig)[idx] { &ABIArg::Slots { ref slots, .. } => { assert_eq!(from_regs.len(), slots.len()); for (slot, from_reg) in slots.iter().zip(from_regs.regs().iter()) { @@ -2307,7 +2309,7 @@ impl Caller { into_regs: ValueRegs>, ) -> SmallInstVec { let mut insts = smallvec![]; - match &ctx.sigs()[self.sig].rets(ctx.sigs())[idx] { + match &ctx.sigs().rets(self.sig)[idx] { &ABIArg::Slots { ref slots, .. } => { assert_eq!(into_regs.len(), slots.len()); for (slot, into_reg) in slots.iter().zip(into_regs.regs().iter()) { diff --git a/cranelift/codegen/src/machinst/isle.rs b/cranelift/codegen/src/machinst/isle.rs index 441a37fa8d..a7a22ca1a5 100644 --- a/cranelift/codegen/src/machinst/isle.rs +++ b/cranelift/codegen/src/machinst/isle.rs @@ -436,7 +436,7 @@ macro_rules! isle_lower_prelude_methods { } fn abi_get_arg(&mut self, abi: &Sig, idx: usize) -> ABIArg { - self.lower_ctx.sigs()[*abi].get_arg(self.lower_ctx.sigs(), idx) + self.lower_ctx.sigs().get_arg(*abi, idx) } fn abi_num_rets(&mut self, abi: &Sig) -> usize { @@ -444,15 +444,15 @@ macro_rules! isle_lower_prelude_methods { } fn abi_get_ret(&mut self, abi: &Sig, idx: usize) -> ABIArg { - self.lower_ctx.sigs()[*abi].get_ret(self.lower_ctx.sigs(), idx) + self.lower_ctx.sigs().get_ret(*abi, idx) } fn abi_ret_arg(&mut self, abi: &Sig) -> Option { - self.lower_ctx.sigs()[*abi].get_ret_arg(self.lower_ctx.sigs()) + self.lower_ctx.sigs().get_ret_arg(*abi) } fn abi_no_ret_arg(&mut self, abi: &Sig) -> Option<()> { - if let Some(_) = self.lower_ctx.sigs()[*abi].get_ret_arg(self.lower_ctx.sigs()) { + if let Some(_) = self.lower_ctx.sigs().get_ret_arg(*abi) { None } else { Some(()) @@ -716,8 +716,7 @@ macro_rules! isle_prelude_method_helpers { // Borrow `sigdata` again so we don't hold a `self` // borrow across the `&mut self` arg to // `abi_arg_slot_regs()` below. - let sigdata = &self.lower_ctx.sigs()[abi]; - let ret = sigdata.get_ret(self.lower_ctx.sigs(), i); + let ret = self.lower_ctx.sigs().get_ret(abi, i); let retval_regs = self.abi_arg_slot_regs(&ret).unwrap(); retval_insts.extend( caller