From 8d0e8820659fdf8473f7ff8f2fe0d234d16965d7 Mon Sep 17 00:00:00 2001 From: Amanieu d'Antras Date: Sun, 21 Jun 2020 15:34:18 +0100 Subject: [PATCH] Fix handling of reserved registers for ARM inline asm --- src/librustc_ast_lowering/expr.rs | 1 + src/librustc_codegen_llvm/llvm_util.rs | 4 +++ src/librustc_target/asm/arm.rs | 40 +++++++++++++++++++++++--- src/librustc_target/asm/mod.rs | 35 +++++++++++++--------- src/librustc_target/asm/riscv.rs | 2 ++ src/librustc_target/asm/x86.rs | 3 ++ 6 files changed, 67 insertions(+), 18 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index e59cacfffc926..23e0da4cf32a0 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -1004,6 +1004,7 @@ impl<'hir> LoweringContext<'_, 'hir> { asm::InlineAsmReg::parse( sess.asm_arch?, |feature| sess.target_features.contains(&Symbol::intern(feature)), + &sess.target.target, s, ) .map_err(|e| { diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/src/librustc_codegen_llvm/llvm_util.rs index 67a2251e8593e..80278bb9f53d8 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/src/librustc_codegen_llvm/llvm_util.rs @@ -156,6 +156,10 @@ const ARM_WHITELIST: &[(&str, Option)] = &[ ("vfp2", Some(sym::arm_target_feature)), ("vfp3", Some(sym::arm_target_feature)), ("vfp4", Some(sym::arm_target_feature)), + // This is needed for inline assembly, but shouldn't be stabilized as-is + // since it should be enabled per-function using #[instruction_set], not + // #[target_feature]. + ("thumb-mode", Some(sym::arm_target_feature)), ]; const AARCH64_WHITELIST: &[(&str, Option)] = &[ diff --git a/src/librustc_target/asm/arm.rs b/src/librustc_target/asm/arm.rs index 1798b2a094975..85a136b94aa79 100644 --- a/src/librustc_target/asm/arm.rs +++ b/src/librustc_target/asm/arm.rs @@ -1,4 +1,5 @@ use super::{InlineAsmArch, InlineAsmType}; +use crate::spec::Target; use rustc_macros::HashStable_Generic; use std::fmt; @@ -58,6 +59,37 @@ impl ArmInlineAsmRegClass { } } +// This uses the same logic as useR7AsFramePointer in LLVM +fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool { + target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode")) +} + +fn frame_pointer_r11( + _arch: InlineAsmArch, + has_feature: impl FnMut(&str) -> bool, + target: &Target, + _allocating: bool, +) -> Result<(), &'static str> { + if !frame_pointer_is_r7(has_feature, target) { + Err("the frame pointer (r11) cannot be used as an operand for inline asm") + } else { + Ok(()) + } +} + +fn frame_pointer_r7( + _arch: InlineAsmArch, + has_feature: impl FnMut(&str) -> bool, + target: &Target, + _allocating: bool, +) -> Result<(), &'static str> { + if frame_pointer_is_r7(has_feature, target) { + Err("the frame pointer (r7) cannot be used as an operand for inline asm") + } else { + Ok(()) + } +} + def_regs! { Arm ArmInlineAsmReg ArmInlineAsmRegClass { r0: reg, reg_thumb = ["r0", "a1"], @@ -66,11 +98,11 @@ def_regs! { r3: reg, reg_thumb = ["r3", "a4"], r4: reg, reg_thumb = ["r4", "v1"], r5: reg, reg_thumb = ["r5", "v2"], - r6: reg, reg_thumb = ["r6", "v3"], - r7: reg, reg_thumb = ["r7", "v4"], + r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7, r8: reg = ["r8", "v5"], r9: reg = ["r9", "v6", "rfp"], r10: reg = ["r10", "sl"], + r11: reg = ["r11", "fp"] % frame_pointer_r11, r12: reg = ["r12", "ip"], r14: reg = ["r14", "lr"], s0: sreg, sreg_low16 = ["s0"], @@ -153,8 +185,8 @@ def_regs! { q13: qreg = ["q13"], q14: qreg = ["q14"], q15: qreg = ["q15"], - #error = ["r11", "fp"] => - "the frame pointer cannot be used as an operand for inline asm", + #error = ["r6", "v3"] => + "r6 is used internally by LLVM and cannot be used as an operand for inline asm", #error = ["r13", "sp"] => "the stack pointer cannot be used as an operand for inline asm", #error = ["r15", "pc"] => diff --git a/src/librustc_target/asm/mod.rs b/src/librustc_target/asm/mod.rs index 834d7c6d381a3..ccec17817d37d 100644 --- a/src/librustc_target/asm/mod.rs +++ b/src/librustc_target/asm/mod.rs @@ -1,4 +1,5 @@ use crate::abi::Size; +use crate::spec::Target; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_macros::HashStable_Generic; use rustc_span::Symbol; @@ -83,12 +84,13 @@ macro_rules! def_regs { pub fn parse( _arch: super::InlineAsmArch, mut _has_feature: impl FnMut(&str) -> bool, + _target: &crate::spec::Target, name: &str, ) -> Result { match name { $( $($alias)|* | $reg_name => { - $($filter(_arch, &mut _has_feature, false)?;)? + $($filter(_arch, &mut _has_feature, _target, false)?;)? Ok(Self::$reg) } )* @@ -103,6 +105,7 @@ macro_rules! def_regs { pub(super) fn fill_reg_map( _arch: super::InlineAsmArch, mut _has_feature: impl FnMut(&str) -> bool, + _target: &crate::spec::Target, _map: &mut rustc_data_structures::fx::FxHashMap< super::InlineAsmRegClass, rustc_data_structures::fx::FxHashSet, @@ -111,7 +114,7 @@ macro_rules! def_regs { #[allow(unused_imports)] use super::{InlineAsmReg, InlineAsmRegClass}; $( - if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true { + if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true { if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) { set.insert(InlineAsmReg::$arch($arch_reg::$reg)); } @@ -234,6 +237,7 @@ impl InlineAsmReg { pub fn parse( arch: InlineAsmArch, has_feature: impl FnMut(&str) -> bool, + target: &Target, name: Symbol, ) -> Result { // FIXME: use direct symbol comparison for register names @@ -241,20 +245,22 @@ impl InlineAsmReg { let name = name.as_str(); Ok(match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { - Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?) + Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?) + } + InlineAsmArch::Arm => { + Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?) } - InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?), InlineAsmArch::AArch64 => { - Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?) + Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?) } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { - Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?) + Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?) } InlineAsmArch::Nvptx64 => { - Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?) + Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?) } InlineAsmArch::Hexagon => { - Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?) + Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } }) } @@ -536,36 +542,37 @@ impl fmt::Display for InlineAsmType { pub fn allocatable_registers( arch: InlineAsmArch, has_feature: impl FnMut(&str) -> bool, + target: &crate::spec::Target, ) -> FxHashMap> { match arch { InlineAsmArch::X86 | InlineAsmArch::X86_64 => { let mut map = x86::regclass_map(); - x86::fill_reg_map(arch, has_feature, &mut map); + x86::fill_reg_map(arch, has_feature, target, &mut map); map } InlineAsmArch::Arm => { let mut map = arm::regclass_map(); - arm::fill_reg_map(arch, has_feature, &mut map); + arm::fill_reg_map(arch, has_feature, target, &mut map); map } InlineAsmArch::AArch64 => { let mut map = aarch64::regclass_map(); - aarch64::fill_reg_map(arch, has_feature, &mut map); + aarch64::fill_reg_map(arch, has_feature, target, &mut map); map } InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { let mut map = riscv::regclass_map(); - riscv::fill_reg_map(arch, has_feature, &mut map); + riscv::fill_reg_map(arch, has_feature, target, &mut map); map } InlineAsmArch::Nvptx64 => { let mut map = nvptx::regclass_map(); - nvptx::fill_reg_map(arch, has_feature, &mut map); + nvptx::fill_reg_map(arch, has_feature, target, &mut map); map } InlineAsmArch::Hexagon => { let mut map = hexagon::regclass_map(); - hexagon::fill_reg_map(arch, has_feature, &mut map); + hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } } diff --git a/src/librustc_target/asm/riscv.rs b/src/librustc_target/asm/riscv.rs index 3ff542247ff02..ced7483b00571 100644 --- a/src/librustc_target/asm/riscv.rs +++ b/src/librustc_target/asm/riscv.rs @@ -1,4 +1,5 @@ use super::{InlineAsmArch, InlineAsmType}; +use crate::spec::Target; use rustc_macros::HashStable_Generic; use std::fmt; @@ -50,6 +51,7 @@ impl RiscVInlineAsmRegClass { fn not_e( _arch: InlineAsmArch, mut has_feature: impl FnMut(&str) -> bool, + _target: &Target, _allocating: bool, ) -> Result<(), &'static str> { if has_feature("e") { diff --git a/src/librustc_target/asm/x86.rs b/src/librustc_target/asm/x86.rs index ed51b526414d1..0f62c19e1a3cd 100644 --- a/src/librustc_target/asm/x86.rs +++ b/src/librustc_target/asm/x86.rs @@ -1,4 +1,5 @@ use super::{InlineAsmArch, InlineAsmType}; +use crate::spec::Target; use rustc_macros::HashStable_Generic; use std::fmt; @@ -131,6 +132,7 @@ impl X86InlineAsmRegClass { fn x86_64_only( arch: InlineAsmArch, _has_feature: impl FnMut(&str) -> bool, + _target: &Target, _allocating: bool, ) -> Result<(), &'static str> { match arch { @@ -143,6 +145,7 @@ fn x86_64_only( fn high_byte( arch: InlineAsmArch, _has_feature: impl FnMut(&str) -> bool, + _target: &Target, allocating: bool, ) -> Result<(), &'static str> { match arch {