| 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()) |
| } |
| } |