| use std::fmt; | |
| use rustc_data_structures::fx::FxIndexSet; | |
| use rustc_span::{Symbol, kw, sym}; | |
| use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; | |
| use crate::spec::{RelocModel, Target}; | |
| def_reg_class! { | |
| Xtensa XtensaInlineAsmRegClass { | |
| reg, | |
| freg, | |
| sreg, | |
| breg, | |
| } | |
| } | |
| impl XtensaInlineAsmRegClass { | |
| pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { | |
| &[] | |
| } | |
| pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option<Self> { | |
| None | |
| } | |
| pub fn suggest_modifier( | |
| self, | |
| _arch: InlineAsmArch, | |
| _ty: InlineAsmType, | |
| ) -> Option<ModifierInfo> { | |
| None | |
| } | |
| pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<ModifierInfo> { | |
| None | |
| } | |
| pub fn supported_types( | |
| self, | |
| _arch: InlineAsmArch, | |
| ) -> &'static [(InlineAsmType, Option<Symbol>)] { | |
| match self { | |
| Self::reg => types! { _: I8, I16, I32; }, | |
| Self::freg => types! { fp: F32; }, | |
| Self::sreg | Self::breg => &[], | |
| } | |
| } | |
| } | |
| fn has_fp( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&sym::fp) { | |
| Ok(()) | |
| } else { | |
| Err("target does not support floating point registers") | |
| } | |
| } | |
| // The frame pointer is a7 under the windowed ABI and a15 otherwise. Always | |
| // reject it as an inline asm operand: LLVM can force its use for variable- | |
| // sized stack frames (e.g. via cross-language LTO with C). | |
| fn frame_pointer_a7( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&sym::windowed) { | |
| Err("the frame pointer (a7) cannot be used as an operand for inline asm") | |
| } else { | |
| Ok(()) | |
| } | |
| } | |
| fn frame_pointer_a15( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if !target_features.contains(&sym::windowed) { | |
| Err("the frame pointer (a15) cannot be used as an operand for inline asm") | |
| } else { | |
| Ok(()) | |
| } | |
| } | |
| fn has_bool( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&sym::bool) { | |
| Ok(()) | |
| } else { | |
| Err("target does not support boolean registers") | |
| } | |
| } | |
| fn has_loop( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&kw::Loop) { | |
| Ok(()) | |
| } else { | |
| Err("target does not support loop registers") | |
| } | |
| } | |
| fn has_mac16( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&sym::mac16) { | |
| Ok(()) | |
| } else { | |
| Err("target does not support MAC16 registers") | |
| } | |
| } | |
| fn has_s32c1i( | |
| _arch: InlineAsmArch, | |
| _reloc_model: RelocModel, | |
| target_features: &FxIndexSet<Symbol>, | |
| _target: &Target, | |
| _is_clobber: bool, | |
| ) -> Result<(), &'static str> { | |
| if target_features.contains(&sym::s32c1i) { | |
| Ok(()) | |
| } else { | |
| Err("target does not support the s32c1i instruction") | |
| } | |
| } | |
| def_regs! { | |
| Xtensa XtensaInlineAsmReg XtensaInlineAsmRegClass { | |
| a2: reg = ["a2"], | |
| a3: reg = ["a3"], | |
| a4: reg = ["a4"], | |
| a5: reg = ["a5"], | |
| a6: reg = ["a6"], | |
| a7: reg = ["a7"] % frame_pointer_a7, | |
| a8: reg = ["a8"], | |
| a9: reg = ["a9"], | |
| a10: reg = ["a10"], | |
| a11: reg = ["a11"], | |
| a12: reg = ["a12"], | |
| a13: reg = ["a13"], | |
| a14: reg = ["a14"], | |
| a15: reg = ["a15"] % frame_pointer_a15, | |
| f0: freg = ["f0"] % has_fp, | |
| f1: freg = ["f1"] % has_fp, | |
| f2: freg = ["f2"] % has_fp, | |
| f3: freg = ["f3"] % has_fp, | |
| f4: freg = ["f4"] % has_fp, | |
| f5: freg = ["f5"] % has_fp, | |
| f6: freg = ["f6"] % has_fp, | |
| f7: freg = ["f7"] % has_fp, | |
| f8: freg = ["f8"] % has_fp, | |
| f9: freg = ["f9"] % has_fp, | |
| f10: freg = ["f10"] % has_fp, | |
| f11: freg = ["f11"] % has_fp, | |
| f12: freg = ["f12"] % has_fp, | |
| f13: freg = ["f13"] % has_fp, | |
| f14: freg = ["f14"] % has_fp, | |
| f15: freg = ["f15"] % has_fp, | |
| // Clobber-only special registers (caller-saved per ISA ยง8.1.7, except | |
| // LITBASE); needed for `clobber_abi`. | |
| sar: sreg = ["sar"], | |
| scompare1: sreg = ["scompare1"] % has_s32c1i, | |
| lbeg: sreg = ["lbeg"] % has_loop, | |
| lend: sreg = ["lend"] % has_loop, | |
| lcount: sreg = ["lcount"] % has_loop, | |
| acclo: sreg = ["acclo"] % has_mac16, | |
| acchi: sreg = ["acchi"] % has_mac16, | |
| m0: sreg = ["m0"] % has_mac16, | |
| m1: sreg = ["m1"] % has_mac16, | |
| m2: sreg = ["m2"] % has_mac16, | |
| m3: sreg = ["m3"] % has_mac16, | |
| // Clobber-only boolean registers. | |
| b0: breg = ["b0"] % has_bool, | |
| b1: breg = ["b1"] % has_bool, | |
| b2: breg = ["b2"] % has_bool, | |
| b3: breg = ["b3"] % has_bool, | |
| b4: breg = ["b4"] % has_bool, | |
| b5: breg = ["b5"] % has_bool, | |
| b6: breg = ["b6"] % has_bool, | |
| b7: breg = ["b7"] % has_bool, | |
| b8: breg = ["b8"] % has_bool, | |
| b9: breg = ["b9"] % has_bool, | |
| b10: breg = ["b10"] % has_bool, | |
| b11: breg = ["b11"] % has_bool, | |
| b12: breg = ["b12"] % has_bool, | |
| b13: breg = ["b13"] % has_bool, | |
| b14: breg = ["b14"] % has_bool, | |
| b15: breg = ["b15"] % has_bool, | |
| #error = ["a0"] => "a0 is used internally by LLVM and cannot be used as an operand for inline asm", | |
| #error = ["sp", "a1"] => "sp is used internally by LLVM and cannot be used as an operand for inline asm", | |
| } | |
| } | |
| impl XtensaInlineAsmReg { | |
| pub fn emit( | |
| self, | |
| out: &mut dyn fmt::Write, | |
| _arch: InlineAsmArch, | |
| _modifier: Option<char>, | |
| ) -> fmt::Result { | |
| out.write_str(self.name()) | |
| } | |
| } |