diff --git a/compiler/rustc_codegen_llvm/src/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs index a53946995ee1c..8eab11ce603bc 100644 --- a/compiler/rustc_codegen_llvm/src/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -233,6 +233,7 @@ impl<'ll, 'tcx> AsmBuilderMethods<'tcx> for Builder<'_, 'll, 'tcx> { InlineAsmArch::S390x => {} InlineAsmArch::SpirV => {} InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => {} + InlineAsmArch::Xtensa => {} InlineAsmArch::Bpf => {} InlineAsmArch::Msp430 => { constraints.push("~{sr}".to_string()); @@ -608,6 +609,9 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) -> | X86InlineAsmRegClass::tmm_reg, ) => unreachable!("clobber-only"), InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => "r", + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::freg) => "f", + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::breg) => "b", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => "r", InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => "w", InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => "r", @@ -661,6 +665,7 @@ fn modifier_to_llvm( InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::PowerPC(_) => None, + InlineAsmRegClass::Xtensa(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::vreg) => { @@ -774,6 +779,9 @@ fn dummy_output_type<'ll>(cx: &CodegenCx<'ll, '_>, reg: InlineAsmRegClass) -> &' unreachable!("clobber-only") } InlineAsmRegClass::Wasm(WasmInlineAsmRegClass::local) => cx.type_i32(), + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::reg) => cx.type_i32(), + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::freg) => cx.type_f32(), + InlineAsmRegClass::Xtensa(XtensaInlineAsmRegClass::breg) => cx.type_i1(), InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::reg) => cx.type_i64(), InlineAsmRegClass::Bpf(BpfInlineAsmRegClass::wreg) => cx.type_i32(), InlineAsmRegClass::Avr(AvrInlineAsmRegClass::reg) => cx.type_i8(), diff --git a/compiler/rustc_codegen_ssa/src/target_features.rs b/compiler/rustc_codegen_ssa/src/target_features.rs index bfdef2dc0e80c..eac6555843858 100644 --- a/compiler/rustc_codegen_ssa/src/target_features.rs +++ b/compiler/rustc_codegen_ssa/src/target_features.rs @@ -251,6 +251,35 @@ const WASM_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("reference-types", Some(sym::wasm_target_feature)), ]; +const XTENSA_ALLOWED_FEATURES: &[(&str, Option)] = &[ + ("fp", Some(sym::xtensa_target_feature)), + ("windowed", Some(sym::xtensa_target_feature)), + ("bool", Some(sym::xtensa_target_feature)), + ("loop", Some(sym::xtensa_target_feature)), + ("sext", Some(sym::xtensa_target_feature)), + ("nsa", Some(sym::xtensa_target_feature)), + ("mul32", Some(sym::xtensa_target_feature)), + ("mul32high", Some(sym::xtensa_target_feature)), + ("div32", Some(sym::xtensa_target_feature)), + ("mac16", Some(sym::xtensa_target_feature)), + ("dfpaccel", Some(sym::xtensa_target_feature)), + ("s32c1i", Some(sym::xtensa_target_feature)), + ("threadptr", Some(sym::xtensa_target_feature)), + ("extendedl32r", Some(sym::xtensa_target_feature)), + ("atomctl", Some(sym::xtensa_target_feature)), + ("memctl", Some(sym::xtensa_target_feature)), + ("debug", Some(sym::xtensa_target_feature)), + ("exception", Some(sym::xtensa_target_feature)), + ("highpriinterrupts", Some(sym::xtensa_target_feature)), + ("coprocessor", Some(sym::xtensa_target_feature)), + ("interrupt", Some(sym::xtensa_target_feature)), + ("rvector", Some(sym::xtensa_target_feature)), + ("timerint", Some(sym::xtensa_target_feature)), + ("prid", Some(sym::xtensa_target_feature)), + ("regprotect", Some(sym::xtensa_target_feature)), + ("miscsr", Some(sym::xtensa_target_feature)), +]; + const BPF_ALLOWED_FEATURES: &[(&str, Option)] = &[("alu32", Some(sym::bpf_target_feature))]; /// When rustdoc is running, provide a list of all known features so that all their respective @@ -267,6 +296,7 @@ pub fn all_known_features() -> impl Iterator &'static [(&'static str, Opt "powerpc" | "powerpc64" => POWERPC_ALLOWED_FEATURES, "riscv32" | "riscv64" => RISCV_ALLOWED_FEATURES, "wasm32" | "wasm64" => WASM_ALLOWED_FEATURES, + "xtensa" => XTENSA_ALLOWED_FEATURES, "bpf" => BPF_ALLOWED_FEATURES, _ => &[], } diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 8a6941a451621..ff7ddf522efef 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -373,6 +373,7 @@ symbols! { assume_init, async_await, async_closure, + atomctl, atomic, atomic_mod, atomics, @@ -414,6 +415,7 @@ symbols! { braced_empty_structs, branch, breakpoint, + breg, bridge, bswap, c_str, @@ -525,6 +527,7 @@ symbols! { contents, context, convert, + coprocessor, copy, copy_closures, copy_nonoverlapping, @@ -591,6 +594,7 @@ symbols! { derive_default_enum, destruct, destructuring_assignment, + dfpaccel, diagnostic, direct, discriminant_kind, @@ -648,6 +652,7 @@ symbols! { ermsb_target_feature, exact_div, except, + exception, exchange_malloc, exclusive_range_pattern, exhaustive_integer_patterns, @@ -663,6 +668,7 @@ symbols! { export_name, expr, extended_key_value_attributes, + extendedl32r, extern_absolute_paths, extern_crate_item_prelude, extern_crate_self, @@ -757,6 +763,7 @@ symbols! { hash, hexagon_target_feature, hidden, + highpriinterrupts, homogeneous_aggregate, html_favicon_url, html_logo_url, @@ -804,6 +811,7 @@ symbols! { integer_: "integer", integral, intel, + interrupt, into_future, into_iter, intra_doc_pointers, @@ -864,6 +872,7 @@ symbols! { logf64, loop_break_value, lt, + mac16, macro_at_most_once_rep, macro_attributes_in_derive_output, macro_escape, @@ -902,6 +911,7 @@ symbols! { mem_variant_count, mem_zeroed, member_constraints, + memctl, memory, memtag, message, @@ -919,6 +929,7 @@ symbols! { mips_target_feature, miri, misc, + miscsr, mmx_reg, modifiers, module, @@ -1071,6 +1082,7 @@ symbols! { prelude, prelude_import, preserves_flags, + prid, primitive, print_macro, println_macro, @@ -1255,7 +1267,9 @@ symbols! { rustdoc_internals, rustfmt, rvalue_static_promotion, + rvector, s, + s32c1i, sanitize, sanitizer_runtime, saturating_add, @@ -1424,8 +1438,10 @@ symbols! { thread, thread_local, thread_local_macro, + threadptr, thumb2, thumb_mode: "thumb-mode", + timerint, tmm_reg, todo_macro, tool_attributes, @@ -1548,6 +1564,7 @@ symbols! { wasm_target_feature, while_let, width, + windowed, windows, windows_subsystem, with_negative_coherence, @@ -1561,7 +1578,9 @@ symbols! { writeln_macro, x87_reg, xer, + xloop, xmm_reg, + xtensa_target_feature, yeet_desugar_details, yeet_expr, ymm_reg, diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index df8ccc42a77a3..49204b0ace638 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -176,6 +176,7 @@ mod s390x; mod spirv; mod wasm; mod x86; +mod xtensa; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; @@ -190,6 +191,7 @@ pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; +pub use xtensa::{XtensaInlineAsmReg, XtensaInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; #[derive(Copy, Clone, Encodable, Decodable, Debug, Eq, PartialEq, Hash)] @@ -210,6 +212,7 @@ pub enum InlineAsmArch { SpirV, Wasm32, Wasm64, + Xtensa, Bpf, Avr, Msp430, @@ -236,6 +239,7 @@ impl FromStr for InlineAsmArch { "spirv" => Ok(Self::SpirV), "wasm32" => Ok(Self::Wasm32), "wasm64" => Ok(Self::Wasm64), + "xtensa" => Ok(Self::Xtensa), "bpf" => Ok(Self::Bpf), "avr" => Ok(Self::Avr), "msp430" => Ok(Self::Msp430), @@ -268,6 +272,7 @@ pub enum InlineAsmReg { S390x(S390xInlineAsmReg), SpirV(SpirVInlineAsmReg), Wasm(WasmInlineAsmReg), + Xtensa(XtensaInlineAsmReg), Bpf(BpfInlineAsmReg), Avr(AvrInlineAsmReg), Msp430(Msp430InlineAsmReg), @@ -286,6 +291,7 @@ impl InlineAsmReg { Self::Hexagon(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), + Self::Xtensa(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), @@ -303,6 +309,7 @@ impl InlineAsmReg { Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), + Self::Xtensa(r) => InlineAsmRegClass::Xtensa(r.reg_class()), Self::Bpf(r) => InlineAsmRegClass::Bpf(r.reg_class()), Self::Avr(r) => InlineAsmRegClass::Avr(r.reg_class()), Self::Msp430(r) => InlineAsmRegClass::Msp430(r.reg_class()), @@ -329,6 +336,9 @@ impl InlineAsmReg { InlineAsmArch::Mips | InlineAsmArch::Mips64 => { Self::Mips(MipsInlineAsmReg::parse(name)?) } + InlineAsmArch::Xtensa => { + Self::Xtensa(XtensaInlineAsmReg::parse(name)?) + } InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?), InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?), InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { @@ -359,6 +369,7 @@ impl InlineAsmReg { Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Bpf(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Avr(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), + Self::Xtensa(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::Err => unreachable!(), } @@ -381,6 +392,7 @@ impl InlineAsmReg { Self::Hexagon(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), Self::S390x(r) => r.emit(out, arch, modifier), + Self::Xtensa(r) => r.emit(out, arch, modifier), Self::Bpf(r) => r.emit(out, arch, modifier), Self::Avr(r) => r.emit(out, arch, modifier), Self::Msp430(r) => r.emit(out, arch, modifier), @@ -398,6 +410,7 @@ impl InlineAsmReg { Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), Self::Mips(_) => cb(self), Self::S390x(_) => cb(self), + Self::Xtensa(_) => cb(self), Self::Bpf(r) => r.overlapping_regs(|r| cb(Self::Bpf(r))), Self::Avr(r) => r.overlapping_regs(|r| cb(Self::Avr(r))), Self::Msp430(_) => cb(self), @@ -430,6 +443,7 @@ pub enum InlineAsmRegClass { S390x(S390xInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), Wasm(WasmInlineAsmRegClass), + Xtensa(XtensaInlineAsmRegClass), Bpf(BpfInlineAsmRegClass), Avr(AvrInlineAsmRegClass), Msp430(Msp430InlineAsmRegClass), @@ -451,6 +465,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.name(), Self::SpirV(r) => r.name(), Self::Wasm(r) => r.name(), + Self::Xtensa(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), @@ -474,6 +489,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), + Self::Xtensa(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Xtensa), Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), Self::Avr(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Avr), Self::Msp430(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Msp430), @@ -504,6 +520,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), Self::Wasm(r) => r.suggest_modifier(arch, ty), + Self::Xtensa(r) => r.suggest_modifier(arch, ty), Self::Bpf(r) => r.suggest_modifier(arch, ty), Self::Avr(r) => r.suggest_modifier(arch, ty), Self::Msp430(r) => r.suggest_modifier(arch, ty), @@ -530,6 +547,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), Self::Wasm(r) => r.default_modifier(arch), + Self::Xtensa(r) => r.default_modifier(arch), Self::Bpf(r) => r.default_modifier(arch), Self::Avr(r) => r.default_modifier(arch), Self::Msp430(r) => r.default_modifier(arch), @@ -555,6 +573,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch), + Self::Xtensa(r) => r.supported_types(arch), Self::Bpf(r) => r.supported_types(arch), Self::Avr(r) => r.supported_types(arch), Self::Msp430(r) => r.supported_types(arch), @@ -587,6 +606,7 @@ impl InlineAsmRegClass { } InlineAsmArch::Bpf => Self::Bpf(BpfInlineAsmRegClass::parse(name)?), InlineAsmArch::Avr => Self::Avr(AvrInlineAsmRegClass::parse(name)?), + InlineAsmArch::Xtensa => Self::Xtensa(XtensaInlineAsmRegClass::parse(name)?), InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmRegClass::parse(name)?), }) } @@ -606,6 +626,7 @@ impl InlineAsmRegClass { Self::S390x(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), Self::Wasm(r) => r.valid_modifiers(arch), + Self::Xtensa(r) => r.valid_modifiers(arch), Self::Bpf(r) => r.valid_modifiers(arch), Self::Avr(r) => r.valid_modifiers(arch), Self::Msp430(r) => r.valid_modifiers(arch), @@ -658,6 +679,7 @@ impl fmt::Display for InlineAsmRegOrRegClass { /// Set of types which can be used with a particular register class. #[derive(Copy, Clone, Debug, Eq, PartialEq)] pub enum InlineAsmType { + I1, I8, I16, I32, @@ -681,6 +703,7 @@ impl InlineAsmType { pub fn size(self) -> Size { Size::from_bytes(match self { + Self::I1 => return Size::from_bits(1), Self::I8 => 1, Self::I16 => 2, Self::I32 => 4, @@ -702,6 +725,7 @@ impl InlineAsmType { impl fmt::Display for InlineAsmType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { + Self::I1 => f.write_str("i1"), Self::I8 => f.write_str("i8"), Self::I16 => f.write_str("i16"), Self::I32 => f.write_str("i32"), @@ -790,6 +814,11 @@ pub fn allocatable_registers( wasm::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } + InlineAsmArch::Xtensa => { + let mut map = xtensa::regclass_map(); + xtensa::fill_reg_map(arch, reloc_model, target_features, target, &mut map); + map + } InlineAsmArch::Bpf => { let mut map = bpf::regclass_map(); bpf::fill_reg_map(arch, reloc_model, target_features, target, &mut map); diff --git a/compiler/rustc_target/src/asm/xtensa.rs b/compiler/rustc_target/src/asm/xtensa.rs new file mode 100644 index 0000000000000..288fff4adfc6d --- /dev/null +++ b/compiler/rustc_target/src/asm/xtensa.rs @@ -0,0 +1,294 @@ +use super::{InlineAsmArch, InlineAsmType}; +use crate::spec::{Target, RelocModel}; +use rustc_macros::HashStable_Generic; +use rustc_data_structures::stable_set::FxHashSet; +use rustc_span::{sym, Symbol}; +use std::fmt; + +def_reg_class! { + Xtensa XtensaInlineAsmRegClass { + reg, + freg, + breg, + } +} + +impl XtensaInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option)] { + match self { + Self::reg => types! { _: I8, I16, I32; }, + Self::breg => types! { bool: I1; }, + Self::freg => types! { fp: F32; dfpaccel: F64; }, + } + } +} + +// Xtensa has lots of features - macro to reduce boiler plate +macro_rules! feature { + ($fnname:ident, $feature:expr) => { + fn $fnname( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + target_features: &FxHashSet, + _target: &Target, + _is_clobber: bool, + ) -> Result<(), &'static str> { + if target_features.contains(&$feature) { + Ok(()) + } else { + Err(concat!("target does not support ", stringify!($feature), " registers")) + } + } + }; +} + +feature!(has_fp, sym::fp); +feature!(has_dfpaccel, sym::dfpaccel); +feature!(has_bool, sym::bool); +feature!(has_xloop, sym::xloop); +feature!(has_extendedl32r, sym::extendedl32r); +feature!(has_s32c1i, sym::s32c1i); +feature!(has_mac16, sym::mac16); +feature!(has_windowed, sym::windowed); +feature!(has_debug, sym::debug); +feature!(has_memctl, sym::memctl); +feature!(has_atomctl, sym::atomctl); +feature!(has_exception, sym::exception); +feature!(has_highpriinterrupts, sym::highpriinterrupts); +feature!(has_coprocessor, sym::coprocessor); +feature!(has_rvector, sym::rvector); +feature!(has_timerint, sym::timerint); +feature!(has_interrupt, sym::interrupt); +feature!(has_prid, sym::prid); +feature!(has_miscsr, sym::miscsr); +feature!(has_threadptr, sym::threadptr); + +fn has_expstate( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxHashSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + match target.cpu.as_ref() { + "esp32" => Ok(()), + _ => Err("target does not support expstate registers") + } +} +fn has_gpio_out( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxHashSet, + target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + match target.cpu.as_ref() { + "esp32-s2" => Ok(()), + _ => Err("target does not support gpio_out registers") + } +} + +// FIXME sometimes there isn't a frame pointer at all? +fn frame_pointer_is_a7( + _arch: InlineAsmArch, + _reloc_model: RelocModel, + target_features: &FxHashSet, + _target: &Target, + _is_clobber: bool, +) -> bool { + target_features.contains(&sym::windowed) +} + +fn frame_pointer_a7( + arch: InlineAsmArch, + reloc_model: RelocModel, + target_features: &FxHashSet, + target: &Target, + is_clobber: bool, +) -> Result<(), &'static str> { + if frame_pointer_is_a7(arch, reloc_model, target_features, target, is_clobber) { + 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: &FxHashSet, + target: &Target, + is_clobber: bool, +) -> Result<(), &'static str> { + if !frame_pointer_is_a7(arch, reloc_model, target_features, target, is_clobber) { + Err("the frame pointer (a15) cannot be used as an operand for inline asm") + } else { + Ok(()) + } +} + +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, + sar: reg = ["sar"], + configid0: reg = ["configid0"], + configid1: reg = ["configid1"], + lbeg: reg = ["lbeg"] % has_xloop, + lend: reg = ["lend"] % has_xloop, + lcount: reg = ["lcount"] % has_xloop, + litbase: reg = ["litbase"] % has_extendedl32r, + scompare1: reg = ["scompare1"] % has_s32c1i, + acclo: reg = ["acclo"] % has_mac16, + acchi: reg = ["acchi"] % has_mac16, + m0: reg = ["m0"] % has_mac16, + m1: reg = ["m1"] % has_mac16, + m2: reg = ["m2"] % has_mac16, + m3: reg = ["m3"] % has_mac16, + windowbase: reg = ["windowbase"] % has_windowed, + windowstart: reg = ["windowstart"] % has_windowed, + ddr: reg = ["ddr"] % has_debug, + ibreakenable: reg = ["ibreakenable"] % has_debug, + ibreaka0: reg = ["ibreaka0"] % has_debug, + ibreaka1: reg = ["ibreaka1"] % has_debug, + dbreaka0: reg = ["dbreaka0"] % has_debug, + dbreaka1: reg = ["dbreaka1"] % has_debug, + dbreakc0: reg = ["dbreakc0"] % has_debug, + dbreakc1: reg = ["dbreakc1"] % has_debug, + icount: reg = ["icount"] % has_debug, + icountlevel: reg = ["icountlevel"] % has_debug, + debugcause: reg = ["debugcause"] % has_debug, + memctl: reg = ["memctl"] % has_memctl, + atomctl: reg = ["atomctl"] % has_atomctl, + ps: reg = ["ps"] % has_exception, + epc1: reg = ["epc1"] % has_exception, + epc2: reg = ["epc2"] % has_highpriinterrupts, + epc3: reg = ["epc3"] % has_highpriinterrupts, + epc4: reg = ["epc4"] % has_highpriinterrupts, + epc5: reg = ["epc5"] % has_highpriinterrupts, + epc6: reg = ["epc6"] % has_highpriinterrupts, + epc7: reg = ["epc7"] % has_highpriinterrupts, + depc: reg = ["depc"] % has_exception, + eps2: reg = ["eps2"] % has_highpriinterrupts, + eps3: reg = ["eps3"] % has_highpriinterrupts, + eps4: reg = ["eps4"] % has_highpriinterrupts, + eps5: reg = ["eps5"] % has_highpriinterrupts, + eps6: reg = ["eps6"] % has_highpriinterrupts, + eps7: reg = ["eps7"] % has_highpriinterrupts, + excsave1: reg = ["excsave1"] % has_exception, + excsave2: reg = ["excsave2"] % has_highpriinterrupts, + excsave3: reg = ["excsave3"] % has_highpriinterrupts, + excsave4: reg = ["excsave4"] % has_highpriinterrupts, + excsave5: reg = ["excsave5"] % has_highpriinterrupts, + excsave6: reg = ["excsave6"] % has_highpriinterrupts, + excsave7: reg = ["excsave7"] % has_highpriinterrupts, + exccause: reg = ["exccause"] % has_exception, + excvaddr: reg = ["excvaddr"] % has_exception, + cpenable: reg = ["cpenable"] % has_coprocessor, + vecbase: reg = ["vecbase"] % has_rvector, + interrupt: reg = ["interrupt"] % has_interrupt, + intclear: reg = ["intclear"] % has_interrupt, + intenable: reg = ["intenable"] % has_interrupt, + prid: reg = ["prid"] % has_prid, + ccount: reg = ["ccount"] % has_timerint, + ccompare0: reg = ["ccompare0"] % has_timerint, + ccompare1: reg = ["ccompare1"] % has_timerint, + ccompare2: reg = ["ccompare2"] % has_timerint, + misc0: reg = ["misc0"] % has_miscsr, + misc1: reg = ["misc1"] % has_miscsr, + misc2: reg = ["misc2"] % has_miscsr, + misc3: reg = ["misc3"] % has_miscsr, + threadptr: reg = ["threadptr"] % has_threadptr, + fcr: reg = ["fcr"] % has_dfpaccel, + fsr: reg = ["fsr"] % has_dfpaccel, + f64r_lo: reg = ["f64r_lo"] % has_dfpaccel, + f64r_hi: reg = ["f64r_hi"] % has_dfpaccel, + f64s: reg = ["f64s"] % has_dfpaccel, + 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, + br: reg = ["br"] % has_bool, + 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, + + // Custom TIE extensions - https://en.wikipedia.org/wiki/Tensilica_Instruction_Extension + gpio_out: reg = ["gpio_out"] % has_gpio_out, + expstate: reg = ["expstate"] % has_expstate, + + #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, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/src/test/assembly/asm/xtensa-types.rs b/src/test/assembly/asm/xtensa-types.rs new file mode 100644 index 0000000000000..8bdecc4f37b46 --- /dev/null +++ b/src/test/assembly/asm/xtensa-types.rs @@ -0,0 +1,140 @@ +// min-llvm-version: 10.0.1 +// assembly-output: emit-asm +// compile-flags: --target xtensa-esp32-none-elf +// needs-llvm-components: xtensa + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for f64 {} +impl Copy for ptr {} + +extern "C" { + fn extern_func(); +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: call4 extern_func +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + asm!("call4 {}", sym extern_func); +} + +macro_rules! check_general_reg { + ($func:ident $ty:ident $class:ident $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " {}, {}"), out($class) y, in($class) x); + y + } + }; +} + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: mov a{{[0-9]+}}, a{{[0-9]+}} +// CHECK: #NO_APP +check_general_reg!(reg_i8 i8 reg "mov"); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: mov a{{[0-9]+}}, a{{[0-9]+}} +// CHECK: #NO_APP +check_general_reg!(reg_i16 i16 reg "mov"); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: mov a{{[0-9]+}}, a{{[0-9]+}} +// CHECK: #NO_APP +check_general_reg!(reg_i32 i32 reg "mov"); + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: mov a{{[0-9]+}}, a{{[0-9]+}} +// CHECK: #NO_APP +check_general_reg!(reg_ptr ptr reg "mov"); + +// CHECK-LABEL: freg_f32: +// CHECK: #APP +// CHECK: mov.s f{{[0-9]+}}, f{{[0-9]+}} +// CHECK: #NO_APP +check_general_reg!(freg_f32 f32 freg "mov.s"); + +macro_rules! check_explicit_reg { + ($func:ident $ty:ident $reg:tt $mov:literal) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!($mov, " ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } + }; +} + +// CHECK-LABEL: a5_i8: +// CHECK: #APP +// CHECK: mov a5, a5 +// CHECK: #NO_APP +check_explicit_reg!(a5_i8 i8 "a5" "mov"); + +// CHECK-LABEL: a5_i16: +// CHECK: #APP +// CHECK: mov a5, a5 +// CHECK: #NO_APP +check_explicit_reg!(a5_i16 i16 "a5" "mov"); + +// CHECK-LABEL: a0_i32: +// CHECK: #APP +// CHECK: mov a5, a5 +// CHECK: #NO_APP +check_explicit_reg!(a5_i32 i32 "a5" "mov"); + +// CHECK-LABEL: a5_ptr: +// CHECK: #APP +// CHECK: mov a5, a5 +// CHECK: #NO_APP +check_explicit_reg!(a5_ptr ptr "a5" "mov"); + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s f0, f0 +// CHECK: #NO_APP +check_explicit_reg!(f0_f32 f32 "f0" "mov.s");