Skip to content

Commit 81d2d3c

Browse files
authored
Rollup merge of #73588 - Amanieu:thumb-fp, r=nagisa
Fix handling of reserved registers for ARM inline asm `r6` is now disallowed as an operand since LLVM sometimes uses it as a base pointer. The check against using the frame pointer as an operand now takes the platform into account and will block either `r7` or `r11` as appropriate. Fixes #73450 cc @cbiffle
2 parents 25671fa + a98868d commit 81d2d3c

File tree

7 files changed

+73
-20
lines changed

7 files changed

+73
-20
lines changed

src/doc/unstable-book/src/library-features/asm.md

+6-2
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ Here is the list of currently supported register classes:
474474
| AArch64 | `reg` | `x[0-28]`, `x30` | `r` |
475475
| AArch64 | `vreg` | `v[0-31]` | `w` |
476476
| AArch64 | `vreg_low16` | `v[0-15]` | `x` |
477-
| ARM | `reg` | `r[0-r10]`, `r12`, `r14` | `r` |
477+
| ARM | `reg` | `r[0-5]` `r7`\*, `r[8-10]`, `r11`\*, `r12`, `r14` | `r` |
478478
| ARM (Thumb) | `reg_thumb` | `r[0-r7]` | `l` |
479479
| ARM (ARM) | `reg_thumb` | `r[0-r10]`, `r12`, `r14` | `l` |
480480
| ARM | `sreg` | `s[0-31]` | `t` |
@@ -497,6 +497,8 @@ Here is the list of currently supported register classes:
497497
> Note #2: On x86-64 the high byte registers (e.g. `ah`) are only available when used as an explicit register. Specifying the `reg_byte` register class for an operand will always allocate a low byte register.
498498
>
499499
> Note #3: NVPTX doesn't have a fixed register set, so named registers are not supported.
500+
>
501+
> Note #4: On ARM the frame pointer is either `r7` or `r11` depending on the platform.
500502
501503
Additional register classes may be added in the future based on demand (e.g. MMX, x87, etc).
502504

@@ -591,7 +593,9 @@ Some registers cannot be used for input or output operands:
591593
| Architecture | Unsupported register | Reason |
592594
| ------------ | -------------------- | ------ |
593595
| All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. |
594-
| All | `bp` (x86), `r11` (ARM), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
596+
| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. |
597+
| ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. |
598+
| ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. |
595599
| x86 | `k0` | This is a constant zero register which can't be modified. |
596600
| x86 | `ip` | This is the program counter, not a real register. |
597601
| x86 | `mm[0-7]` | MMX registers are not currently supported (but may be in the future). |

