[llvm-branch-commits] [llvm] ARM: Read the ABI from the "target-abi" module flag (PR #217600)
Matt Arsenault via llvm-branch-commits
llvm-branch-commits at lists.llvm.org
Thu Aug 20 05:20:50 PDT 2026
https://github.com/arsenm created https://github.com/llvm/llvm-project/pull/217600
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 at anthropic.com>
>From 011eb21937ddd92b1f09fd18ab40df238d5cf8ca Mon Sep 17 00:00:00 2001
From: Matt Arsenault <Matthew.Arsenault at amd.com>
Date: Tue, 18 Aug 2026 20:30:36 +0200
Subject: [PATCH] ARM: Read the ABI from the "target-abi" module flag
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 at anthropic.com>
---
llvm/lib/Target/ARM/ARMAsmPrinter.cpp | 5 ++--
llvm/lib/Target/ARM/ARMFastISel.cpp | 4 +--
llvm/lib/Target/ARM/ARMISelLowering.cpp | 4 +--
llvm/lib/Target/ARM/ARMSubtarget.cpp | 11 +++----
llvm/lib/Target/ARM/ARMSubtarget.h | 14 +++++++--
llvm/lib/Target/ARM/ARMTargetMachine.cpp | 12 +++++++-
llvm/lib/Target/ARM/ARMTargetMachine.h | 5 ++++
llvm/test/CodeGen/ARM/module-target-abi.ll | 30 +++++++++++++++++++
.../ARM/target-abi-module-flag-conflict.ll | 21 +++++++++++++
9 files changed, 92 insertions(+), 14 deletions(-)
create mode 100644 llvm/test/CodeGen/ARM/module-target-abi.ll
create mode 100644 llvm/test/CodeGen/ARM/target-abi-module-flag-conflict.ll
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"}
More information about the llvm-branch-commits
mailing list