[llvm-branch-commits] [llvm] ARM: Read the ABI from the "target-abi" module flag (PR #217600)

via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Thu Aug 20 05:21:24 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-backend-risc-v

Author: Matt Arsenault (arsenm)

<details>
<summary>Changes</summary>

This module flag is already used by RISCV, but ARM ignored it and
still exclusively relied on the -target-abi global option.

Co-authored-by: Claude (Claude-Opus-4.8) <noreply@<!-- -->anthropic.com>

---
Full diff: https://github.com/llvm/llvm-project/pull/217600.diff


9 Files Affected:

- (modified) llvm/lib/Target/ARM/ARMAsmPrinter.cpp (+3-2) 
- (modified) llvm/lib/Target/ARM/ARMFastISel.cpp (+2-2) 
- (modified) llvm/lib/Target/ARM/ARMISelLowering.cpp (+2-2) 
- (modified) llvm/lib/Target/ARM/ARMSubtarget.cpp (+6-5) 
- (modified) llvm/lib/Target/ARM/ARMSubtarget.h (+12-2) 
- (modified) llvm/lib/Target/ARM/ARMTargetMachine.cpp (+11-1) 
- (modified) llvm/lib/Target/ARM/ARMTargetMachine.h (+5) 
- (added) llvm/test/CodeGen/ARM/module-target-abi.ll (+30) 
- (added) llvm/test/CodeGen/ARM/target-abi-module-flag-conflict.ll (+21) 


``````````diff
diff --git a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
index 11f7929cb6dbe..c7414661f73f4 100644
--- a/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
+++ b/llvm/lib/Target/ARM/ARMAsmPrinter.cpp
@@ -699,8 +699,9 @@ void ARMAsmPrinter::emitAttributes() {
   const ARMBaseTargetMachine &ATM =
       static_cast<const ARMBaseTargetMachine &>(TM);
   FloatABI::ABIType FloatABI = ATM.getFloatABI(*MMI->getModule());
+  ARM::ARMABI ABI = ATM.getEffectiveABI(*MMI->getModule());
   const ARMSubtarget STI(TT, std::string(CPU), ArchFS, ATM,
-                         ATM.isLittleEndian(), FloatABI);
+                         ATM.isLittleEndian(), FloatABI, ABI);
 
   // Emit build attributes for the available hardware.
   ATS.emitTargetAttributes(STI);
@@ -808,7 +809,7 @@ void ARMAsmPrinter::emitAttributes() {
   ATS.emitAttribute(ARMBuildAttrs::ABI_align_preserved, 1);
 
   // Hard float.  Use both S and D registers and conform to AAPCS-VFP.
-  if (getTM().isAAPCS_ABI() && STI.isTargetHardFloat())
+  if (STI.isAAPCS_ABI() && STI.isTargetHardFloat())
     ATS.emitAttribute(ARMBuildAttrs::ABI_VFP_args, ARMBuildAttrs::HardFPAAPCS);
 
   // FIXME: To support emitting this build attribute as GCC does, the
diff --git a/llvm/lib/Target/ARM/ARMFastISel.cpp b/llvm/lib/Target/ARM/ARMFastISel.cpp
index 26804a6265e63..88ee3156ee339 100644
--- a/llvm/lib/Target/ARM/ARMFastISel.cpp
+++ b/llvm/lib/Target/ARM/ARMFastISel.cpp
@@ -1896,7 +1896,7 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC,
     report_fatal_error("Unsupported calling convention");
   case CallingConv::Fast:
     if (Subtarget->hasFPRegs() && !isVarArg) {
-      if (!TM.isAAPCS_ABI())
+      if (!Subtarget->isAAPCS_ABI())
         return (Return ? RetFastCC_ARM_APCS : FastCC_ARM_APCS);
       // For AAPCS ABI targets, just use VFP variant of the calling convention.
       return (Return ? RetCC_ARM_AAPCS_VFP : CC_ARM_AAPCS_VFP);
@@ -1905,7 +1905,7 @@ CCAssignFn *ARMFastISel::CCAssignFnForCall(CallingConv::ID CC,
   case CallingConv::C:
   case CallingConv::CXX_FAST_TLS:
     // Use target triple & subtarget features to do actual dispatch.
-    if (TM.isAAPCS_ABI()) {
+    if (Subtarget->isAAPCS_ABI()) {
       if (Subtarget->hasFPRegs() && Subtarget->isTargetHardFloat() && !isVarArg)
         return (Return ? RetCC_ARM_AAPCS_VFP: CC_ARM_AAPCS_VFP);
       else
diff --git a/llvm/lib/Target/ARM/ARMISelLowering.cpp b/llvm/lib/Target/ARM/ARMISelLowering.cpp
index d0bee82a3044a..43013b1992b50 100644
--- a/llvm/lib/Target/ARM/ARMISelLowering.cpp
+++ b/llvm/lib/Target/ARM/ARMISelLowering.cpp
@@ -1706,7 +1706,7 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
     return isVarArg ? CallingConv::ARM_AAPCS : CallingConv::ARM_AAPCS_VFP;
   case CallingConv::C:
   case CallingConv::Tail:
-    if (!getTM().isAAPCS_ABI())
+    if (!Subtarget->isAAPCS_ABI())
       return CallingConv::ARM_APCS;
     else if (Subtarget->isTargetHardFloat() && !isVarArg)
       return CallingConv::ARM_AAPCS_VFP;
@@ -1714,7 +1714,7 @@ ARMTargetLowering::getEffectiveCallingConv(CallingConv::ID CC,
       return CallingConv::ARM_AAPCS;
   case CallingConv::Fast:
   case CallingConv::CXX_FAST_TLS:
-    if (!getTM().isAAPCS_ABI()) {
+    if (!Subtarget->isAAPCS_ABI()) {
       if (Subtarget->hasFPRegs() && !Subtarget->isThumb1Only() && !isVarArg)
         return CallingConv::Fast;
       return CallingConv::ARM_APCS;
diff --git a/llvm/lib/Target/ARM/ARMSubtarget.cpp b/llvm/lib/Target/ARM/ARMSubtarget.cpp
index fd09ac1050f80..fb62e4e773bc0 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.cpp
+++ b/llvm/lib/Target/ARM/ARMSubtarget.cpp
@@ -89,12 +89,13 @@ ARMFrameLowering *ARMSubtarget::initializeFrameLowering(StringRef CPU,
 ARMSubtarget::ARMSubtarget(const Triple &TT, const std::string &CPU,
                            const std::string &FS,
                            const ARMBaseTargetMachine &TM, bool IsLittle,
-                           FloatABI::ABIType FloatABI, bool MinSize,
-                           DenormalMode DM)
+                           FloatABI::ABIType FloatABI, ARM::ARMABI ABI,
+                           bool MinSize, DenormalMode DM)
     : ARMGenSubtargetInfo(TT, CPU, /*TuneCPU*/ CPU, FS),
       UseMulOps(UseFusedMulOps), CPUString(CPU), OptMinSize(MinSize),
       IsLittle(IsLittle), DM(DM), TargetTriple(TT), Options(TM.Options), TM(TM),
-      FloatABIType(FloatABI), FrameLowering(initializeFrameLowering(CPU, FS)),
+      FloatABIType(FloatABI), ABI(ABI),
+      FrameLowering(initializeFrameLowering(CPU, FS)),
       // At this point initializeSubtargetDependencies has been called so
       // we can query directly.
       InstrInfo(isThumb1Only() ? (ARMBaseInstrInfo *)new Thumb1InstrInfo(*this)
@@ -333,9 +334,9 @@ void ARMSubtarget::initSubtargetFeatures(StringRef CPU, StringRef FS) {
   if (isTargetWindows())
     NoARM = true;
 
-  if (TM.isAAPCS_ABI())
+  if (isAAPCS_ABI())
     stackAlignment = Align(8);
-  if (TM.isAAPCS16_ABI())
+  if (isAAPCS16_ABI())
     stackAlignment = Align(16);
 
   // FIXME: Completely disable sibcall for Thumb1 since ThumbRegisterInfo::
diff --git a/llvm/lib/Target/ARM/ARMSubtarget.h b/llvm/lib/Target/ARM/ARMSubtarget.h
index d60b41c1b8324..237d61150c6a0 100644
--- a/llvm/lib/Target/ARM/ARMSubtarget.h
+++ b/llvm/lib/Target/ARM/ARMSubtarget.h
@@ -31,6 +31,7 @@
 #include "llvm/MC/MCSchedule.h"
 #include "llvm/Target/TargetMachine.h"
 #include "llvm/Target/TargetOptions.h"
+#include "llvm/TargetParser/ARMTargetParser.h"
 #include "llvm/TargetParser/Triple.h"
 #include <bitset>
 #include <memory>
@@ -209,14 +210,17 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
   /// The floating-point ABI in effect for this subtarget.
   FloatABI::ABIType FloatABIType;
 
+  /// The ABI in effect.
+  const ARM::ARMABI ABI;
+
 public:
   /// This constructor initializes the data members to match that
   /// of the specified triple.
   ///
   ARMSubtarget(const Triple &TT, const std::string &CPU, const std::string &FS,
                const ARMBaseTargetMachine &TM, bool IsLittle,
-               FloatABI::ABIType FloatABI, bool MinSize = false,
-               DenormalMode DM = DenormalMode::getIEEE());
+               FloatABI::ABIType FloatABI, ARM::ARMABI ABI,
+               bool MinSize = false, DenormalMode DM = DenormalMode::getIEEE());
 
   /// getMaxInlineSizeThreshold - Returns the maximum memset / memcpy size
   /// that still makes it profitable to inline the call.
@@ -376,6 +380,12 @@ class ARMSubtarget : public ARMGenSubtargetInfo {
   /// Returns true if the subtarget uses the hard floating-point ABI.
   bool isTargetHardFloat() const { return FloatABIType == FloatABI::Hard; }
 
+  bool isAPCS_ABI() const { return ABI == ARM::ARM_ABI_APCS; }
+  bool isAAPCS_ABI() const {
+    return ABI == ARM::ARM_ABI_AAPCS || ABI == ARM::ARM_ABI_AAPCS16;
+  }
+  bool isAAPCS16_ABI() const { return ABI == ARM::ARM_ABI_AAPCS16; }
+
   bool isReadTPSoft() const {
     return !(isReadTPTPIDRURW() || isReadTPTPIDRURO() || isReadTPTPIDRPRW());
   }
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.cpp b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
index e14f356a8b11b..40cd57eec571f 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.cpp
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.cpp
@@ -247,6 +247,13 @@ FloatABI::ABIType ARMBaseTargetMachine::getFloatABI(const Module &M) const {
   return M.getTargetTriple().getDefaultFloatABI();
 }
 
+ARM::ARMABI ARMBaseTargetMachine::getEffectiveABI(const Module &M) const {
+  // Consistency of "target-abi" and -target-abi is validated elsewhere.
+  if (const auto *MD = cast_or_null<MDString>(M.getModuleFlag("target-abi")))
+    return ARM::computeTargetABI(TargetTriple, MD->getString());
+  return TargetABI;
+}
+
 const ARMSubtarget *
 ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
   Attribute CPUAttr = F.getFnAttribute("target-cpu");
@@ -283,10 +290,13 @@ ARMBaseTargetMachine::getSubtargetImpl(const Function &F) const {
   // registers, but no floating-point hardware (mve+nofp)
   Key += FloatABI == FloatABI::Hard ? "+hard-float-abi" : "+soft-float-abi";
 
+  ARM::ARMABI ABI = getEffectiveABI(*F.getParent());
+  Key += "+abi=" + std::to_string((int)ABI);
+
   auto &I = SubtargetMap[Key];
   if (!I) {
     I = std::make_unique<ARMSubtarget>(TargetTriple, CPU, FS, *this, isLittle,
-                                       FloatABI, F.hasMinSize(), DM);
+                                       FloatABI, ABI, F.hasMinSize(), DM);
 
     if (!I->isThumb() && !I->hasARMOps())
       F.getContext().emitError("Function '" + F.getName() + "' uses ARM "
diff --git a/llvm/lib/Target/ARM/ARMTargetMachine.h b/llvm/lib/Target/ARM/ARMTargetMachine.h
index 81dc7a5965f6f..1771fcaa26c66 100644
--- a/llvm/lib/Target/ARM/ARMTargetMachine.h
+++ b/llvm/lib/Target/ARM/ARMTargetMachine.h
@@ -57,6 +57,11 @@ class ARMBaseTargetMachine : public CodeGenTargetMachineImpl {
   /// explicit -target-abi=aapcs16 forces the hard-float ABI.
   FloatABI::ABIType getFloatABI(const Module &M) const;
 
+  /// Returns the ABI in effect for \p M: the "target-abi" module flag if
+  /// present, otherwise the legacy -target-abi option; falling back to the
+  /// TargetMachine-level ABI computed at construction.
+  ARM::ARMABI getEffectiveABI(const Module &M) const;
+
   TargetTransformInfo getTargetTransformInfo(const Function &F) const override;
 
   // Pass Pipeline Configuration
diff --git a/llvm/test/CodeGen/ARM/module-target-abi.ll b/llvm/test/CodeGen/ARM/module-target-abi.ll
new file mode 100644
index 0000000000000..0cb41cae6c67c
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/module-target-abi.ll
@@ -0,0 +1,30 @@
+; The "target-abi" module flag selects the ABI used for codegen. APCS uses
+; 4-byte stack alignment while AAPCS uses 8-byte alignment, which is observable
+; in the emitted prologue. The flag drives this with no -target-abi option.
+; RUN: split-file %s %t
+; RUN: llc -mtriple=armv7-none-eabi -filetype=asm < %t/apcs.ll | FileCheck %s --check-prefix=APCS
+; RUN: llc -mtriple=armv7-none-eabi -filetype=asm < %t/aapcs.ll | FileCheck %s --check-prefix=AAPCS
+
+;--- apcs.ll
+; APCS: push {lr}
+; APCS: sub sp, sp, #4
+declare void @use(ptr)
+define void @f() {
+  %a = alloca i32
+  call void @use(ptr %a)
+  ret void
+}
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"apcs"}
+
+;--- aapcs.ll
+; AAPCS: push {r11, lr}
+; AAPCS: sub sp, sp, #8
+declare void @use(ptr)
+define void @f() {
+  %a = alloca i32
+  call void @use(ptr %a)
+  ret void
+}
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"aapcs"}
diff --git a/llvm/test/CodeGen/ARM/target-abi-module-flag-conflict.ll b/llvm/test/CodeGen/ARM/target-abi-module-flag-conflict.ll
new file mode 100644
index 0000000000000..188dc2895d643
--- /dev/null
+++ b/llvm/test/CodeGen/ARM/target-abi-module-flag-conflict.ll
@@ -0,0 +1,21 @@
+; Check that a "target-abi" module flag conflicting with the
+; -target-abi command-line option is diagnosed once.
+; RUN: not llc -mtriple=armv7-none-eabi -target-abi=aapcs -filetype=null < %s 2>&1 \
+; RUN:   | FileCheck %s -implicit-check-not=error:
+
+; CHECK: error: -target-abi option != target-abi module flag
+define float @f1(float %x) #0 {
+  %r = fadd float %x, %x
+  ret float %r
+}
+
+define float @f2(float %x) #1 {
+  %r = fadd float %x, %x
+  ret float %r
+}
+
+attributes #0 = { "target-cpu"="cortex-a8" }
+attributes #1 = { "target-cpu"="cortex-a15" }
+
+!llvm.module.flags = !{!0}
+!0 = !{i32 1, !"target-abi", !"apcs"}

``````````

</details>


https://github.com/llvm/llvm-project/pull/217600


More information about the llvm-branch-commits mailing list