src/librustc_ast_lowering/expr.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1001,6 +1001,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
10011001
asm::InlineAsmReg::parse(
10021002
sess.asm_arch?,
10031003
|feature| sess.target_features.contains(&Symbol::intern(feature)),
1004+
&sess.target.target,
10041005
s,
10051006
)
10061007
.map_err(|e| {

src/librustc_codegen_llvm/llvm_util.rs

+4
Original file line numberDiff line numberDiff line change
@@ -156,6 +156,10 @@ const ARM_WHITELIST: &[(&str, Option<Symbol>)] = &[
156156
("vfp2", Some(sym::arm_target_feature)),
157157
("vfp3", Some(sym::arm_target_feature)),
158158
("vfp4", Some(sym::arm_target_feature)),
159+
// This is needed for inline assembly, but shouldn't be stabilized as-is
160+
// since it should be enabled per-function using #[instruction_set], not
161+
// #[target_feature].
162+
("thumb-mode", Some(sym::arm_target_feature)),
159163
];
160164

161165
const AARCH64_WHITELIST: &[(&str, Option<Symbol>)] = &[

src/librustc_target/asm/arm.rs

+36-4
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{InlineAsmArch, InlineAsmType};
2+
use crate::spec::Target;
23
use rustc_macros::HashStable_Generic;
34
use std::fmt;
45

@@ -58,6 +59,37 @@ impl ArmInlineAsmRegClass {
5859
}
5960
}
6061

62+
// This uses the same logic as useR7AsFramePointer in LLVM
63+
fn frame_pointer_is_r7(mut has_feature: impl FnMut(&str) -> bool, target: &Target) -> bool {
64+
target.options.is_like_osx || (!target.options.is_like_windows && has_feature("thumb-mode"))
65+
}
66+
67+
fn frame_pointer_r11(
68+
_arch: InlineAsmArch,
69+
has_feature: impl FnMut(&str) -> bool,
70+
target: &Target,
71+
_allocating: bool,
72+
) -> Result<(), &'static str> {
73+
if !frame_pointer_is_r7(has_feature, target) {
74+
Err("the frame pointer (r11) cannot be used as an operand for inline asm")
75+
} else {
76+
Ok(())
77+
}
78+
}
79+
80+
fn frame_pointer_r7(
81+
_arch: InlineAsmArch,
82+
has_feature: impl FnMut(&str) -> bool,
83+
target: &Target,
84+
_allocating: bool,
85+
) -> Result<(), &'static str> {
86+
if frame_pointer_is_r7(has_feature, target) {
87+
Err("the frame pointer (r7) cannot be used as an operand for inline asm")
88+
} else {
89+
Ok(())
90+
}
91+
}
92+
6193
def_regs! {
6294
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
6395
r0: reg, reg_thumb = ["r0", "a1"],
@@ -66,11 +98,11 @@ def_regs! {
6698
r3: reg, reg_thumb = ["r3", "a4"],
6799
r4: reg, reg_thumb = ["r4", "v1"],
68100
r5: reg, reg_thumb = ["r5", "v2"],
69-
r6: reg, reg_thumb = ["r6", "v3"],
70-
r7: reg, reg_thumb = ["r7", "v4"],
101+
r7: reg, reg_thumb = ["r7", "v4"] % frame_pointer_r7,
71102
r8: reg = ["r8", "v5"],
72103
r9: reg = ["r9", "v6", "rfp"],
73104
r10: reg = ["r10", "sl"],
105+
r11: reg = ["r11", "fp"] % frame_pointer_r11,
74106
r12: reg = ["r12", "ip"],
75107
r14: reg = ["r14", "lr"],
76108
s0: sreg, sreg_low16 = ["s0"],
@@ -153,8 +185,8 @@ def_regs! {
153185
q13: qreg = ["q13"],
154186
q14: qreg = ["q14"],
155187
q15: qreg = ["q15"],
156-
#error = ["r11", "fp"] =>
157-
"the frame pointer cannot be used as an operand for inline asm",
188+
#error = ["r6", "v3"] =>
189+
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
158190
#error = ["r13", "sp"] =>
159191
"the stack pointer cannot be used as an operand for inline asm",
160192
#error = ["r15", "pc"] =>

src/librustc_target/asm/mod.rs

+21-14
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use crate::abi::Size;
2+
use crate::spec::Target;
23
use rustc_data_structures::fx::{FxHashMap, FxHashSet};
34
use rustc_macros::HashStable_Generic;
45
use rustc_span::Symbol;
@@ -83,12 +84,13 @@ macro_rules! def_regs {
8384
pub fn parse(
8485
_arch: super::InlineAsmArch,
8586
mut _has_feature: impl FnMut(&str) -> bool,
87+
_target: &crate::spec::Target,
8688
name: &str,
8789
) -> Result<Self, &'static str> {
8890
match name {
8991
$(
9092
$($alias)|* | $reg_name => {
91-
$($filter(_arch, &mut _has_feature, false)?;)?
93+
$($filter(_arch, &mut _has_feature, _target, false)?;)?
9294
Ok(Self::$reg)
9395
}
9496
)*
@@ -103,6 +105,7 @@ macro_rules! def_regs {
103105
pub(super) fn fill_reg_map(
104106
_arch: super::InlineAsmArch,
105107
mut _has_feature: impl FnMut(&str) -> bool,
108+
_target: &crate::spec::Target,
106109
_map: &mut rustc_data_structures::fx::FxHashMap<
107110
super::InlineAsmRegClass,
108111
rustc_data_structures::fx::FxHashSet<super::InlineAsmReg>,
@@ -111,7 +114,7 @@ macro_rules! def_regs {
111114
#[allow(unused_imports)]
112115
use super::{InlineAsmReg, InlineAsmRegClass};
113116
$(
114-
if $($filter(_arch, &mut _has_feature, true).is_ok() &&)? true {
117+
if $($filter(_arch, &mut _has_feature, _target, true).is_ok() &&)? true {
115118
if let Some(set) = _map.get_mut(&InlineAsmRegClass::$arch($arch_regclass::$class)) {
116119
set.insert(InlineAsmReg::$arch($arch_reg::$reg));
117120
}
@@ -234,27 +237,30 @@ impl InlineAsmReg {
234237
pub fn parse(
235238
arch: InlineAsmArch,
236239
has_feature: impl FnMut(&str) -> bool,
240+
target: &Target,
237241
name: Symbol,
238242
) -> Result<Self, &'static str> {
239243
// FIXME: use direct symbol comparison for register names
240244
// Use `Symbol::as_str` instead of `Symbol::with` here because `has_feature` may access `Symbol`.
241245
let name = name.as_str();
242246
Ok(match arch {
243247
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
244-
Self::X86(X86InlineAsmReg::parse(arch, has_feature, &name)?)
248+
Self::X86(X86InlineAsmReg::parse(arch, has_feature, target, &name)?)
249+
}
250+
InlineAsmArch::Arm => {
251+
Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, target, &name)?)
245252
}
246-
InlineAsmArch::Arm => Self::Arm(ArmInlineAsmReg::parse(arch, has_feature, &name)?),
247253
InlineAsmArch::AArch64 => {
248-
Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, &name)?)
254+
Self::AArch64(AArch64InlineAsmReg::parse(arch, has_feature, target, &name)?)
249255
}
250256
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
251-
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, &name)?)
257+
Self::RiscV(RiscVInlineAsmReg::parse(arch, has_feature, target, &name)?)
252258
}
253259
InlineAsmArch::Nvptx64 => {
254-
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, &name)?)
260+
Self::Nvptx(NvptxInlineAsmReg::parse(arch, has_feature, target, &name)?)
255261
}
256262
InlineAsmArch::Hexagon => {
257-
Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, &name)?)
263+
Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?)
258264
}
259265
})
260266
}
@@ -536,36 +542,37 @@ impl fmt::Display for InlineAsmType {
536542
pub fn allocatable_registers(
537543
arch: InlineAsmArch,
538544
has_feature: impl FnMut(&str) -> bool,
545+
target: &crate::spec::Target,
539546
) -> FxHashMap<InlineAsmRegClass, FxHashSet<InlineAsmReg>> {
540547
match arch {
541548
InlineAsmArch::X86 | InlineAsmArch::X86_64 => {
542549
let mut map = x86::regclass_map();
543-
x86::fill_reg_map(arch, has_feature, &mut map);
550+
x86::fill_reg_map(arch, has_feature, target, &mut map);
544551
map
545552
}
546553
InlineAsmArch::Arm => {
547554
let mut map = arm::regclass_map();
548-
arm::fill_reg_map(arch, has_feature, &mut map);
555+
arm::fill_reg_map(arch, has_feature, target, &mut map);
549556
map
550557
}
551558
InlineAsmArch::AArch64 => {
552559
let mut map = aarch64::regclass_map();
553-
aarch64::fill_reg_map(arch, has_feature, &mut map);
560+
aarch64::fill_reg_map(arch, has_feature, target, &mut map);
554561
map
555562
}
556563
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {
557564
let mut map = riscv::regclass_map();
558-
riscv::fill_reg_map(arch, has_feature, &mut map);
565+
riscv::fill_reg_map(arch, has_feature, target, &mut map);
559566
map
560567
}
561568
InlineAsmArch::Nvptx64 => {
562569
let mut map = nvptx::regclass_map();
563-
nvptx::fill_reg_map(arch, has_feature, &mut map);
570+
nvptx::fill_reg_map(arch, has_feature, target, &mut map);
564571
map
565572
}
566573
InlineAsmArch::Hexagon => {
567574
let mut map = hexagon::regclass_map();
568-
hexagon::fill_reg_map(arch, has_feature, &mut map);
575+
hexagon::fill_reg_map(arch, has_feature, target, &mut map);
569576
map
570577
}
571578
}

src/librustc_target/asm/riscv.rs

+2
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{InlineAsmArch, InlineAsmType};
2+
use crate::spec::Target;
23
use rustc_macros::HashStable_Generic;
34
use std::fmt;
45

@@ -50,6 +51,7 @@ impl RiscVInlineAsmRegClass {
5051
fn not_e(
5152
_arch: InlineAsmArch,
5253
mut has_feature: impl FnMut(&str) -> bool,
54+
_target: &Target,
5355
_allocating: bool,
5456
) -> Result<(), &'static str> {
5557
if has_feature("e") {

src/librustc_target/asm/x86.rs

+3
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
use super::{InlineAsmArch, InlineAsmType};
2+
use crate::spec::Target;
23
use rustc_macros::HashStable_Generic;
34
use std::fmt;
45

@@ -131,6 +132,7 @@ impl X86InlineAsmRegClass {
131132
fn x86_64_only(
132133
arch: InlineAsmArch,
133134
_has_feature: impl FnMut(&str) -> bool,
135+
_target: &Target,
134136
_allocating: bool,
135137
) -> Result<(), &'static str> {
136138
match arch {
@@ -143,6 +145,7 @@ fn x86_64_only(
143145
fn high_byte(
144146
arch: InlineAsmArch,
145147
_has_feature: impl FnMut(&str) -> bool,
148+
_target: &Target,
146149
allocating: bool,
147150
) -> Result<(), &'static str> {
148151
match arch {

0 commit comments

Comments
 (0)