Path: blob/main/cranelift/codegen/src/isa/pulley_shared/abi.rs
1693 views
//! Implementation of a standard Pulley ABI.12use super::{PulleyFlags, PulleyTargetKind, inst::*};3use crate::isa::pulley_shared::PointerWidth;4use crate::{5CodegenResult,6ir::{self, MemFlags, Signature, types::*},7isa,8machinst::*,9settings,10};11use alloc::vec::Vec;12use core::marker::PhantomData;13use cranelift_bitset::ScalarBitSet;14use regalloc2::{MachineEnv, PReg, PRegSet};15use smallvec::{SmallVec, smallvec};16use std::borrow::ToOwned;17use std::sync::OnceLock;1819/// Support for the Pulley ABI from the callee side (within a function body).20pub(crate) type PulleyCallee<P> = Callee<PulleyMachineDeps<P>>;2122/// Pulley-specific ABI behavior. This struct just serves as an implementation23/// point for the trait; it is never actually instantiated.24pub struct PulleyMachineDeps<P>25where26P: PulleyTargetKind,27{28_phantom: PhantomData<P>,29}3031impl<P> ABIMachineSpec for PulleyMachineDeps<P>32where33P: PulleyTargetKind,34{35type I = InstAndKind<P>;36type F = PulleyFlags;3738/// This is the limit for the size of argument and return-value areas on the39/// stack. We place a reasonable limit here to avoid integer overflow issues40/// with 32-bit arithmetic: for now, 128 MB.41const STACK_ARG_RET_SIZE_LIMIT: u32 = 128 * 1024 * 1024;4243fn word_bits() -> u32 {44P::pointer_width().bits().into()45}4647/// Return required stack alignment in bytes.48fn stack_align(_call_conv: isa::CallConv) -> u32 {491650}5152fn compute_arg_locs(53call_conv: isa::CallConv,54flags: &settings::Flags,55params: &[ir::AbiParam],56args_or_rets: ArgsOrRets,57add_ret_area_ptr: bool,58mut args: ArgsAccumulator,59) -> CodegenResult<(u32, Option<usize>)> {60// NB: make sure this method stays in sync with61// `cranelift_pulley::interp::Vm::call`.62//63// In general we use the first half of all register banks as argument64// passing registers because, well, why not for now. Currently the only65// exception is x15 which is reserved as a single caller-saved register66// not used for arguments. This is used in `ReturnCallIndirect` to hold67// the location of where we're jumping to.6869let x_end = 14;70let f_end = 15;71let v_end = 15;7273let mut next_x_reg = 0;74let mut next_f_reg = 0;75let mut next_v_reg = 0;76let mut next_stack: u32 = 0;7778let ret_area_ptr = if add_ret_area_ptr {79debug_assert_eq!(args_or_rets, ArgsOrRets::Args);80next_x_reg += 1;81Some(ABIArg::reg(82x_reg(next_x_reg - 1).to_real_reg().unwrap(),83I64,84ir::ArgumentExtension::None,85ir::ArgumentPurpose::Normal,86))87} else {88None89};9091for param in params {92// Find the regclass(es) of the register(s) used to store a value of93// this type.94let (rcs, reg_tys) = Self::I::rc_for_type(param.value_type)?;9596let mut slots = ABIArgSlotVec::new();97for (rc, reg_ty) in rcs.iter().zip(reg_tys.iter()) {98let next_reg = if (next_x_reg <= x_end) && *rc == RegClass::Int {99let x = Some(x_reg(next_x_reg));100next_x_reg += 1;101x102} else if (next_f_reg <= f_end) && *rc == RegClass::Float {103let f = Some(f_reg(next_f_reg));104next_f_reg += 1;105f106} else if (next_v_reg <= v_end) && *rc == RegClass::Vector {107let v = Some(v_reg(next_v_reg));108next_v_reg += 1;109v110} else {111None112};113114if let Some(reg) = next_reg {115slots.push(ABIArgSlot::Reg {116reg: reg.to_real_reg().unwrap(),117ty: *reg_ty,118extension: param.extension,119});120} else {121if args_or_rets == ArgsOrRets::Rets && !flags.enable_multi_ret_implicit_sret() {122return Err(crate::CodegenError::Unsupported(123"Too many return values to fit in registers. \124Use a StructReturn argument instead. (#9510)"125.to_owned(),126));127}128129// Compute size and 16-byte stack alignment happens130// separately after all args.131let size = reg_ty.bits() / 8;132let size = std::cmp::max(size, 8);133134// Align.135debug_assert!(size.is_power_of_two());136next_stack = align_to(next_stack, size);137138slots.push(ABIArgSlot::Stack {139offset: i64::from(next_stack),140ty: *reg_ty,141extension: param.extension,142});143144next_stack += size;145}146}147148args.push(ABIArg::Slots {149slots,150purpose: param.purpose,151});152}153154let pos = if let Some(ret_area_ptr) = ret_area_ptr {155args.push_non_formal(ret_area_ptr);156Some(args.args().len() - 1)157} else {158None159};160161next_stack = align_to(next_stack, Self::stack_align(call_conv));162163Ok((next_stack, pos))164}165166fn gen_load_stack(mem: StackAMode, into_reg: Writable<Reg>, ty: Type) -> Self::I {167let mut flags = MemFlags::trusted();168// Stack loads/stores of vectors always use little-endianess to avoid169// implementing a byte-swap of vectors on big-endian platforms.170if ty.is_vector() {171flags.set_endianness(ir::Endianness::Little);172}173Inst::gen_load(into_reg, mem.into(), ty, flags).into()174}175176fn gen_store_stack(mem: StackAMode, from_reg: Reg, ty: Type) -> Self::I {177let mut flags = MemFlags::trusted();178// Stack loads/stores of vectors always use little-endianess to avoid179// implementing a byte-swap of vectors on big-endian platforms.180if ty.is_vector() {181flags.set_endianness(ir::Endianness::Little);182}183Inst::gen_store(mem.into(), from_reg, ty, flags).into()184}185186fn gen_move(to_reg: Writable<Reg>, from_reg: Reg, ty: Type) -> Self::I {187Self::I::gen_move(to_reg, from_reg, ty)188}189190fn gen_extend(191dst: Writable<Reg>,192src: Reg,193signed: bool,194from_bits: u8,195to_bits: u8,196) -> Self::I {197assert!(from_bits < to_bits);198let src = XReg::new(src).unwrap();199let dst = dst.try_into().unwrap();200match (signed, from_bits) {201(true, 8) => RawInst::Sext8 { dst, src }.into(),202(true, 16) => RawInst::Sext16 { dst, src }.into(),203(true, 32) => RawInst::Sext32 { dst, src }.into(),204(false, 8) => RawInst::Zext8 { dst, src }.into(),205(false, 16) => RawInst::Zext16 { dst, src }.into(),206(false, 32) => RawInst::Zext32 { dst, src }.into(),207_ => unimplemented!("extend {from_bits} to {to_bits} as signed? {signed}"),208}209}210211fn get_ext_mode(212_call_conv: isa::CallConv,213specified: ir::ArgumentExtension,214) -> ir::ArgumentExtension {215specified216}217218fn gen_args(args: Vec<ArgPair>) -> Self::I {219Inst::Args { args }.into()220}221222fn gen_rets(rets: Vec<RetPair>) -> Self::I {223Inst::Rets { rets }.into()224}225226fn get_stacklimit_reg(_call_conv: isa::CallConv) -> Reg {227spilltmp_reg()228}229230fn gen_add_imm(231_call_conv: isa::CallConv,232into_reg: Writable<Reg>,233from_reg: Reg,234imm: u32,235) -> SmallInstVec<Self::I> {236let dst = into_reg.try_into().unwrap();237let imm = imm as i32;238smallvec![239RawInst::Xconst32 { dst, imm }.into(),240RawInst::Xadd32 {241dst,242src1: from_reg.try_into().unwrap(),243src2: dst.to_reg(),244}245.into()246]247}248249fn gen_stack_lower_bound_trap(_limit_reg: Reg) -> SmallInstVec<Self::I> {250unimplemented!("pulley shouldn't need stack bound checks")251}252253fn gen_get_stack_addr(mem: StackAMode, dst: Writable<Reg>) -> Self::I {254let dst = dst.to_reg();255let dst = XReg::new(dst).unwrap();256let dst = WritableXReg::from_reg(dst);257let mem = mem.into();258Inst::LoadAddr { dst, mem }.into()259}260261fn gen_load_base_offset(into_reg: Writable<Reg>, base: Reg, offset: i32, ty: Type) -> Self::I {262let base = XReg::try_from(base).unwrap();263let mem = Amode::RegOffset { base, offset };264Inst::gen_load(into_reg, mem, ty, MemFlags::trusted()).into()265}266267fn gen_store_base_offset(base: Reg, offset: i32, from_reg: Reg, ty: Type) -> Self::I {268let base = XReg::try_from(base).unwrap();269let mem = Amode::RegOffset { base, offset };270Inst::gen_store(mem, from_reg, ty, MemFlags::trusted()).into()271}272273fn gen_sp_reg_adjust(amount: i32) -> SmallInstVec<Self::I> {274if amount == 0 {275return smallvec![];276}277278let inst = if amount < 0 {279let amount = amount.checked_neg().unwrap();280if let Ok(amt) = u32::try_from(amount) {281RawInst::StackAlloc32 { amt }282} else {283unreachable!()284}285} else {286if let Ok(amt) = u32::try_from(amount) {287RawInst::StackFree32 { amt }288} else {289unreachable!()290}291};292smallvec![inst.into()]293}294295/// Generates the entire prologue for the function.296///297/// Note that this is different from other backends where it's not spread298/// out among a few individual functions. That's because the goal here is to299/// generate a single macro-instruction for the entire prologue in the most300/// common cases and we don't want to spread the logic over multiple301/// functions.302///303/// The general machinst methods are split to accommodate stack checks and304/// things like stack probes, all of which are empty on Pulley because305/// Pulley has its own stack check mechanism.306fn gen_prologue_frame_setup(307_call_conv: isa::CallConv,308_flags: &settings::Flags,309_isa_flags: &PulleyFlags,310frame_layout: &FrameLayout,311) -> SmallInstVec<Self::I> {312let mut insts = SmallVec::new();313314let incoming_args_diff = frame_layout.tail_args_size - frame_layout.incoming_args_size;315if incoming_args_diff > 0 {316// Decrement SP by the amount of additional incoming argument space317// we need318insts.extend(Self::gen_sp_reg_adjust(-(incoming_args_diff as i32)));319}320321let style = frame_layout.pulley_frame_style();322323match &style {324FrameStyle::None => {}325FrameStyle::PulleyBasicSetup { frame_size } => {326insts.push(RawInst::PushFrame.into());327insts.extend(Self::gen_sp_reg_adjust(328-i32::try_from(*frame_size).unwrap(),329));330}331FrameStyle::PulleySetupAndSaveClobbers {332frame_size,333saved_by_pulley,334} => insts.push(335RawInst::PushFrameSave {336amt: *frame_size,337regs: pulley_interpreter::UpperRegSet::from_bitset(*saved_by_pulley),338}339.into(),340),341FrameStyle::Manual { frame_size } => insts.extend(Self::gen_sp_reg_adjust(342-i32::try_from(*frame_size).unwrap(),343)),344}345346for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) {347insts.push(348Inst::gen_store(Amode::SpOffset { offset }, reg, ty, MemFlags::trusted()).into(),349);350}351352insts353}354355/// Reverse of `gen_prologue_frame_setup`.356fn gen_epilogue_frame_restore(357_call_conv: isa::CallConv,358_flags: &settings::Flags,359_isa_flags: &PulleyFlags,360frame_layout: &FrameLayout,361) -> SmallInstVec<Self::I> {362let mut insts = SmallVec::new();363364let style = frame_layout.pulley_frame_style();365366// Restore clobbered registers that are manually managed in Cranelift.367for (offset, ty, reg) in frame_layout.manually_managed_clobbers(&style) {368insts.push(369Inst::gen_load(370Writable::from_reg(reg),371Amode::SpOffset { offset },372ty,373MemFlags::trusted(),374)375.into(),376);377}378379// Perform the inverse of `gen_prologue_frame_setup`.380match &style {381FrameStyle::None => {}382FrameStyle::PulleyBasicSetup { frame_size } => {383insts.extend(Self::gen_sp_reg_adjust(i32::try_from(*frame_size).unwrap()));384insts.push(RawInst::PopFrame.into());385}386FrameStyle::PulleySetupAndSaveClobbers {387frame_size,388saved_by_pulley,389} => insts.push(390RawInst::PopFrameRestore {391amt: *frame_size,392regs: pulley_interpreter::UpperRegSet::from_bitset(*saved_by_pulley),393}394.into(),395),396FrameStyle::Manual { frame_size } => {397insts.extend(Self::gen_sp_reg_adjust(i32::try_from(*frame_size).unwrap()))398}399}400401insts402}403404fn gen_return(405call_conv: isa::CallConv,406_isa_flags: &PulleyFlags,407frame_layout: &FrameLayout,408) -> SmallInstVec<Self::I> {409let mut insts = SmallVec::new();410411// Handle final stack adjustments for the tail-call ABI.412if call_conv == isa::CallConv::Tail && frame_layout.tail_args_size > 0 {413insts.extend(Self::gen_sp_reg_adjust(414frame_layout.tail_args_size.try_into().unwrap(),415));416}417insts.push(RawInst::Ret {}.into());418419insts420}421422fn gen_probestack(_insts: &mut SmallInstVec<Self::I>, _frame_size: u32) {423// Pulley doesn't implement stack probes since all stack pointer424// decrements are checked already.425}426427fn gen_clobber_save(428_call_conv: isa::CallConv,429_flags: &settings::Flags,430_frame_layout: &FrameLayout,431) -> SmallVec<[Self::I; 16]> {432// Note that this is intentionally empty because everything necessary433// was already done in `gen_prologue_frame_setup`.434SmallVec::new()435}436437fn gen_clobber_restore(438_call_conv: isa::CallConv,439_flags: &settings::Flags,440_frame_layout: &FrameLayout,441) -> SmallVec<[Self::I; 16]> {442// Intentionally empty as restores happen for Pulley in `gen_return`.443SmallVec::new()444}445446fn gen_memcpy<F: FnMut(Type) -> Writable<Reg>>(447_call_conv: isa::CallConv,448_dst: Reg,449_src: Reg,450_size: usize,451_alloc_tmp: F,452) -> SmallVec<[Self::I; 8]> {453todo!()454}455456fn get_number_of_spillslots_for_value(457rc: RegClass,458_target_vector_bytes: u32,459_isa_flags: &PulleyFlags,460) -> u32 {461// Spill slots are the size of a "word" or a pointer, but Pulley462// registers are 8-byte for integers/floats regardless of pointer size.463// Calculate the number of slots necessary to store 8 bytes.464let slots_for_8bytes = match P::pointer_width() {465PointerWidth::PointerWidth32 => 2,466PointerWidth::PointerWidth64 => 1,467};468match rc {469// Int/float registers are 8-bytes470RegClass::Int | RegClass::Float => slots_for_8bytes,471// Vector registers are 16 bytes472RegClass::Vector => 2 * slots_for_8bytes,473}474}475476fn get_machine_env(_flags: &settings::Flags, _call_conv: isa::CallConv) -> &MachineEnv {477static MACHINE_ENV: OnceLock<MachineEnv> = OnceLock::new();478MACHINE_ENV.get_or_init(create_reg_environment)479}480481fn get_regs_clobbered_by_call(482_call_conv_of_callee: isa::CallConv,483is_exception: bool,484) -> PRegSet {485if is_exception {486ALL_CLOBBERS487} else {488DEFAULT_CLOBBERS489}490}491492fn compute_frame_layout(493_call_conv: isa::CallConv,494flags: &settings::Flags,495_sig: &Signature,496regs: &[Writable<RealReg>],497function_calls: FunctionCalls,498incoming_args_size: u32,499tail_args_size: u32,500stackslots_size: u32,501fixed_frame_storage_size: u32,502outgoing_args_size: u32,503) -> FrameLayout {504let mut regs: Vec<Writable<RealReg>> = regs505.iter()506.cloned()507.filter(|r| DEFAULT_CALLEE_SAVES.contains(r.to_reg().into()))508.collect();509510regs.sort_unstable();511512// Compute clobber size.513let clobber_size = compute_clobber_size(®s);514515// Compute linkage frame size.516let setup_area_size = if flags.preserve_frame_pointers()517|| function_calls != FunctionCalls::None518// The function arguments that are passed on the stack are addressed519// relative to the Frame Pointer.520|| incoming_args_size > 0521|| clobber_size > 0522|| fixed_frame_storage_size > 0523{524P::pointer_width().bytes() * 2 // FP, LR525} else {5260527};528529FrameLayout {530word_bytes: u32::from(P::pointer_width().bytes()),531incoming_args_size,532tail_args_size,533setup_area_size: setup_area_size.into(),534clobber_size,535fixed_frame_storage_size,536stackslots_size,537outgoing_args_size,538clobbered_callee_saves: regs,539function_calls,540}541}542543fn gen_inline_probestack(544_insts: &mut SmallInstVec<Self::I>,545_call_conv: isa::CallConv,546_frame_size: u32,547_guard_size: u32,548) {549// Pulley doesn't need inline probestacks because it always checks stack550// decrements.551}552553fn retval_temp_reg(_call_conv_of_callee: isa::CallConv) -> Writable<Reg> {554// Use x15 as a temp if needed: clobbered, not a555// retval.556Writable::from_reg(regs::x_reg(15))557}558559fn exception_payload_regs(_call_conv: isa::CallConv) -> &'static [Reg] {560const PAYLOAD_REGS: &'static [Reg] = &[561Reg::from_real_reg(regs::px_reg(0)),562Reg::from_real_reg(regs::px_reg(1)),563];564PAYLOAD_REGS565}566}567568/// Different styles of management of fp/lr and clobbered registers.569///570/// This helps decide, depending on Cranelift settings and frame layout, what571/// macro instruction is used to setup the pulley frame.572enum FrameStyle {573/// No management is happening, fp/lr aren't saved by Pulley or Cranelift.574/// No stack is being allocated either.575None,576577/// Pulley saves the fp/lr combo and then stack adjustments/clobbers are578/// handled manually.579PulleyBasicSetup { frame_size: u32 },580581/// Pulley is managing the fp/lr combo, the stack size, and clobbered582/// X-class registers.583///584/// Note that `saved_by_pulley` is not the exhaustive set of clobbered585/// registers. It's only those that are part of the `PushFrameSave`586/// instruction.587PulleySetupAndSaveClobbers {588/// The size of the frame, including clobbers, that's being allocated.589frame_size: u16,590/// Registers that pulley is saving/restoring.591saved_by_pulley: ScalarBitSet<u16>,592},593594/// Cranelift is manually managing everything, both clobbers and stack595/// increments/decrements.596///597/// Note that fp/lr are not saved in this mode.598Manual {599/// The size of the stack being allocated.600frame_size: u32,601},602}603604/// Pulley-specific helpers when dealing with ABI code.605impl FrameLayout {606/// Whether or not this frame saves fp/lr.607fn setup_frame(&self) -> bool {608self.setup_area_size > 0609}610611/// Returns the stack size allocated by this function, excluding incoming612/// tail args or the optional "setup area" of fp/lr.613fn stack_size(&self) -> u32 {614self.clobber_size + self.fixed_frame_storage_size + self.outgoing_args_size615}616617/// Returns the style of frame being used for this function.618///619/// See `FrameStyle` for more information.620fn pulley_frame_style(&self) -> FrameStyle {621let saved_by_pulley = self.clobbered_xregs_saved_by_pulley();622match (623self.stack_size(),624self.setup_frame(),625saved_by_pulley.is_empty(),626) {627// No stack allocated, not saving fp/lr, no clobbers, nothing to do628(0, false, true) => FrameStyle::None,629630// No stack allocated, saving fp/lr, no clobbers, so this is631// pulley-managed via push/pop_frame.632(0, true, true) => FrameStyle::PulleyBasicSetup { frame_size: 0 },633634// Some stack is being allocated and pulley is managing fp/lr. Let635// pulley manage clobbered registers as well, regardless if they're636// present or not.637//638// If the stack is too large then `PulleyBasicSetup` is used639// otherwise we'll be pushing `PushFrameSave` and `PopFrameRestore`.640(frame_size, true, _) => match frame_size.try_into() {641Ok(frame_size) => FrameStyle::PulleySetupAndSaveClobbers {642frame_size,643saved_by_pulley,644},645Err(_) => FrameStyle::PulleyBasicSetup { frame_size },646},647648// Some stack is being allocated, but pulley isn't managing fp/lr,649// so we're manually doing everything.650(frame_size, false, true) => FrameStyle::Manual { frame_size },651652// If there's no frame setup and there's clobbered registers this653// technically should have already hit a case above, so panic here.654(_, false, false) => unreachable!(),655}656}657658/// Returns the set of clobbered registers that Pulley is managing via its659/// macro instructions rather than the generated code.660fn clobbered_xregs_saved_by_pulley(&self) -> ScalarBitSet<u16> {661let mut clobbered: ScalarBitSet<u16> = ScalarBitSet::new();662// Pulley only manages clobbers if it's also managing fp/lr.663if !self.setup_frame() {664return clobbered;665}666let mut found_manual_clobber = false;667for reg in self.clobbered_callee_saves.iter() {668let r_reg = reg.to_reg();669// Pulley can only manage clobbers of integer registers at this670// time, float registers are managed manually.671//672// Also assert that all pulley-managed clobbers come first,673// otherwise the loop below in `manually_managed_clobbers` is674// incorrect.675if r_reg.class() == RegClass::Int {676assert!(!found_manual_clobber);677if let Some(offset) = r_reg.hw_enc().checked_sub(16) {678clobbered.insert(offset);679}680} else {681found_manual_clobber = true;682}683}684clobbered685}686687/// Returns an iterator over the clobbers that Cranelift is managing, not688/// Pulley.689///690/// If this frame has clobbers then they're either saved by Pulley with691/// `FrameStyle::PulleySetupAndSaveClobbers`. Cranelift might need to manage692/// these registers depending on Cranelift settings. Cranelift also always693/// manages floating-point registers.694fn manually_managed_clobbers<'a>(695&'a self,696style: &'a FrameStyle,697) -> impl Iterator<Item = (i32, Type, Reg)> + 'a {698let mut offset = self.stack_size();699self.clobbered_callee_saves.iter().filter_map(move |reg| {700// Allocate space for this clobber no matter what. If pulley is701// managing this then we're just accounting for the pulley-saved702// registers as well. Note that all pulley-managed registers come703// first in the list here.704offset -= 8;705let r_reg = reg.to_reg();706let ty = match r_reg.class() {707RegClass::Int => {708// If this register is saved by pulley, skip this clobber.709if let FrameStyle::PulleySetupAndSaveClobbers {710saved_by_pulley, ..711} = style712{713if let Some(reg) = r_reg.hw_enc().checked_sub(16) {714if saved_by_pulley.contains(reg) {715return None;716}717}718}719I64720}721RegClass::Float => F64,722RegClass::Vector => unreachable!("no vector registers are callee-save"),723};724let offset = i32::try_from(offset).unwrap();725Some((offset, ty, Reg::from(reg.to_reg())))726})727}728}729730const DEFAULT_CALLEE_SAVES: PRegSet = PRegSet::empty()731// Integer registers.732.with(px_reg(16))733.with(px_reg(17))734.with(px_reg(18))735.with(px_reg(19))736.with(px_reg(20))737.with(px_reg(21))738.with(px_reg(22))739.with(px_reg(23))740.with(px_reg(24))741.with(px_reg(25))742.with(px_reg(26))743.with(px_reg(27))744.with(px_reg(28))745.with(px_reg(29))746.with(px_reg(30))747.with(px_reg(31))748// Note: no float/vector registers are callee-saved.749;750751fn compute_clobber_size(clobbers: &[Writable<RealReg>]) -> u32 {752let mut clobbered_size = 0;753for reg in clobbers {754match reg.to_reg().class() {755RegClass::Int => {756clobbered_size += 8;757}758RegClass::Float => {759clobbered_size += 8;760}761RegClass::Vector => unimplemented!("Vector Size Clobbered"),762}763}764align_to(clobbered_size, 16)765}766767const DEFAULT_CLOBBERS: PRegSet = PRegSet::empty()768// Integer registers: the first 16 get clobbered.769.with(px_reg(0))770.with(px_reg(1))771.with(px_reg(2))772.with(px_reg(3))773.with(px_reg(4))774.with(px_reg(5))775.with(px_reg(6))776.with(px_reg(7))777.with(px_reg(8))778.with(px_reg(9))779.with(px_reg(10))780.with(px_reg(11))781.with(px_reg(12))782.with(px_reg(13))783.with(px_reg(14))784.with(px_reg(15))785// All float registers get clobbered.786.with(pf_reg(0))787.with(pf_reg(1))788.with(pf_reg(2))789.with(pf_reg(3))790.with(pf_reg(4))791.with(pf_reg(5))792.with(pf_reg(6))793.with(pf_reg(7))794.with(pf_reg(8))795.with(pf_reg(9))796.with(pf_reg(10))797.with(pf_reg(11))798.with(pf_reg(12))799.with(pf_reg(13))800.with(pf_reg(14))801.with(pf_reg(15))802.with(pf_reg(16))803.with(pf_reg(17))804.with(pf_reg(18))805.with(pf_reg(19))806.with(pf_reg(20))807.with(pf_reg(21))808.with(pf_reg(22))809.with(pf_reg(23))810.with(pf_reg(24))811.with(pf_reg(25))812.with(pf_reg(26))813.with(pf_reg(27))814.with(pf_reg(28))815.with(pf_reg(29))816.with(pf_reg(30))817.with(pf_reg(31))818// All vector registers get clobbered.819.with(pv_reg(0))820.with(pv_reg(1))821.with(pv_reg(2))822.with(pv_reg(3))823.with(pv_reg(4))824.with(pv_reg(5))825.with(pv_reg(6))826.with(pv_reg(7))827.with(pv_reg(8))828.with(pv_reg(9))829.with(pv_reg(10))830.with(pv_reg(11))831.with(pv_reg(12))832.with(pv_reg(13))833.with(pv_reg(14))834.with(pv_reg(15))835.with(pv_reg(16))836.with(pv_reg(17))837.with(pv_reg(18))838.with(pv_reg(19))839.with(pv_reg(20))840.with(pv_reg(21))841.with(pv_reg(22))842.with(pv_reg(23))843.with(pv_reg(24))844.with(pv_reg(25))845.with(pv_reg(26))846.with(pv_reg(27))847.with(pv_reg(28))848.with(pv_reg(29))849.with(pv_reg(30))850.with(pv_reg(31));851852const ALL_CLOBBERS: PRegSet = PRegSet::empty()853.with(px_reg(0))854.with(px_reg(1))855.with(px_reg(2))856.with(px_reg(3))857.with(px_reg(4))858.with(px_reg(5))859.with(px_reg(6))860.with(px_reg(7))861.with(px_reg(8))862.with(px_reg(9))863.with(px_reg(10))864.with(px_reg(11))865.with(px_reg(12))866.with(px_reg(13))867.with(px_reg(14))868.with(px_reg(15))869.with(px_reg(16))870.with(px_reg(17))871.with(px_reg(18))872.with(px_reg(19))873.with(px_reg(20))874.with(px_reg(21))875.with(px_reg(22))876.with(px_reg(23))877.with(px_reg(24))878.with(px_reg(25))879.with(px_reg(26))880.with(px_reg(27))881.with(px_reg(28))882.with(px_reg(29))883.with(px_reg(30))884.with(px_reg(31))885.with(pf_reg(0))886.with(pf_reg(1))887.with(pf_reg(2))888.with(pf_reg(3))889.with(pf_reg(4))890.with(pf_reg(5))891.with(pf_reg(6))892.with(pf_reg(7))893.with(pf_reg(8))894.with(pf_reg(9))895.with(pf_reg(10))896.with(pf_reg(11))897.with(pf_reg(12))898.with(pf_reg(13))899.with(pf_reg(14))900.with(pf_reg(15))901.with(pf_reg(16))902.with(pf_reg(17))903.with(pf_reg(18))904.with(pf_reg(19))905.with(pf_reg(20))906.with(pf_reg(21))907.with(pf_reg(22))908.with(pf_reg(23))909.with(pf_reg(24))910.with(pf_reg(25))911.with(pf_reg(26))912.with(pf_reg(27))913.with(pf_reg(28))914.with(pf_reg(29))915.with(pf_reg(30))916.with(pf_reg(31))917.with(pv_reg(0))918.with(pv_reg(1))919.with(pv_reg(2))920.with(pv_reg(3))921.with(pv_reg(4))922.with(pv_reg(5))923.with(pv_reg(6))924.with(pv_reg(7))925.with(pv_reg(8))926.with(pv_reg(9))927.with(pv_reg(10))928.with(pv_reg(11))929.with(pv_reg(12))930.with(pv_reg(13))931.with(pv_reg(14))932.with(pv_reg(15))933.with(pv_reg(16))934.with(pv_reg(17))935.with(pv_reg(18))936.with(pv_reg(19))937.with(pv_reg(20))938.with(pv_reg(21))939.with(pv_reg(22))940.with(pv_reg(23))941.with(pv_reg(24))942.with(pv_reg(25))943.with(pv_reg(26))944.with(pv_reg(27))945.with(pv_reg(28))946.with(pv_reg(29))947.with(pv_reg(30))948.with(pv_reg(31));949950fn create_reg_environment() -> MachineEnv {951// Prefer caller-saved registers over callee-saved registers, because that952// way we don't need to emit code to save and restore them if we don't953// mutate them.954955let preferred_regs_by_class: [Vec<PReg>; 3] = {956let x_registers: Vec<PReg> = (0..16).map(|x| px_reg(x)).collect();957let f_registers: Vec<PReg> = (0..32).map(|x| pf_reg(x)).collect();958let v_registers: Vec<PReg> = (0..32).map(|x| pv_reg(x)).collect();959[x_registers, f_registers, v_registers]960};961962let non_preferred_regs_by_class: [Vec<PReg>; 3] = {963let x_registers: Vec<PReg> = (16..XReg::SPECIAL_START)964.map(|x| px_reg(x.into()))965.collect();966let f_registers: Vec<PReg> = vec![];967let v_registers: Vec<PReg> = vec![];968[x_registers, f_registers, v_registers]969};970971MachineEnv {972preferred_regs_by_class,973non_preferred_regs_by_class,974fixed_stack_slots: vec![],975scratch_by_class: [None, None, None],976}977}978979980