diff options
| author | Taiki Endo <te316e89@gmail.com> | 2024-11-07 21:19:03 +0900 |
|---|---|---|
| committer | Taiki Endo <te316e89@gmail.com> | 2024-11-07 21:19:03 +0900 |
| commit | 241f82ad915b167992ec9d3bb729f095a7829424 (patch) | |
| tree | 929b6fb781d5536274cb0cef82d76d81e1eba399 /compiler/rustc_target/src | |
| parent | c07aa1e17199e27f6f7ac8f3307bca7bda0084b6 (diff) | |
| download | rust-241f82ad915b167992ec9d3bb729f095a7829424.tar.gz rust-241f82ad915b167992ec9d3bb729f095a7829424.zip | |
Basic inline assembly support for SPARC and SPARC64
Diffstat (limited to 'compiler/rustc_target/src')
| -rw-r--r-- | compiler/rustc_target/src/asm/mod.rs | 30 | ||||
| -rw-r--r-- | compiler/rustc_target/src/asm/sparc.rs | 138 |
2 files changed, 168 insertions, 0 deletions
diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index 460b6e4b647..1632c6ad2d3 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -191,6 +191,7 @@ mod nvptx; mod powerpc; mod riscv; mod s390x; +mod sparc; mod spirv; mod wasm; mod x86; @@ -209,6 +210,7 @@ pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use powerpc::{PowerPCInlineAsmReg, PowerPCInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use s390x::{S390xInlineAsmReg, S390xInlineAsmRegClass}; +pub use sparc::{SparcInlineAsmReg, SparcInlineAsmRegClass}; pub use spirv::{SpirVInlineAsmReg, SpirVInlineAsmRegClass}; pub use wasm::{WasmInlineAsmReg, WasmInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -230,6 +232,8 @@ pub enum InlineAsmArch { PowerPC, PowerPC64, S390x, + Sparc, + Sparc64, SpirV, Wasm32, Wasm64, @@ -260,6 +264,8 @@ impl FromStr for InlineAsmArch { "mips" | "mips32r6" => Ok(Self::Mips), "mips64" | "mips64r6" => Ok(Self::Mips64), "s390x" => Ok(Self::S390x), + "sparc" => Ok(Self::Sparc), + "sparc64" => Ok(Self::Sparc64), "spirv" => Ok(Self::SpirV), "wasm32" => Ok(Self::Wasm32), "wasm64" => Ok(Self::Wasm64), @@ -286,6 +292,7 @@ pub enum InlineAsmReg { LoongArch(LoongArchInlineAsmReg), Mips(MipsInlineAsmReg), S390x(S390xInlineAsmReg), + Sparc(SparcInlineAsmReg), SpirV(SpirVInlineAsmReg), Wasm(WasmInlineAsmReg), Bpf(BpfInlineAsmReg), @@ -309,6 +316,7 @@ impl InlineAsmReg { Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), + Self::Sparc(r) => r.name(), Self::Bpf(r) => r.name(), Self::Avr(r) => r.name(), Self::Msp430(r) => r.name(), @@ -329,6 +337,7 @@ impl InlineAsmReg { Self::LoongArch(r) => InlineAsmRegClass::LoongArch(r.reg_class()), Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), Self::S390x(r) => InlineAsmRegClass::S390x(r.reg_class()), + Self::Sparc(r) => InlineAsmRegClass::Sparc(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()), @@ -361,6 +370,9 @@ impl InlineAsmReg { Self::Mips(MipsInlineAsmReg::parse(name)?) } InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse(name)?), + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + Self::Sparc(SparcInlineAsmReg::parse(name)?) + } InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse(name)?), InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { Self::Wasm(WasmInlineAsmReg::parse(name)?) @@ -393,6 +405,7 @@ impl InlineAsmReg { } Self::Mips(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), Self::S390x(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), + Self::Sparc(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::Msp430(r) => r.validate(arch, reloc_model, target_features, target, is_clobber), @@ -420,6 +433,7 @@ impl InlineAsmReg { Self::LoongArch(r) => r.emit(out, arch, modifier), Self::Mips(r) => r.emit(out, arch, modifier), Self::S390x(r) => r.emit(out, arch, modifier), + Self::Sparc(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), @@ -440,6 +454,7 @@ impl InlineAsmReg { Self::LoongArch(_) => cb(self), Self::Mips(_) => cb(self), Self::S390x(r) => r.overlapping_regs(|r| cb(Self::S390x(r))), + Self::Sparc(_) => 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), @@ -463,6 +478,7 @@ pub enum InlineAsmRegClass { LoongArch(LoongArchInlineAsmRegClass), Mips(MipsInlineAsmRegClass), S390x(S390xInlineAsmRegClass), + Sparc(SparcInlineAsmRegClass), SpirV(SpirVInlineAsmRegClass), Wasm(WasmInlineAsmRegClass), Bpf(BpfInlineAsmRegClass), @@ -487,6 +503,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.name(), Self::Mips(r) => r.name(), Self::S390x(r) => r.name(), + Self::Sparc(r) => r.name(), Self::SpirV(r) => r.name(), Self::Wasm(r) => r.name(), Self::Bpf(r) => r.name(), @@ -513,6 +530,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::LoongArch), Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), Self::S390x(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::S390x), + Self::Sparc(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Sparc), Self::SpirV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::SpirV), Self::Wasm(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Wasm), Self::Bpf(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Bpf), @@ -542,6 +560,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.suggest_modifier(arch, ty), Self::Mips(r) => r.suggest_modifier(arch, ty), Self::S390x(r) => r.suggest_modifier(arch, ty), + Self::Sparc(r) => r.suggest_modifier(arch, ty), Self::SpirV(r) => r.suggest_modifier(arch, ty), Self::Wasm(r) => r.suggest_modifier(arch, ty), Self::Bpf(r) => r.suggest_modifier(arch, ty), @@ -571,6 +590,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.default_modifier(arch), Self::Mips(r) => r.default_modifier(arch), Self::S390x(r) => r.default_modifier(arch), + Self::Sparc(r) => r.default_modifier(arch), Self::SpirV(r) => r.default_modifier(arch), Self::Wasm(r) => r.default_modifier(arch), Self::Bpf(r) => r.default_modifier(arch), @@ -599,6 +619,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.supported_types(arch), Self::Mips(r) => r.supported_types(arch), Self::S390x(r) => r.supported_types(arch), + Self::Sparc(r) => r.supported_types(arch), Self::SpirV(r) => r.supported_types(arch), Self::Wasm(r) => r.supported_types(arch), Self::Bpf(r) => r.supported_types(arch), @@ -632,6 +653,9 @@ impl InlineAsmRegClass { Self::Mips(MipsInlineAsmRegClass::parse(name)?) } InlineAsmArch::S390x => Self::S390x(S390xInlineAsmRegClass::parse(name)?), + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + Self::Sparc(SparcInlineAsmRegClass::parse(name)?) + } InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmRegClass::parse(name)?), InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { Self::Wasm(WasmInlineAsmRegClass::parse(name)?) @@ -658,6 +682,7 @@ impl InlineAsmRegClass { Self::LoongArch(r) => r.valid_modifiers(arch), Self::Mips(r) => r.valid_modifiers(arch), Self::S390x(r) => r.valid_modifiers(arch), + Self::Sparc(r) => r.valid_modifiers(arch), Self::SpirV(r) => r.valid_modifiers(arch), Self::Wasm(r) => r.valid_modifiers(arch), Self::Bpf(r) => r.valid_modifiers(arch), @@ -843,6 +868,11 @@ pub fn allocatable_registers( s390x::fill_reg_map(arch, reloc_model, target_features, target, &mut map); map } + InlineAsmArch::Sparc | InlineAsmArch::Sparc64 => { + let mut map = sparc::regclass_map(); + sparc::fill_reg_map(arch, reloc_model, target_features, target, &mut map); + map + } InlineAsmArch::SpirV => { let mut map = spirv::regclass_map(); spirv::fill_reg_map(arch, reloc_model, target_features, target, &mut map); diff --git a/compiler/rustc_target/src/asm/sparc.rs b/compiler/rustc_target/src/asm/sparc.rs new file mode 100644 index 00000000000..6261708642b --- /dev/null +++ b/compiler/rustc_target/src/asm/sparc.rs @@ -0,0 +1,138 @@ +use std::fmt; + +use rustc_data_structures::fx::FxIndexSet; +use rustc_span::Symbol; + +use super::{InlineAsmArch, InlineAsmType, ModifierInfo}; +use crate::spec::{RelocModel, Target}; + +def_reg_class! { + Sparc SparcInlineAsmRegClass { + reg, + yreg, + } +} + +impl SparcInlineAsmRegClass { + 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 => { + if arch == InlineAsmArch::Sparc { + types! { + _: I8, I16, I32; + // FIXME: i64 is ok for g*/o* registers on SPARC-V8+ ("h" constraint in GCC), + // but not yet supported in LLVM. + // v8plus: I64; + } + } else { + types! { _: I8, I16, I32, I64; } + } + } + Self::yreg => &[], + } + } +} + +fn reserved_g5( + arch: InlineAsmArch, + _reloc_model: RelocModel, + _target_features: &FxIndexSet<Symbol>, + _target: &Target, + _is_clobber: bool, +) -> Result<(), &'static str> { + if arch == InlineAsmArch::Sparc { + // FIXME: Section 2.1.5 "Function Registers with Unassigned Roles" of the V8+ Technical + // Specification says "%g5; no longer reserved for system software" [1], but LLVM always + // reserves it on SPARC32 [2]. + // [1]: https://temlib.org/pub/SparcStation/Standards/V8plus.pdf + // [2]: https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L64-L66 + Err("g5 is reserved for system on SPARC32") + } else { + Ok(()) + } +} + +def_regs! { + Sparc SparcInlineAsmReg SparcInlineAsmRegClass { + // FIXME: + // - LLVM has reserve-{g,o,l,i}N feature to reserve each general-purpose registers. + // - g2-g4 are reserved for application (optional in both LLVM and GCC, and GCC has -mno-app-regs option to reserve them). + // There are currently no builtin targets that use them, but in the future they may need to + // be supported via options similar to AArch64's -Z fixed-x18. + r2: reg = ["r2", "g2"], // % reserved_g2 + r3: reg = ["r3", "g3"], // % reserved_g3 + r4: reg = ["r4", "g4"], // % reserved_g4 + r5: reg = ["r5", "g5"] % reserved_g5, + r8: reg = ["r8", "o0"], // % reserved_o0 + r9: reg = ["r9", "o1"], // % reserved_o1 + r10: reg = ["r10", "o2"], // % reserved_o2 + r11: reg = ["r11", "o3"], // % reserved_o3 + r12: reg = ["r12", "o4"], // % reserved_o4 + r13: reg = ["r13", "o5"], // % reserved_o5 + r15: reg = ["r15", "o7"], // % reserved_o7 + r16: reg = ["r16", "l0"], // % reserved_l0 + r17: reg = ["r17", "l1"], // % reserved_l1 + r18: reg = ["r18", "l2"], // % reserved_l2 + r19: reg = ["r19", "l3"], // % reserved_l3 + r20: reg = ["r20", "l4"], // % reserved_l4 + r21: reg = ["r21", "l5"], // % reserved_l5 + r22: reg = ["r22", "l6"], // % reserved_l6 + r23: reg = ["r23", "l7"], // % reserved_l7 + r24: reg = ["r24", "i0"], // % reserved_i0 + r25: reg = ["r25", "i1"], // % reserved_i1 + r26: reg = ["r26", "i2"], // % reserved_i2 + r27: reg = ["r27", "i3"], // % reserved_i3 + r28: reg = ["r28", "i4"], // % reserved_i4 + r29: reg = ["r29", "i5"], // % reserved_i5 + y: yreg = ["y"], + #error = ["r0", "g0"] => + "g0 is always zero and cannot be used as an operand for inline asm", + // FIXME: %g1 is volatile in ABI, but used internally by LLVM. + // https://github.com/llvm/llvm-project/blob/llvmorg-19.1.0/llvm/lib/Target/Sparc/SparcRegisterInfo.cpp#L55-L56 + // > FIXME: G1 reserved for now for large imm generation by frame code. + #error = ["r1", "g1"] => + "reserved by LLVM and cannot be used as an operand for inline asm", + #error = ["r6", "g6", "r7", "g7"] => + "reserved for system and cannot be used as an operand for inline asm", + #error = ["sp", "r14", "o6"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["fp", "r30", "i6"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["r31", "i7"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl SparcInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option<char>, + ) -> fmt::Result { + write!(out, "%{}", self.name()) + } +} |
