diff --git a/compiler/rustc_ast_lowering/src/asm.rs b/compiler/rustc_ast_lowering/src/asm.rs index 5a85356d96d..18fcc99ffba 100644 --- a/compiler/rustc_ast_lowering/src/asm.rs +++ b/compiler/rustc_ast_lowering/src/asm.rs @@ -129,13 +129,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { .operands .iter() .map(|(op, op_sp)| { - let lower_reg = |reg| match reg { + let lower_reg = |reg, is_clobber| match reg { InlineAsmRegOrRegClass::Reg(s) => { asm::InlineAsmRegOrRegClass::Reg(if let Some(asm_arch) = asm_arch { asm::InlineAsmReg::parse( asm_arch, &sess.target_features, &sess.target, + is_clobber, s, ) .unwrap_or_else(|e| { @@ -162,24 +163,24 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let op = match *op { InlineAsmOperand::In { reg, ref expr } => hir::InlineAsmOperand::In { - reg: lower_reg(reg), + reg: lower_reg(reg, false), expr: self.lower_expr_mut(expr), }, InlineAsmOperand::Out { reg, late, ref expr } => hir::InlineAsmOperand::Out { - reg: lower_reg(reg), + reg: lower_reg(reg, expr.is_none()), late, expr: expr.as_ref().map(|expr| self.lower_expr_mut(expr)), }, InlineAsmOperand::InOut { reg, late, ref expr } => { hir::InlineAsmOperand::InOut { - reg: lower_reg(reg), + reg: lower_reg(reg, false), late, expr: self.lower_expr_mut(expr), } } InlineAsmOperand::SplitInOut { reg, late, ref in_expr, ref out_expr } => { hir::InlineAsmOperand::SplitInOut { - reg: lower_reg(reg), + reg: lower_reg(reg, false), late, in_expr: self.lower_expr_mut(in_expr), out_expr: out_expr.as_ref().map(|expr| self.lower_expr_mut(expr)), diff --git a/compiler/rustc_target/src/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs index da875508676..d184ad4e78a 100644 --- a/compiler/rustc_target/src/asm/aarch64.rs +++ b/compiler/rustc_target/src/asm/aarch64.rs @@ -77,6 +77,7 @@ pub fn reserved_x18( _arch: InlineAsmArch, _target_features: &FxHashSet, target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if target.os == "android" || target.is_like_fuchsia diff --git a/compiler/rustc_target/src/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs index e3615b43c70..b2d5bb3736a 100644 --- a/compiler/rustc_target/src/asm/arm.rs +++ b/compiler/rustc_target/src/asm/arm.rs @@ -66,10 +66,13 @@ fn frame_pointer_is_r7(target_features: &FxHashSet, target: &Target) -> } fn frame_pointer_r11( - _arch: InlineAsmArch, + arch: InlineAsmArch, target_features: &FxHashSet, target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { + not_thumb1(arch, target_features, target, is_clobber)?; + if !frame_pointer_is_r7(target_features, target) { Err("the frame pointer (r11) cannot be used as an operand for inline asm") } else { @@ -81,6 +84,7 @@ fn frame_pointer_r7( _arch: InlineAsmArch, target_features: &FxHashSet, target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if frame_pointer_is_r7(target_features, target) { Err("the frame pointer (r7) cannot be used as an operand for inline asm") @@ -93,9 +97,13 @@ fn not_thumb1( _arch: InlineAsmArch, target_features: &FxHashSet, _target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { - if target_features.contains(&sym::thumb_mode) && !target_features.contains(&sym::thumb2) { - Err("high registers (r8+) cannot be used in Thumb-1 code") + if !is_clobber + && target_features.contains(&sym::thumb_mode) + && !target_features.contains(&sym::thumb2) + { + Err("high registers (r8+) can only be used as clobbers in Thumb-1 code") } else { Ok(()) } @@ -105,8 +113,9 @@ fn reserved_r9( arch: InlineAsmArch, target_features: &FxHashSet, target: &Target, + is_clobber: bool, ) -> Result<(), &'static str> { - not_thumb1(arch, target_features, target)?; + not_thumb1(arch, target_features, target, is_clobber)?; // We detect this using the reserved-r9 feature instead of using the target // because the relocation model can be changed with compiler options. diff --git a/compiler/rustc_target/src/asm/bpf.rs b/compiler/rustc_target/src/asm/bpf.rs index d94fcb53e24..b4d982f3836 100644 --- a/compiler/rustc_target/src/asm/bpf.rs +++ b/compiler/rustc_target/src/asm/bpf.rs @@ -47,6 +47,7 @@ fn only_alu32( _arch: InlineAsmArch, target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if !target_features.contains(&sym::alu32) { Err("register can't be used without the `alu32` target feature") diff --git a/compiler/rustc_target/src/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs index a84410d0f3c..fd95b0338a6 100644 --- a/compiler/rustc_target/src/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -83,12 +83,13 @@ pub fn parse( _arch: super::InlineAsmArch, _target_features: &rustc_data_structures::fx::FxHashSet, _target: &crate::spec::Target, + _is_clobber: bool, name: &str, ) -> Result { match name { $( $($alias)|* | $reg_name => { - $($filter(_arch, _target_features, _target)?;)? + $($filter(_arch, _target_features, _target, _is_clobber)?;)? Ok(Self::$reg) } )* @@ -112,7 +113,7 @@ pub(super) fn fill_reg_map( #[allow(unused_imports)] use super::{InlineAsmReg, InlineAsmRegClass}; $( - if $($filter(_arch, _target_features, _target).is_ok() &&)? true { + if $($filter(_arch, _target_features, _target, false).is_ok() &&)? true { if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { set.insert(InlineAsmReg::$arch($arch_reg::$reg)); } @@ -298,6 +299,7 @@ pub fn parse( arch: InlineAsmArch, target_features: &FxHashSet, target: &Target, + is_clobber: bool, name: Symbol, ) -> Result { // FIXME: use direct symbol comparison for register names @@ -305,47 +307,79 @@ pub fn parse( let name = name.as_str(); Ok(match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmReg::parse(arch, target_features, target, name)?) + Self::X86(X86InlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } InlineAsmArch::Arm => { - Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Nvptx64 => { - Self::Nvptx(NvptxInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => { - Self::PowerPC(PowerPCInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Hexagon => { - Self::Hexagon(HexagonInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Mips | InlineAsmArch::Mips64 => { - Self::Mips(MipsInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::S390x => { - Self::S390x(S390xInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::SpirV => { - Self::SpirV(SpirVInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => { - Self::Wasm(WasmInlineAsmReg::parse(arch, target_features, target, name)?) + Self::Arm(ArmInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } + InlineAsmArch::AArch64 => Self::AArch64(AArch64InlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => Self::RiscV( + RiscVInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?, + ), + InlineAsmArch::Nvptx64 => Self::Nvptx(NvptxInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::PowerPC | InlineAsmArch::PowerPC64 => Self::PowerPC( + PowerPCInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?, + ), + InlineAsmArch::Hexagon => Self::Hexagon(HexagonInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::Mips | InlineAsmArch::Mips64 => Self::Mips(MipsInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::S390x => Self::S390x(S390xInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::SpirV => Self::SpirV(SpirVInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), + InlineAsmArch::Wasm32 | InlineAsmArch::Wasm64 => Self::Wasm(WasmInlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), InlineAsmArch::Bpf => { - Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, name)?) + Self::Bpf(BpfInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } InlineAsmArch::Avr => { - Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, name)?) - } - InlineAsmArch::Msp430 => { - Self::Msp430(Msp430InlineAsmReg::parse(arch, target_features, target, name)?) + Self::Avr(AvrInlineAsmReg::parse(arch, target_features, target, is_clobber, name)?) } + InlineAsmArch::Msp430 => Self::Msp430(Msp430InlineAsmReg::parse( + arch, + target_features, + target, + is_clobber, + name, + )?), }) } @@ -844,7 +878,7 @@ pub fn parse( }, InlineAsmArch::AArch64 => match name { "C" | "system" | "efiapi" => { - Ok(if aarch64::reserved_x18(arch, target_features, target).is_err() { + Ok(if aarch64::reserved_x18(arch, target_features, target, true).is_err() { InlineAsmClobberAbi::AArch64NoX18 } else { InlineAsmClobberAbi::AArch64 diff --git a/compiler/rustc_target/src/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs index 39644d232ba..e145ba8a16e 100644 --- a/compiler/rustc_target/src/asm/riscv.rs +++ b/compiler/rustc_target/src/asm/riscv.rs @@ -56,6 +56,7 @@ fn not_e( _arch: InlineAsmArch, target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { if target_features.contains(&sym::e) { Err("register can't be used with the `e` target feature") diff --git a/compiler/rustc_target/src/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs index 01d32570f78..a8ee80ec4ea 100644 --- a/compiler/rustc_target/src/asm/x86.rs +++ b/compiler/rustc_target/src/asm/x86.rs @@ -141,6 +141,7 @@ fn x86_64_only( arch: InlineAsmArch, _target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => Err("register is only available on x86_64"), @@ -153,6 +154,7 @@ fn high_byte( arch: InlineAsmArch, _target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86_64 => Err("high byte registers cannot be used as an operand on x86_64"), @@ -164,6 +166,7 @@ fn rbx_reserved( arch: InlineAsmArch, _target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => Ok(()), @@ -178,6 +181,7 @@ fn esi_reserved( arch: InlineAsmArch, _target_features: &FxHashSet, _target: &Target, + _is_clobber: bool, ) -> Result<(), &'static str> { match arch { InlineAsmArch::X86 => {