1
Fork 0

Fix handling of reserved registers for ARM inline asm

This commit is contained in:
Amanieu d'Antras 2020-06-21 15:34:18 +01:00
parent 7adbc0dfef
commit 8d0e882065
6 changed files with 67 additions and 18 deletions

View file

@ -1004,6 +1004,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
asm::InlineAsmReg::parse( asm::InlineAsmReg::parse(
sess.asm_arch?, sess.asm_arch?,
|feature| sess.target_features.contains(&Symbol::intern(feature)), |feature| sess.target_features.contains(&Symbol::intern(feature)),
&sess.target.target,
s, s,
) )
.map_err(|e| { .map_err(|e| {

View file

@ -156,6 +156,10 @@ const ARM_WHITELIST: &[(&str, Option<Symbol>)] = &[
("vfp2", Some(sym::arm_target_feature)), ("vfp2", Some(sym::arm_target_feature)),
("vfp3", Some(sym::arm_target_feature)), ("vfp3", Some(sym::arm_target_feature)),
("vfp4", 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<Symbol>)] = &[ const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[

View file

@ -1,4 +1,5 @@
use super::{InlineAsmArch, InlineAsmType}; use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use std::fmt; 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! { def_regs! {
Arm ArmInlineAsmReg ArmInlineAsmRegClass { Arm ArmInlineAsmReg ArmInlineAsmRegClass {
r0: reg, reg_thumb = ["r0", "a1"], r0: reg, reg_thumb = ["r0", "a1"],
@ -66,11 +98,11 @@ def_regs! {
r3: reg, reg_thumb = ["r3", "a4"], r3: reg, reg_thumb = ["r3", "a4"],
r4: reg, reg_thumb = ["r4", "v1"], r4: reg, reg_thumb = ["r4", "v1"],
r5: reg, reg_thumb = ["r5", "v2"], r5: reg, reg_thumb = ["r5", "v2"],
r6: reg, reg_thumb = ["r6", "v3"], r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
r7: reg, reg_thumb = ["r7", "v4"],
r8: reg = ["r8", "v5"], r8: reg = ["r8", "v5"],
r9: reg = ["r9", "v6", "rfp"], r9: reg = ["r9", "v6", "rfp"],
r10: reg = ["r10", "sl"], r10: reg = ["r10", "sl"],
r11: reg = ["r11", "fp"] % frame_pointer_r11,
r12: reg = ["r12", "ip"], r12: reg = ["r12", "ip"],
r14: reg = ["r14", "lr"], r14: reg = ["r14", "lr"],
s0: sreg, sreg_low16 = ["s0"], s0: sreg, sreg_low16 = ["s0"],
@ -153,8 +185,8 @@ def_regs! {
q13: qreg = ["q13"], q13: qreg = ["q13"],
q14: qreg = ["q14"], q14: qreg = ["q14"],
q15: qreg = ["q15"], q15: qreg = ["q15"],
#error = ["r11", "fp"] => #error = ["r6", "v3"] =>
"the frame pointer cannot be used as an operand for inline asm", "r6 is used internally by LLVM and cannot be used as an operand for inline asm",
#error = ["r13", "sp"] => #error = ["r13", "sp"] =>
"the stack pointer cannot be used as an operand for inline asm", "the stack pointer cannot be used as an operand for inline asm",
#error = ["r15", "pc"] => #error = ["r15", "pc"] =>

View file

@ -1,4 +1,5 @@
use crate::abi::Size; use crate::abi::Size;
use crate::spec::Target;
use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::fx::{FxHashMap, FxHashSet};
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use rustc_span::Symbol; use rustc_span::Symbol;
@ -83,12 +84,13 @@ macro_rules! def_regs {
pub fn parse( pub fn parse(
_arch: super::InlineAsmArch, _arch: super::InlineAsmArch,
mut _has_feature: impl FnMut(&str) -> bool, mut _has_feature: impl FnMut(&str) -> bool,
_target: &crate::spec::Target,
name: &str, name: &str,
) -> Result<Self, &'static str> { ) -> Result<Self, &'static str> {
match name { match name {
$( $(
$($alias)|* | $reg_name => { $($alias)|* | $reg_name => {
$($filter(_arch, &mut _has_feature, false)?;)? $($filter(_arch, &mut _has_feature, _target, false)?;)?
Ok(Self::$reg) Ok(Self::$reg)
} }
)* )*
@ -103,6 +105,7 @@ macro_rules! def_regs {
pub(super) fn fill_reg_map( pub(super) fn fill_reg_map(
_arch: super::InlineAsmArch, _arch: super::InlineAsmArch,
mut _has_feature: impl FnMut(&str) -> bool, mut _has_feature: impl FnMut(&str) -> bool,
_target: &crate::spec::Target,
_map: &mut rustc_data_structures::fx::FxHashMap< _map: &mut rustc_data_structures::fx::FxHashMap<
super::InlineAsmRegClass, super::InlineAsmRegClass,
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>, rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
@ -111,7 +114,7 @@ macro_rules! def_regs {
#[allow(unused_imports)] #[allow(unused_imports)]
use super::{InlineAsmReg, InlineAsmRegClass}; 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)) { if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
set.insert(InlineAsmReg::$arch($arch_reg::$reg)); set.insert(InlineAsmReg::$arch($arch_reg::$reg));
} }
@ -234,6 +237,7 @@ impl InlineAsmReg {
pub fn parse( pub fn parse(
arch: InlineAsmArch, arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool, has_feature: impl FnMut(&str) -> bool,
target: &Target,
name: Symbol, name: Symbol,
) -> Result<Self, &'static str> { ) -> Result<Self, &'static str> {
// FIXME: use direct symbol comparison for register names // FIXME: use direct symbol comparison for register names
@ -241,20 +245,22 @@ impl InlineAsmReg {
let name = name.as_str(); let name = name.as_str();
Ok(match arch { Ok(match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => { 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 => { InlineAsmArch::AArch64 => {
Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?) Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
} }
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?) Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
} }
InlineAsmArch::Nvptx64 => { InlineAsmArch::Nvptx64 => {
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?) Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
} }
InlineAsmArch::Hexagon => { 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( pub fn allocatable_registers(
arch: InlineAsmArch, arch: InlineAsmArch,
has_feature: impl FnMut(&str) -> bool, has_feature: impl FnMut(&str) -> bool,
target: &crate::spec::Target,
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> { ) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
match arch { match arch {
InlineAsmArch::X86 | InlineAsmArch::X86_64 => { InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
let mut map = x86::regclass_map(); 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 map
} }
InlineAsmArch::Arm => { InlineAsmArch::Arm => {
let mut map = arm::regclass_map(); 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 map
} }
InlineAsmArch::AArch64 => { InlineAsmArch::AArch64 => {
let mut map = aarch64::regclass_map(); 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 map
} }
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
let mut map = riscv::regclass_map(); 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 map
} }
InlineAsmArch::Nvptx64 => { InlineAsmArch::Nvptx64 => {
let mut map = nvptx::regclass_map(); 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 map
} }
InlineAsmArch::Hexagon => { InlineAsmArch::Hexagon => {
let mut map = hexagon::regclass_map(); 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 map
} }
} }

View file

@ -1,4 +1,5 @@
use super::{InlineAsmArch, InlineAsmType}; use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use std::fmt; use std::fmt;
@ -50,6 +51,7 @@ impl RiscVInlineAsmRegClass {
fn not_e( fn not_e(
_arch: InlineAsmArch, _arch: InlineAsmArch,
mut has_feature: impl FnMut(&str) -> bool, mut has_feature: impl FnMut(&str) -> bool,
_target: &Target,
_allocating: bool, _allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
if has_feature("e") { if has_feature("e") {

View file

@ -1,4 +1,5 @@
use super::{InlineAsmArch, InlineAsmType}; use super::{InlineAsmArch, InlineAsmType};
use crate::spec::Target;
use rustc_macros::HashStable_Generic; use rustc_macros::HashStable_Generic;
use std::fmt; use std::fmt;
@ -131,6 +132,7 @@ impl X86InlineAsmRegClass {
fn x86_64_only( fn x86_64_only(
arch: InlineAsmArch, arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool, _has_feature: impl FnMut(&str) -> bool,
_target: &Target,
_allocating: bool, _allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
match arch { match arch {
@ -143,6 +145,7 @@ fn x86_64_only(
fn high_byte( fn high_byte(
arch: InlineAsmArch, arch: InlineAsmArch,
_has_feature: impl FnMut(&str) -> bool, _has_feature: impl FnMut(&str) -> bool,
_target: &Target,
allocating: bool, allocating: bool,
) -> Result<(), &'static str> { ) -> Result<(), &'static str> {
match arch { match arch {