diff --git a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp index 81c87ace76e56..57311e06f5387 100644 --- a/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp +++ b/llvm/lib/Target/AArch64/AArch64ISelLowering.cpp @@ -30,6 +30,7 @@ #include "llvm/ADT/SmallVectorExtras.h" #include "llvm/ADT/Statistic.h" #include "llvm/ADT/StringRef.h" +#include "llvm/ADT/StringSwitch.h" #include "llvm/ADT/Twine.h" #include "llvm/Analysis/LoopInfo.h" #include "llvm/Analysis/MemoryLocation.h" @@ -13157,6 +13158,20 @@ AArch64TargetLowering::getRegForInlineAsmConstraint( return std::make_pair(unsigned(AArch64::ZT0), &AArch64::ZTRRegClass); } + // Clang will correctly decode the usage of register name aliases into their + // official names. However, other frontends like `rustc` do not. This allows + // users of these frontends to use the ABI names for registers in LLVM-style + // register constraints. + // + // x31->sp is not included here because it's not a general register and + // needs different handling + unsigned XRegFromAlias = StringSwitch(Constraint.lower()) + .Cases({"{x29}", "{fp}"}, AArch64::FP) + .Cases({"{x30}", "{lr}"}, AArch64::LR) + .Default(AArch64::NoRegister); + if (XRegFromAlias != AArch64::NoRegister) + return std::make_pair(XRegFromAlias, &AArch64::GPR64RegClass); + // Use the default implementation in TargetLowering to convert the register // constraint into a member of a register class. std::pair Res; diff --git a/llvm/test/CodeGen/AArch64/inline-asm-clobber-x29-x30.ll b/llvm/test/CodeGen/AArch64/inline-asm-clobber-x29-x30.ll new file mode 100644 index 0000000000000..587a85367b5ba --- /dev/null +++ b/llvm/test/CodeGen/AArch64/inline-asm-clobber-x29-x30.ll @@ -0,0 +1,36 @@ +; RUN: llc -mtriple=aarch64 -verify-machineinstrs < %s | FileCheck %s + +; Test that both numeric register names (x29, x30) and their architectural +; aliases (fp, lr) work correctly as clobbers in inline assembly. + +define void @clobber_x29() nounwind { +; CHECK-LABEL: clobber_x29: +; CHECK: str x29, [sp +; CHECK: ldr x29, [sp + tail call void asm sideeffect "", "~{x29}"() + ret void +} + +define void @clobber_fp() nounwind { +; CHECK-LABEL: clobber_fp: +; CHECK: str x29, [sp +; CHECK: ldr x29, [sp + tail call void asm sideeffect "", "~{fp}"() + ret void +} + +define void @clobber_x30() nounwind { +; CHECK-LABEL: clobber_x30: +; CHECK: str x30, [sp +; CHECK: ldr x30, [sp + tail call void asm sideeffect "", "~{x30}"() + ret void +} + +define void @clobber_lr() nounwind { +; CHECK-LABEL: clobber_lr: +; CHECK: str x30, [sp +; CHECK: ldr x30, [sp + tail call void asm sideeffect "", "~{lr}"() + ret void +}