Skip to content

Commit 03e4c76

Browse files
committed
asm: Work around LLVM bug on AArch64
Upstream issue: llvm/llvm-project#58384 LLVM gets confused if we assign a 32-bit value to a 64-bit register, so pass the 32-bit register name to LLVM in that case.
1 parent c0a7612 commit 03e4c76

File tree

2 files changed

+70
-3
lines changed

2 files changed

+70
-3
lines changed

compiler/rustc_codegen_llvm/src/asm.rs

+54-3
Original file line numberDiff line numberDiff line change
@@ -496,6 +496,44 @@ fn xmm_reg_index(reg: InlineAsmReg) -> Option<u32> {
496496
}
497497
}
498498

499+
/// If the register is an AArch64 integer register then return its index.
500+
fn a64_reg_index(reg: InlineAsmReg) -> Option<u32> {
501+
match reg {
502+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x0) => Some(0),
503+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x1) => Some(1),
504+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x2) => Some(2),
505+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x3) => Some(3),
506+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x4) => Some(4),
507+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x5) => Some(5),
508+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x6) => Some(6),
509+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x7) => Some(7),
510+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x8) => Some(8),
511+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x9) => Some(9),
512+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x10) => Some(10),
513+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x11) => Some(11),
514+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x12) => Some(12),
515+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x13) => Some(13),
516+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x14) => Some(14),
517+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x15) => Some(15),
518+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x16) => Some(16),
519+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x17) => Some(17),
520+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x18) => Some(18),
521+
// x19 is reserved
522+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x20) => Some(20),
523+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x21) => Some(21),
524+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x22) => Some(22),
525+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x23) => Some(23),
526+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x24) => Some(24),
527+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x25) => Some(25),
528+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x26) => Some(26),
529+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x27) => Some(27),
530+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x28) => Some(28),
531+
// x29 is reserved
532+
InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) => Some(30),
533+
_ => None,
534+
}
535+
}
536+
499537
/// If the register is an AArch64 vector register then return its index.
500538
fn a64_vreg_index(reg: InlineAsmReg) -> Option<u32> {
501539
match reg {
@@ -526,6 +564,22 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
526564
'x'
527565
};
528566
format!("{{{}mm{}}}", class, idx)
567+
} else if let Some(idx) = a64_reg_index(reg) {
568+
let class = if let Some(layout) = layout {
569+
match layout.size.bytes() {
570+
8 => 'x',
571+
_ => 'w',
572+
}
573+
} else {
574+
// We use i32 as the type for discarded outputs
575+
'w'
576+
};
577+
if class == 'x' && reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
578+
// LLVM doesn't recognize x30. use lr instead.
579+
"{lr}".to_string()
580+
} else {
581+
format!("{{{}{}}}", class, idx)
582+
}
529583
} else if let Some(idx) = a64_vreg_index(reg) {
530584
let class = if let Some(layout) = layout {
531585
match layout.size.bytes() {
@@ -541,9 +595,6 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'_>>) ->
541595
'q'
542596
};
543597
format!("{{{}{}}}", class, idx)
544-
} else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) {
545-
// LLVM doesn't recognize x30
546-
"{lr}".to_string()
547598
} else if reg == InlineAsmReg::Arm(ArmInlineAsmReg::r14) {
548599
// LLVM doesn't recognize r14
549600
"{lr}".to_string()

src/test/ui/asm/aarch64/llvm-58384.rs

+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// only-aarch64
2+
// run-pass
3+
// needs-asm-support
4+
5+
// Test that we properly work around this LLVM issue:
6+
// https://github.com/llvm/llvm-project/issues/58384
7+
8+
use std::arch::asm;
9+
10+
fn main() {
11+
let a: i32;
12+
unsafe {
13+
asm!("", inout("x0") 435 => a);
14+
}
15+
assert_eq!(a, 435);
16+
}

0 commit comments

Comments
 (0)