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) <[email protected]> >From 011eb21937ddd92b1f09fd18ab40df238d5cf8ca Mon Sep 17 00:00:00 2001 From: Matt Arsenault <[email protected]> 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) <[email protected]> --- 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"} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
