Skip to content

Commit 443ed7c

Browse files
authored
Rollup merge of #91643 - Amanieu:r9x18, r=joshtriplett
asm: Allow using r9 (ARM) and x18 (AArch64) if they are not reserved by the current target This supersedes #88879. cc `@Skirmisher` r? `@joshtriplett`
2 parents 9383a49 + 17766f8 commit 443ed7c

File tree

7 files changed

+83
-28
lines changed

7 files changed

+83
-28
lines changed

compiler/rustc_ast_lowering/src/asm.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,12 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> {
6464
let mut clobber_abis = FxHashMap::default();
6565
if let Some(asm_arch) = asm_arch {
6666
for (abi_name, abi_span) in &asm.clobber_abis {
67-
match asm::InlineAsmClobberAbi::parse(asm_arch, &self.sess.target, *abi_name) {
67+
match asm::InlineAsmClobberAbi::parse(
68+
asm_arch,
69+
|feature| self.sess.target_features.contains(&Symbol::intern(feature)),
70+
&self.sess.target,
71+
*abi_name,
72+
) {
6873
Ok(abi) => {
6974
// If the abi was already in the list, emit an error
7075
match clobber_abis.get(&abi) {

compiler/rustc_codegen_ssa/src/target_features.rs

+1
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,7 @@ const ARM_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[
3636
// #[target_feature].
3737
("thumb-mode", Some(sym::arm_target_feature)),
3838
("thumb2", Some(sym::arm_target_feature)),
39+
("reserve-r9", Some(sym::arm_target_feature)),
3940
];
4041

4142
const AARCH64_ALLOWED_FEATURES: &[(&str, Option<Symbol>)] = &[

compiler/rustc_target/src/asm/aarch64.rs

+18-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

@@ -70,6 +71,22 @@ impl AArch64InlineAsmRegClass {
7071
}
7172
}
7273

74+
pub fn reserved_x18(
75+
_arch: InlineAsmArch,
76+
_has_feature: impl FnMut(&str) -> bool,
77+
target: &Target,
78+
) -> Result<(), &'static str> {
79+
if target.os == "android"
80+
|| target.is_like_fuchsia
81+
|| target.is_like_osx
82+
|| target.is_like_windows
83+
{
84+
Err("x18 is a reserved register on this target")
85+
} else {
86+
Ok(())
87+
}
88+
}
89+
7390
def_regs! {
7491
AArch64 AArch64InlineAsmReg AArch64InlineAsmRegClass {
7592
x0: reg = ["x0", "w0"],
@@ -90,6 +107,7 @@ def_regs! {
90107
x15: reg = ["x15", "w15"],
91108
x16: reg = ["x16", "w16"],
92109
x17: reg = ["x17", "w17"],
110+
x18: reg = ["x18", "w18"] % reserved_x18,
93111
x20: reg = ["x20", "w20"],
94112
x21: reg = ["x21", "w21"],
95113
x22: reg = ["x22", "w22"],
@@ -149,8 +167,6 @@ def_regs! {
149167
p14: preg = ["p14"],
150168
p15: preg = ["p15"],
151169
ffr: preg = ["ffr"],
152-
#error = ["x18", "w18"] =>
153-
"x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm",
154170
#error = ["x19", "w19"] =>
155171
"x19 is used internally by LLVM and cannot be used as an operand for inline asm",
156172
#error = ["x29", "w29", "fp", "wfp"] =>

compiler/rustc_target/src/asm/arm.rs

+17-2
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,22 @@ fn not_thumb1(
9999
}
100100
}
101101

102+
fn reserved_r9(
103+
arch: InlineAsmArch,
104+
mut has_feature: impl FnMut(&str) -> bool,
105+
target: &Target,
106+
) -> Result<(), &'static str> {
107+
not_thumb1(arch, &mut has_feature, target)?;
108+
109+
// We detect this using the reserved-r9 feature instead of using the target
110+
// because the relocation model can be changed with compiler options.
111+
if has_feature("reserved-r9") {
112+
Err("the RWPI static base register (r9) cannot be used as an operand for inline asm")
113+
} else {
114+
Ok(())
115+
}
116+
}
117+
102118
def_regs! {
103119
Arm ArmInlineAsmReg ArmInlineAsmRegClass {
104120
r0: reg = ["r0", "a1"],
@@ -109,6 +125,7 @@ def_regs! {
109125
r5: reg = ["r5", "v2"],
110126
r7: reg = ["r7", "v4"] % frame_pointer_r7,
111127
r8: reg = ["r8", "v5"] % not_thumb1,
128+
r9: reg = ["r9", "v6", "rfp"] % reserved_r9,
112129
r10: reg = ["r10", "sl"] % not_thumb1,
113130
r11: reg = ["r11", "fp"] % frame_pointer_r11,
114131
r12: reg = ["r12", "ip"] % not_thumb1,
@@ -195,8 +212,6 @@ def_regs! {
195212
q15: qreg = ["q15"],
196213
#error = ["r6", "v3"] =>
197214
"r6 is used internally by LLVM and cannot be used as an operand for inline asm",
198-
#error = ["r9", "v6", "rfp"] =>
199-
"r9 is used internally by LLVM and cannot be used as an operand for inline asm",
200215
#error = ["r13", "sp"] =>
201216
"the stack pointer cannot be used as an operand for inline asm",
202217
#error = ["r15", "pc"] =>

compiler/rustc_target/src/asm/mod.rs

+30-4
Original file line numberDiff line numberDiff line change
@@ -785,6 +785,7 @@ pub enum InlineAsmClobberAbi {
785785
X86_64SysV,
786786
Arm,
787787
AArch64,
788+
AArch64NoX18,
788789
RiscV,
789790
}
790791

@@ -793,6 +794,7 @@ impl InlineAsmClobberAbi {
793794
/// clobber ABIs for the target.
794795
pub fn parse(
795796
arch: InlineAsmArch,
797+
has_feature: impl FnMut(&str) -> bool,
796798
target: &Target,
797799
name: Symbol,
798800
) -> Result<Self, &'static [&'static str]> {
@@ -816,7 +818,13 @@ impl InlineAsmClobberAbi {
816818
_ => Err(&["C", "system", "efiapi", "aapcs"]),
817819
},
818820
InlineAsmArch::AArch64 => match name {
819-
"C" | "system" | "efiapi" => Ok(InlineAsmClobberAbi::AArch64),
821+
"C" | "system" | "efiapi" => {
822+
Ok(if aarch64::reserved_x18(arch, has_feature, target).is_err() {
823+
InlineAsmClobberAbi::AArch64NoX18
824+
} else {
825+
InlineAsmClobberAbi::AArch64
826+
})
827+
}
820828
_ => Err(&["C", "system", "efiapi"]),
821829
},
822830
InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => match name {
@@ -891,8 +899,25 @@ impl InlineAsmClobberAbi {
891899
AArch64 AArch64InlineAsmReg {
892900
x0, x1, x2, x3, x4, x5, x6, x7,
893901
x8, x9, x10, x11, x12, x13, x14, x15,
894-
// x18 is platform-reserved or temporary, but we exclude it
895-
// here since it is a reserved register.
902+
x16, x17, x18, x30,
903+
904+
// Technically the low 64 bits of v8-v15 are preserved, but
905+
// we have no way of expressing this using clobbers.
906+
v0, v1, v2, v3, v4, v5, v6, v7,
907+
v8, v9, v10, v11, v12, v13, v14, v15,
908+
v16, v17, v18, v19, v20, v21, v22, v23,
909+
v24, v25, v26, v27, v28, v29, v30, v31,
910+
911+
p0, p1, p2, p3, p4, p5, p6, p7,
912+
p8, p9, p10, p11, p12, p13, p14, p15,
913+
ffr,
914+
915+
}
916+
},
917+
InlineAsmClobberAbi::AArch64NoX18 => clobbered_regs! {
918+
AArch64 AArch64InlineAsmReg {
919+
x0, x1, x2, x3, x4, x5, x6, x7,
920+
x8, x9, x10, x11, x12, x13, x14, x15,
896921
x16, x17, x30,
897922

898923
// Technically the low 64 bits of v8-v15 are preserved, but
@@ -910,7 +935,8 @@ impl InlineAsmClobberAbi {
910935
},
911936
InlineAsmClobberAbi::Arm => clobbered_regs! {
912937
Arm ArmInlineAsmReg {
913-
// r9 is platform-reserved and is treated as callee-saved.
938+
// r9 is either platform-reserved or callee-saved. Either
939+
// way we don't need to clobber it.
914940
r0, r1, r2, r3, r12, r14,
915941

916942
// The finest-grained register variant is used here so that

src/test/ui/asm/aarch64/bad-reg.rs

-2
Original file line numberDiff line numberDiff line change
@@ -29,8 +29,6 @@ fn main() {
2929
//~^ ERROR invalid register `sp`: the stack pointer cannot be used as an operand
3030
asm!("", in("xzr") foo);
3131
//~^ ERROR invalid register `xzr`: the zero register cannot be used as an operand
32-
asm!("", in("x18") foo);
33-
//~^ ERROR invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
3432
asm!("", in("x19") foo);
3533
//~^ ERROR invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
3634

src/test/ui/asm/aarch64/bad-reg.stderr

+11-17
Original file line numberDiff line numberDiff line change
@@ -74,79 +74,73 @@ error: invalid register `xzr`: the zero register cannot be used as an operand fo
7474
LL | asm!("", in("xzr") foo);
7575
| ^^^^^^^^^^^^^
7676

77-
error: invalid register `x18`: x18 is used as a reserved register on some targets and cannot be used as an operand for inline asm
78-
--> $DIR/bad-reg.rs:32:18
79-
|
80-
LL | asm!("", in("x18") foo);
81-
| ^^^^^^^^^^^^^
82-
8377
error: invalid register `x19`: x19 is used internally by LLVM and cannot be used as an operand for inline asm
84-
--> $DIR/bad-reg.rs:34:18
78+
--> $DIR/bad-reg.rs:32:18
8579
|
8680
LL | asm!("", in("x19") foo);
8781
| ^^^^^^^^^^^^^
8882

8983
error: register class `preg` can only be used as a clobber, not as an input or output
90-
--> $DIR/bad-reg.rs:37:18
84+
--> $DIR/bad-reg.rs:35:18
9185
|
9286
LL | asm!("", in("p0") foo);
9387
| ^^^^^^^^^^^^
9488

9589
error: register class `preg` can only be used as a clobber, not as an input or output
96-
--> $DIR/bad-reg.rs:40:20
90+
--> $DIR/bad-reg.rs:38:20
9791
|
9892
LL | asm!("{}", in(preg) foo);
9993
| ^^^^^^^^^^^^
10094

10195
error: register class `preg` can only be used as a clobber, not as an input or output
102-
--> $DIR/bad-reg.rs:42:20
96+
--> $DIR/bad-reg.rs:40:20
10397
|
10498
LL | asm!("{}", out(preg) _);
10599
| ^^^^^^^^^^^
106100

107101
error: register `x0` conflicts with register `x0`
108-
--> $DIR/bad-reg.rs:48:32
102+
--> $DIR/bad-reg.rs:46:32
109103
|
110104
LL | asm!("", in("x0") foo, in("w0") bar);
111105
| ------------ ^^^^^^^^^^^^ register `x0`
112106
| |
113107
| register `x0`
114108

115109
error: register `x0` conflicts with register `x0`
116-
--> $DIR/bad-reg.rs:50:32
110+
--> $DIR/bad-reg.rs:48:32
117111
|
118112
LL | asm!("", in("x0") foo, out("x0") bar);
119113
| ------------ ^^^^^^^^^^^^^ register `x0`
120114
| |
121115
| register `x0`
122116
|
123117
help: use `lateout` instead of `out` to avoid conflict
124-
--> $DIR/bad-reg.rs:50:18
118+
--> $DIR/bad-reg.rs:48:18
125119
|
126120
LL | asm!("", in("x0") foo, out("x0") bar);
127121
| ^^^^^^^^^^^^
128122

129123
error: register `v0` conflicts with register `v0`
130-
--> $DIR/bad-reg.rs:53:32
124+
--> $DIR/bad-reg.rs:51:32
131125
|
132126
LL | asm!("", in("v0") foo, in("q0") bar);
133127
| ------------ ^^^^^^^^^^^^ register `v0`
134128
| |
135129
| register `v0`
136130

137131
error: register `v0` conflicts with register `v0`
138-
--> $DIR/bad-reg.rs:55:32
132+
--> $DIR/bad-reg.rs:53:32
139133
|
140134
LL | asm!("", in("v0") foo, out("q0") bar);
141135
| ------------ ^^^^^^^^^^^^^ register `v0`
142136
| |
143137
| register `v0`
144138
|
145139
help: use `lateout` instead of `out` to avoid conflict
146-
--> $DIR/bad-reg.rs:55:18
140+
--> $DIR/bad-reg.rs:53:18
147141
|
148142
LL | asm!("", in("v0") foo, out("q0") bar);
149143
| ^^^^^^^^^^^^
150144

151-
error: aborting due to 19 previous errors
145+
error: aborting due to 18 previous errors
152146

0 commit comments

Comments
 (0)