[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