[llvm] [AArch64] Add basic NPM support for LoadStoreOptimizer. (PR #184090)
David Green via llvm-commits
llvm-commits at lists.llvm.org
Mon Mar 2 02:14:21 PST 2026
https://github.com/davemgreen created https://github.com/llvm/llvm-project/pull/184090
This adds what I can tell is the the basics for NPM support on LLVM, and ports the AArch64LoadStoreOpt pass to have NPM support.
>From ef69e7f1a1b713d3fcff446572acdc59add4e5f8 Mon Sep 17 00:00:00 2001
From: David Green <david.green at arm.com>
Date: Mon, 2 Mar 2026 09:49:42 +0000
Subject: [PATCH] [AArch64] Add basic NPM support for LoadStoreOptimizer.
---
llvm/lib/Target/AArch64/AArch64.h | 12 +++-
.../AArch64/AArch64LoadStoreOptimizer.cpp | 59 +++++++++++++------
.../Target/AArch64/AArch64PassRegistry.def | 30 ++++++++++
.../Target/AArch64/AArch64TargetMachine.cpp | 8 ++-
.../AArch64/stp-opt-with-renaming-ld3.mir | 1 +
5 files changed, 87 insertions(+), 23 deletions(-)
create mode 100644 llvm/lib/Target/AArch64/AArch64PassRegistry.def
diff --git a/llvm/lib/Target/AArch64/AArch64.h b/llvm/lib/Target/AArch64/AArch64.h
index 40983714ddf1d..597827f524c94 100644
--- a/llvm/lib/Target/AArch64/AArch64.h
+++ b/llvm/lib/Target/AArch64/AArch64.h
@@ -16,6 +16,7 @@
#include "MCTargetDesc/AArch64MCTargetDesc.h"
#include "Utils/AArch64BaseInfo.h"
+#include "llvm/CodeGen/MachineFunctionAnalysisManager.h"
#include "llvm/Pass.h"
#include "llvm/PassRegistry.h"
#include "llvm/Support/DataTypes.h"
@@ -44,7 +45,7 @@ FunctionPass *createAArch64StorePairSuppressPass();
FunctionPass *createAArch64ExpandPseudoPass();
FunctionPass *createAArch64SLSHardeningPass();
FunctionPass *createAArch64SpeculationHardeningPass();
-FunctionPass *createAArch64LoadStoreOptimizationPass();
+FunctionPass *createAArch64LoadStoreOptLegacyPass();
ModulePass *createAArch64LowerHomogeneousPrologEpilogPass();
FunctionPass *createAArch64SIMDInstrOptPass();
ModulePass *createAArch64PromoteConstantPass();
@@ -94,7 +95,7 @@ void initializeAArch64ConditionalComparesPass(PassRegistry &);
void initializeAArch64DAGToDAGISelLegacyPass(PassRegistry &);
void initializeAArch64DeadRegisterDefinitionsPass(PassRegistry&);
void initializeAArch64ExpandPseudoPass(PassRegistry &);
-void initializeAArch64LoadStoreOptPass(PassRegistry&);
+void initializeAArch64LoadStoreOptLegacyPass(PassRegistry &);
void initializeAArch64LowerHomogeneousPrologEpilogPass(PassRegistry &);
void initializeAArch64MIPeepholeOptPass(PassRegistry &);
void initializeAArch64O0PreLegalizerCombinerPass(PassRegistry &);
@@ -121,6 +122,13 @@ void initializeMachineSMEABIPass(PassRegistry &);
void initializeAArch64SRLTDefineSuperRegsPass(PassRegistry &);
void initializeSVEIntrinsicOptsPass(PassRegistry &);
void initializeAArch64Arm64ECCallLoweringPass(PassRegistry &);
+
+class AArch64LoadStoreOptPass : public PassInfoMixin<AArch64LoadStoreOptPass> {
+public:
+ PreservedAnalyses run(MachineFunction &MF,
+ MachineFunctionAnalysisManager &MFAM);
+};
+
} // end namespace llvm
#endif
diff --git a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
index eebac54d5f8c2..4996950c71d04 100644
--- a/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
+++ b/llvm/lib/Target/AArch64/AArch64LoadStoreOptimizer.cpp
@@ -120,11 +120,7 @@ using LdStPairFlags = struct LdStPairFlags {
std::optional<MCPhysReg> getRenameReg() const { return RenameReg; }
};
-struct AArch64LoadStoreOpt : public MachineFunctionPass {
- static char ID;
-
- AArch64LoadStoreOpt() : MachineFunctionPass(ID) {}
-
+struct AArch64LoadStoreOpt {
AliasAnalysis *AA;
const AArch64InstrInfo *TII;
const TargetRegisterInfo *TRI;
@@ -134,11 +130,6 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
LiveRegUnits ModifiedRegUnits, UsedRegUnits;
LiveRegUnits DefinedInBB;
- void getAnalysisUsage(AnalysisUsage &AU) const override {
- AU.addRequired<AAResultsWrapperPass>();
- MachineFunctionPass::getAnalysisUsage(AU);
- }
-
// Scan the instructions looking for a load/store that can be combined
// with the current instruction into a load/store pair.
// Return the matching instruction if one is found, else MBB->end().
@@ -229,8 +220,21 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
bool optimizeBlock(MachineBasicBlock &MBB, bool EnableNarrowZeroStOpt);
+ bool runOnMachineFunction(MachineFunction &MF);
+};
+
+struct AArch64LoadStoreOptLegacy : public MachineFunctionPass {
+ static char ID;
+
+ AArch64LoadStoreOptLegacy() : MachineFunctionPass(ID) {}
+
bool runOnMachineFunction(MachineFunction &Fn) override;
+ void getAnalysisUsage(AnalysisUsage &AU) const override {
+ AU.addRequired<AAResultsWrapperPass>();
+ MachineFunctionPass::getAnalysisUsage(AU);
+ }
+
MachineFunctionProperties getRequiredProperties() const override {
return MachineFunctionProperties().setNoVRegs();
}
@@ -238,11 +242,11 @@ struct AArch64LoadStoreOpt : public MachineFunctionPass {
StringRef getPassName() const override { return AARCH64_LOAD_STORE_OPT_NAME; }
};
-char AArch64LoadStoreOpt::ID = 0;
+char AArch64LoadStoreOptLegacy::ID = 0;
} // end anonymous namespace
-INITIALIZE_PASS(AArch64LoadStoreOpt, "aarch64-ldst-opt",
+INITIALIZE_PASS(AArch64LoadStoreOptLegacy, "aarch64-ldst-opt",
AARCH64_LOAD_STORE_OPT_NAME, false, false)
static bool isNarrowStore(unsigned Opc) {
@@ -3113,13 +3117,9 @@ bool AArch64LoadStoreOpt::optimizeBlock(MachineBasicBlock &MBB,
}
bool AArch64LoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
- if (skipFunction(Fn.getFunction()))
- return false;
-
Subtarget = &Fn.getSubtarget<AArch64Subtarget>();
TII = Subtarget->getInstrInfo();
TRI = Subtarget->getRegisterInfo();
- AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
// Resize the modified and used register unit trackers. We do this once
// per function and then clear the register units each time we optimize a load
@@ -3148,8 +3148,31 @@ bool AArch64LoadStoreOpt::runOnMachineFunction(MachineFunction &Fn) {
// The resulting IR is invalid, but nothing uses the KILL markers after this
// pass, so it's never caused a problem in practice.
+bool AArch64LoadStoreOptLegacy::runOnMachineFunction(MachineFunction &MF) {
+ if (skipFunction(MF.getFunction()))
+ return false;
+ AArch64LoadStoreOpt Impl;
+ Impl.AA = &getAnalysis<AAResultsWrapperPass>().getAAResults();
+ return Impl.runOnMachineFunction(MF);
+}
+
/// createAArch64LoadStoreOptimizationPass - returns an instance of the
/// load / store optimization pass.
-FunctionPass *llvm::createAArch64LoadStoreOptimizationPass() {
- return new AArch64LoadStoreOpt();
+FunctionPass *llvm::createAArch64LoadStoreOptLegacyPass() {
+ return new AArch64LoadStoreOptLegacy();
}
+
+PreservedAnalyses
+AArch64LoadStoreOptPass::run(MachineFunction &MF,
+ MachineFunctionAnalysisManager &MFAM) {
+ AArch64LoadStoreOpt Impl;
+ Impl.AA = &MFAM.getResult<FunctionAnalysisManagerMachineFunctionProxy>(MF)
+ .getManager()
+ .getResult<AAManager>(MF.getFunction());
+ bool Changed = Impl.runOnMachineFunction(MF);
+ if (!Changed)
+ return PreservedAnalyses::all();
+ PreservedAnalyses PA = getMachineFunctionPassPreservedAnalyses();
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
+}
\ No newline at end of file
diff --git a/llvm/lib/Target/AArch64/AArch64PassRegistry.def b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
new file mode 100644
index 0000000000000..2ed3808e6b315
--- /dev/null
+++ b/llvm/lib/Target/AArch64/AArch64PassRegistry.def
@@ -0,0 +1,30 @@
+//===- AArch64PassRegistry.def - Registry of AArch64 passes -----*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file is used as the registry of passes that are part of the AArch64
+// backend.
+//
+//===----------------------------------------------------------------------===//
+
+// NOTE: NO INCLUDE GUARD DESIRED!
+
+#ifndef MODULE_PASS
+#define MODULE_PASS(NAME, CREATE_PASS)
+#endif
+#undef MODULE_PASS
+
+#ifndef FUNCTION_PASS
+#define FUNCTION_PASS(NAME, CREATE_PASS)
+#endif
+#undef FUNCTION_PASS
+
+#ifndef MACHINE_FUNCTION_PASS
+#define MACHINE_FUNCTION_PASS(NAME, CREATE_PASS)
+#endif
+MACHINE_FUNCTION_PASS("aarch64-ldst-opt", AArch64LoadStoreOptPass())
+#undef MACHINE_FUNCTION_PASS
diff --git a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
index 4255ebd4cc557..6fa937be87eea 100644
--- a/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
+++ b/llvm/lib/Target/AArch64/AArch64TargetMachine.cpp
@@ -254,7 +254,7 @@ LLVMInitializeAArch64Target() {
initializeAArch64ConditionOptimizerPass(PR);
initializeAArch64DeadRegisterDefinitionsPass(PR);
initializeAArch64ExpandPseudoPass(PR);
- initializeAArch64LoadStoreOptPass(PR);
+ initializeAArch64LoadStoreOptLegacyPass(PR);
initializeAArch64MIPeepholeOptPass(PR);
initializeAArch64SIMDInstrOptPass(PR);
initializeAArch64O0PreLegalizerCombinerPass(PR);
@@ -586,6 +586,8 @@ class AArch64PassConfig : public TargetPassConfig {
} // end anonymous namespace
void AArch64TargetMachine::registerPassBuilderCallbacks(PassBuilder &PB) {
+#define GET_PASS_REGISTRY "AArch64PassRegistry.def"
+#include "llvm/Passes/TargetPassRegistry.inc"
PB.registerLateLoopOptimizationsEPCallback(
[=](LoopPassManager &LPM, OptimizationLevel Level) {
@@ -877,7 +879,7 @@ void AArch64PassConfig::addPreSched2() {
// Use load/store pair instructions when possible.
if (TM->getOptLevel() != CodeGenOptLevel::None) {
if (EnableLoadStoreOpt)
- addPass(createAArch64LoadStoreOptimizationPass());
+ addPass(createAArch64LoadStoreOptLegacyPass());
}
// Emit KCFI checks for indirect calls.
addPass(createKCFIPass());
@@ -900,7 +902,7 @@ void AArch64PassConfig::addPreEmitPass() {
// at O3, where the Tail Duplication Threshold is set to 4 instructions.
// Run the load/store optimizer once more.
if (TM->getOptLevel() >= CodeGenOptLevel::Aggressive && EnableLoadStoreOpt)
- addPass(createAArch64LoadStoreOptimizationPass());
+ addPass(createAArch64LoadStoreOptLegacyPass());
if (TM->getOptLevel() >= CodeGenOptLevel::Aggressive &&
EnableAArch64CopyPropagation)
diff --git a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-ld3.mir b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-ld3.mir
index b8b3642052ec5..efad81ef5d9db 100644
--- a/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-ld3.mir
+++ b/llvm/test/CodeGen/AArch64/stp-opt-with-renaming-ld3.mir
@@ -1,4 +1,5 @@
# RUN: llc -run-pass=aarch64-ldst-opt -mtriple=arm64-apple-iphoneos -aarch64-load-store-renaming=true -o - -verify-machineinstrs %s | FileCheck %s
+# RUN: llc -passes=aarch64-ldst-opt -mtriple=arm64-apple-iphoneos -aarch64-load-store-renaming=true -o - -verify-machineinstrs %s | FileCheck %s
--- |
define void @test_ld3(ptr %a1) {
entry:
More information about the llvm-commits
mailing list