[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-17 Thread Benjamin Maxwell via cfe-commits

https://github.com/MacDue closed 
https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-17 Thread Benjamin Maxwell via cfe-commits

https://github.com/MacDue updated 
https://github.com/llvm/llvm-project/pull/170277

>From af452bdabbad1131817f3c898ff0060a4ed2e665 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell 
Date: Mon, 1 Dec 2025 11:33:14 +
Subject: [PATCH 1/4] [AArch64][SME] Add pass remarks to the MachineSMEABIPass

This patch implements SME ABI pass remarks for when:

* a lazy ZA save is set up
* a full/agnostic ZA save is set up
* a ZT0 spill is emitted

These remarks can be enabled with `--pass-remarks-analysis=sme` (like
the current SME remarks).

The remarks work by noting where the save/spill was emitted, then
pointing out calls later in the function that require the save. The
remarks stop at the first call found along any path.

For example:

```
 7:  void merge_paths(bool a) __arm_inout("za") {
 8:if (a)
 9:  private_za_callee_a();
10:else
11:  private_za_callee_b();
12:private_za_callee_c(); // no remark (does not require a new save)
13:  }
```

Results in the following remarks:

```
remark: foo.c:8:7: lazy save of ZA emitted in 'merge_paths'
remark: foo.c:9:5: call to 'private_za_callee_a' requires ZA save
remark: foo.c:11:5: call to 'private_za_callee_b' requires ZA save
```

Change-Id: Ia7abd6f4dbeca3c9ac359df7f5251f41d1f68a8c
---
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp | 124 +-
 .../AArch64/sme-abi-save-call-remarks.ll  | 119 +
 .../AArch64/sme-lazy-save-call-remarks.ll |  25 
 3 files changed, 239 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/sme-abi-save-call-remarks.ll
 delete mode 100644 llvm/test/CodeGen/AArch64/sme-lazy-save-call-remarks.ll

diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp 
b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index b3e1ddbb91f79..98d14d238aad1 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -63,6 +63,7 @@
 #include "llvm/CodeGen/LivePhysRegs.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 
@@ -303,6 +304,7 @@ struct MachineSMEABI : public MachineFunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
 AU.setPreservesCFG();
 AU.addRequired();
+AU.addRequired();
 AU.addPreservedID(MachineLoopInfoID);
 AU.addPreservedID(MachineDominatorsID);
 MachineFunctionPass::getAnalysisUsage(AU);
@@ -391,6 +393,19 @@ struct MachineSMEABI : public MachineFunctionPass {
 return emitAllocateLazySaveBuffer(Context, MBB, MBBI);
   }
 
+  /// Collects the reachable calls from \p MBBI marked with \p Marker. This is
+  /// intended to be used to emit lazy save remarks. Note: This stops at the
+  /// first marked call along any path.
+  void collectReachableMarkedCalls(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl 
&Calls,
+   unsigned Marker) const;
+
+  void emitCallSaveRemarks(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI, DebugLoc DL,
+   unsigned Marker, StringRef RemarkName,
+   StringRef SaveName) const;
+
   /// Save live physical registers to virtual registers.
   PhysRegSave createPhysRegSave(LiveRegs PhysLiveRegs, MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI, DebugLoc DL);
@@ -406,6 +421,8 @@ struct MachineSMEABI : public MachineFunctionPass {
   const AArch64RegisterInfo *TRI = nullptr;
   const AArch64FunctionInfo *AFI = nullptr;
   const TargetInstrInfo *TII = nullptr;
+
+  MachineOptimizationRemarkEmitter *ORE = nullptr;
   MachineRegisterInfo *MRI = nullptr;
   MachineLoopInfo *MLI = nullptr;
 };
@@ -706,9 +723,91 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+ 

[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits

https://github.com/MacDue updated 
https://github.com/llvm/llvm-project/pull/170277

>From af452bdabbad1131817f3c898ff0060a4ed2e665 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell 
Date: Mon, 1 Dec 2025 11:33:14 +
Subject: [PATCH 1/4] [AArch64][SME] Add pass remarks to the MachineSMEABIPass

This patch implements SME ABI pass remarks for when:

* a lazy ZA save is set up
* a full/agnostic ZA save is set up
* a ZT0 spill is emitted

These remarks can be enabled with `--pass-remarks-analysis=sme` (like
the current SME remarks).

The remarks work by noting where the save/spill was emitted, then
pointing out calls later in the function that require the save. The
remarks stop at the first call found along any path.

For example:

```
 7:  void merge_paths(bool a) __arm_inout("za") {
 8:if (a)
 9:  private_za_callee_a();
10:else
11:  private_za_callee_b();
12:private_za_callee_c(); // no remark (does not require a new save)
13:  }
```

Results in the following remarks:

```
remark: foo.c:8:7: lazy save of ZA emitted in 'merge_paths'
remark: foo.c:9:5: call to 'private_za_callee_a' requires ZA save
remark: foo.c:11:5: call to 'private_za_callee_b' requires ZA save
```

Change-Id: Ia7abd6f4dbeca3c9ac359df7f5251f41d1f68a8c
---
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp | 124 +-
 .../AArch64/sme-abi-save-call-remarks.ll  | 119 +
 .../AArch64/sme-lazy-save-call-remarks.ll |  25 
 3 files changed, 239 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/sme-abi-save-call-remarks.ll
 delete mode 100644 llvm/test/CodeGen/AArch64/sme-lazy-save-call-remarks.ll

diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp 
b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index b3e1ddbb91f79..98d14d238aad1 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -63,6 +63,7 @@
 #include "llvm/CodeGen/LivePhysRegs.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 
@@ -303,6 +304,7 @@ struct MachineSMEABI : public MachineFunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
 AU.setPreservesCFG();
 AU.addRequired();
+AU.addRequired();
 AU.addPreservedID(MachineLoopInfoID);
 AU.addPreservedID(MachineDominatorsID);
 MachineFunctionPass::getAnalysisUsage(AU);
@@ -391,6 +393,19 @@ struct MachineSMEABI : public MachineFunctionPass {
 return emitAllocateLazySaveBuffer(Context, MBB, MBBI);
   }
 
+  /// Collects the reachable calls from \p MBBI marked with \p Marker. This is
+  /// intended to be used to emit lazy save remarks. Note: This stops at the
+  /// first marked call along any path.
+  void collectReachableMarkedCalls(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl 
&Calls,
+   unsigned Marker) const;
+
+  void emitCallSaveRemarks(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI, DebugLoc DL,
+   unsigned Marker, StringRef RemarkName,
+   StringRef SaveName) const;
+
   /// Save live physical registers to virtual registers.
   PhysRegSave createPhysRegSave(LiveRegs PhysLiveRegs, MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI, DebugLoc DL);
@@ -406,6 +421,8 @@ struct MachineSMEABI : public MachineFunctionPass {
   const AArch64RegisterInfo *TRI = nullptr;
   const AArch64FunctionInfo *AFI = nullptr;
   const TargetInstrInfo *TII = nullptr;
+
+  MachineOptimizationRemarkEmitter *ORE = nullptr;
   MachineRegisterInfo *MRI = nullptr;
   MachineLoopInfo *MLI = nullptr;
 };
@@ -706,9 +723,91 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+ 

[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Sander de Smalen via cfe-commits


@@ -0,0 +1,37 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -Rpass-analysis=sme 
-verify %s -S -o /dev/null
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -mllvm 
-aarch64-new-sme-abi -Rpass-analysis=sme -verify=expected-new %s -S -o 
/dev/null %s
+
+void private_za_callee_a();
+void private_za_callee_b();
+void private_za_callee_c();
+
+void test_za_merge_paths(int a) __arm_inout("za") {
+  // expected-new-remark@+1 {{lazy save of ZA emitted in 
'test_za_merge_paths'}}
+  if (a != 0)
+// expected-remark@+2 {{call from 'test_za_merge_paths' to 'unknown 
callee' sets up a lazy save for ZA}}
+// expected-new-remark@+1 {{call to 'private_za_callee_a' requires ZA 
save}}
+private_za_callee_a();
+  else
+// expected-remark@+2 {{call from 'test_za_merge_paths' to 'unknown 
callee' sets up a lazy save for ZA}}
+// expected-new-remark@+1 {{call to 'private_za_callee_b' requires ZA 
save}}
+private_za_callee_b();
+  // expected-remark@+1 {{call from 'test_za_merge_paths' to 'unknown callee' 
sets up a lazy save for ZA}}
+  private_za_callee_c();

sdesmalen-arm wrote:

nit: the comment you had here before:
```
// The new lowering won't report this call as the save is already needed due
// to the call to `private_za_callee_*()` calls on both paths to this BB.
```
may be useful to keep?

(you can change the offset to `+3` if you add this comment right above the call)

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Sander de Smalen via cfe-commits

https://github.com/sdesmalen-arm approved this pull request.


https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits

https://github.com/MacDue updated 
https://github.com/llvm/llvm-project/pull/170277

>From af452bdabbad1131817f3c898ff0060a4ed2e665 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell 
Date: Mon, 1 Dec 2025 11:33:14 +
Subject: [PATCH 1/3] [AArch64][SME] Add pass remarks to the MachineSMEABIPass

This patch implements SME ABI pass remarks for when:

* a lazy ZA save is set up
* a full/agnostic ZA save is set up
* a ZT0 spill is emitted

These remarks can be enabled with `--pass-remarks-analysis=sme` (like
the current SME remarks).

The remarks work by noting where the save/spill was emitted, then
pointing out calls later in the function that require the save. The
remarks stop at the first call found along any path.

For example:

```
 7:  void merge_paths(bool a) __arm_inout("za") {
 8:if (a)
 9:  private_za_callee_a();
10:else
11:  private_za_callee_b();
12:private_za_callee_c(); // no remark (does not require a new save)
13:  }
```

Results in the following remarks:

```
remark: foo.c:8:7: lazy save of ZA emitted in 'merge_paths'
remark: foo.c:9:5: call to 'private_za_callee_a' requires ZA save
remark: foo.c:11:5: call to 'private_za_callee_b' requires ZA save
```

Change-Id: Ia7abd6f4dbeca3c9ac359df7f5251f41d1f68a8c
---
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp | 124 +-
 .../AArch64/sme-abi-save-call-remarks.ll  | 119 +
 .../AArch64/sme-lazy-save-call-remarks.ll |  25 
 3 files changed, 239 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/sme-abi-save-call-remarks.ll
 delete mode 100644 llvm/test/CodeGen/AArch64/sme-lazy-save-call-remarks.ll

diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp 
b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index b3e1ddbb91f79..98d14d238aad1 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -63,6 +63,7 @@
 #include "llvm/CodeGen/LivePhysRegs.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 
@@ -303,6 +304,7 @@ struct MachineSMEABI : public MachineFunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
 AU.setPreservesCFG();
 AU.addRequired();
+AU.addRequired();
 AU.addPreservedID(MachineLoopInfoID);
 AU.addPreservedID(MachineDominatorsID);
 MachineFunctionPass::getAnalysisUsage(AU);
@@ -391,6 +393,19 @@ struct MachineSMEABI : public MachineFunctionPass {
 return emitAllocateLazySaveBuffer(Context, MBB, MBBI);
   }
 
+  /// Collects the reachable calls from \p MBBI marked with \p Marker. This is
+  /// intended to be used to emit lazy save remarks. Note: This stops at the
+  /// first marked call along any path.
+  void collectReachableMarkedCalls(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl 
&Calls,
+   unsigned Marker) const;
+
+  void emitCallSaveRemarks(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI, DebugLoc DL,
+   unsigned Marker, StringRef RemarkName,
+   StringRef SaveName) const;
+
   /// Save live physical registers to virtual registers.
   PhysRegSave createPhysRegSave(LiveRegs PhysLiveRegs, MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI, DebugLoc DL);
@@ -406,6 +421,8 @@ struct MachineSMEABI : public MachineFunctionPass {
   const AArch64RegisterInfo *TRI = nullptr;
   const AArch64FunctionInfo *AFI = nullptr;
   const TargetInstrInfo *TII = nullptr;
+
+  MachineOptimizationRemarkEmitter *ORE = nullptr;
   MachineRegisterInfo *MRI = nullptr;
   MachineLoopInfo *MLI = nullptr;
 };
@@ -706,9 +723,91 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+ 

[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Sander de Smalen via cfe-commits


@@ -706,16 +723,101 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+  }
+  if (I != MBB.end() && I->isCall())
+Calls.push_back(&*I);
+  // Note: This function always returns true if a "Marker" was found.
+  return true;
+}
+
+void MachineSMEABI::collectReachableMarkedCalls(
+const MachineBasicBlock &StartMBB,
+MachineBasicBlock::const_iterator StartInst,
+SmallVectorImpl &Calls, unsigned Marker) const {
+  assert(Marker == AArch64::InOutZAUsePseudo ||
+ Marker == AArch64::RequiresZASavePseudo ||
+ Marker == AArch64::RequiresZT0SavePseudo);
+  unsigned CallDestroyOpcode = TII->getCallFrameDestroyOpcode();
+  if (findMarkedCall(StartMBB, StartInst, Calls, Marker, CallDestroyOpcode))
+return;
+
+  SmallPtrSet Visited;
+  SmallVector Worklist(StartMBB.succ_rbegin(),
+  StartMBB.succ_rend());
+  while (!Worklist.empty()) {
+const MachineBasicBlock *MBB = Worklist.pop_back_val();
+auto [_, Inserted] = Visited.insert(MBB);
+if (!Inserted)
+  continue;
+
+if (!findMarkedCall(*MBB, MBB->begin(), Calls, Marker, CallDestroyOpcode))
+  Worklist.append(MBB->succ_rbegin(), MBB->succ_rend());
+  }
+}
+
+static StringRef getCalleeName(const MachineInstr &CallInst) {
+  assert(CallInst.isCall() && "expected a call");
+  for (const MachineOperand &MO : CallInst.operands()) {
+if (MO.isSymbol())
+  return MO.getSymbolName();
+if (MO.isGlobal())
+  return MO.getGlobal()->getName();
+  }
+  return {};

sdesmalen-arm wrote:

I was thinking something like "call to function pointer", but I see how it 
doesn't really matter for the message itself ("call requires ZA save" doesn't 
have the "to"). Anyway, thanks for adding the test regardless.

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Sander de Smalen via cfe-commits


@@ -0,0 +1,69 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -S -o /dev/null 
-Rpass-analysis=sme %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -S -o /dev/null 
-Rpass-analysis=sme %s -mllvm -aarch64-new-sme-abi 2>&1 | FileCheck %s 
--check-prefix=CHECK-NEWLOWERING
+
+void private_za_callee_a();
+void private_za_callee_b();
+void private_za_callee_c();
+
+void test_za_merge_paths(int a) __arm_inout("za") {
+  if (a != 0)
+private_za_callee_a();
+  else
+private_za_callee_b();
+  // The new lowering won't report this call as the save is already needed due
+  // to the call to `private_za_callee_*()` calls on both paths to this BB.
+  private_za_callee_c();
+}
+
+void test_lazy_save_multiple_paths(int a) __arm_inout("za") {
+  if (a != 0)
+private_za_callee_a();
+  else {
+private_za_callee_b();
+// The new lowering won't report this call as the save is already needed 
due
+// to the call to `private_za_callee_b()`.
+private_za_callee_c();
+  }
+}
+
+//  CHECK:  sme-remarks.c:14:5: remark: call from 'test_za_merge_paths' to 
'unknown callee' sets up a lazy save for ZA [-Rpass-analysis=sme]
+// CHECK-NEXT: 14 | private_za_callee_b();
+// CHECK-NEXT:| ^

sdesmalen-arm wrote:

You can use Clang cc1's `-verify` option, so that you can write this inline, 
e.g.

```
12: ...
13: // expected-remark@+1 {{call from 'test_za_merge_paths' to 'unknown callee' 
sets up a lazy save for ZA}}
14: private_za_callee_b();
15: ...
```

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits


@@ -706,16 +723,101 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+  }
+  if (I != MBB.end() && I->isCall())
+Calls.push_back(&*I);
+  // Note: This function always returns true if a "Marker" was found.
+  return true;
+}
+
+void MachineSMEABI::collectReachableMarkedCalls(

MacDue wrote:

There's a doc comment for `collectReachableMarkedCalls` on the `MachineSMEABI` 
class. I've added a doc comment for `findMarkedCall` :+1:  

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits


@@ -706,16 +723,101 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+  }
+  if (I != MBB.end() && I->isCall())
+Calls.push_back(&*I);
+  // Note: This function always returns true if a "Marker" was found.
+  return true;
+}
+
+void MachineSMEABI::collectReachableMarkedCalls(
+const MachineBasicBlock &StartMBB,
+MachineBasicBlock::const_iterator StartInst,
+SmallVectorImpl &Calls, unsigned Marker) const {
+  assert(Marker == AArch64::InOutZAUsePseudo ||
+ Marker == AArch64::RequiresZASavePseudo ||
+ Marker == AArch64::RequiresZT0SavePseudo);
+  unsigned CallDestroyOpcode = TII->getCallFrameDestroyOpcode();
+  if (findMarkedCall(StartMBB, StartInst, Calls, Marker, CallDestroyOpcode))
+return;
+
+  SmallPtrSet Visited;
+  SmallVector Worklist(StartMBB.succ_rbegin(),
+  StartMBB.succ_rend());
+  while (!Worklist.empty()) {
+const MachineBasicBlock *MBB = Worklist.pop_back_val();
+auto [_, Inserted] = Visited.insert(MBB);
+if (!Inserted)
+  continue;
+
+if (!findMarkedCall(*MBB, MBB->begin(), Calls, Marker, CallDestroyOpcode))
+  Worklist.append(MBB->succ_rbegin(), MBB->succ_rend());
+  }
+}
+
+static StringRef getCalleeName(const MachineInstr &CallInst) {
+  assert(CallInst.isCall() && "expected a call");
+  for (const MachineOperand &MO : CallInst.operands()) {
+if (MO.isSymbol())
+  return MO.getSymbolName();
+if (MO.isGlobal())
+  return MO.getGlobal()->getName();
+  }
+  return {};

MacDue wrote:

I don't think there's a string that could be resolved (in the IR it's just a 
`BLR %0`). Neither lowerings new/old resolve a name for indirect calls. I've 
added a test that shows this. 

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits


@@ -0,0 +1,119 @@
+; NOTE: Assertions have been autogenerated by utils/update_llc_test_checks.py
+; RUN: llc -mtriple=aarch64 -mattr=+sme2 --pass-remarks-analysis=sme -o 
/dev/null < %s 2>&1 | FileCheck %s
+; RUN: llc -mtriple=aarch64 -mattr=+sme2 --aarch64-new-sme-abi 
--pass-remarks-analysis=sme -o /dev/null < %s 2>&1 | FileCheck %s 
--check-prefix=CHECK-NEWLOWERING
+
+declare void @private_za_callee()
+declare void @private_za_callee_a()
+declare void @private_za_callee_b()
+declare void @private_za_callee_c()
+
+declare void @shared_za_callee() "aarch64_inout_za"
+declare void @shared_za_zt0_callee() "aarch64_inout_za" "aarch64_inout_zt0"
+
+; Note: These remarks are more useful with source debug info (which gives line 
numbers for `:0:0`).

MacDue wrote:

I've added a clang test for this (which should be a little easier to update). 
It also shows that resolving the callee name seems not to work for the old 
remarks, but that's unrelated to this change.

https://github.com/llvm/llvm-project/pull/170277
___
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits


[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread via cfe-commits

llvmbot wrote:




@llvm/pr-subscribers-backend-aarch64

Author: Benjamin Maxwell (MacDue)


Changes

This patch implements SME ABI pass remarks for when:

* a lazy ZA save is set up
* a full/agnostic ZA save is set up
* a ZT0 spill is emitted

These remarks can be enabled with `--pass-remarks-analysis=sme` (like the 
current SME remarks).

The remarks work by noting where the save/spill was emitted, then pointing out 
calls later in the function that require the save. The remarks stop at the 
first call found along any path.

For example:

```
 7:  void merge_paths(bool a) __arm_inout("za") {
 8:if (a)
 9:  private_za_callee_a();
10:else
11:  private_za_callee_b();
12:private_za_callee_c(); // no remark (does not require a new save)
13:  }
```

Results in the following remarks:

```
remark: foo.c:8:7: lazy save of ZA emitted in 'merge_paths'
remark: foo.c:9:5: call to 'private_za_callee_a' requires ZA save
remark: foo.c:11:5: call to 'private_za_callee_b' requires ZA save
```

---

Patch is 20.63 KiB, truncated to 20.00 KiB below, full version: 
https://github.com/llvm/llvm-project/pull/170277.diff


4 Files Affected:

- (added) clang/test/CodeGen/AArch64/sme-remarks.c (+69) 
- (modified) llvm/lib/Target/AArch64/MachineSMEABIPass.cpp (+124-4) 
- (added) llvm/test/CodeGen/AArch64/sme-abi-save-call-remarks.ll (+128) 
- (removed) llvm/test/CodeGen/AArch64/sme-lazy-save-call-remarks.ll (-25) 


``diff
diff --git a/clang/test/CodeGen/AArch64/sme-remarks.c 
b/clang/test/CodeGen/AArch64/sme-remarks.c
new file mode 100644
index 0..6dc52a69f9d1c
--- /dev/null
+++ b/clang/test/CodeGen/AArch64/sme-remarks.c
@@ -0,0 +1,69 @@
+// REQUIRES: aarch64-registered-target
+
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -S -o /dev/null 
-Rpass-analysis=sme %s 2>&1 | FileCheck %s
+// RUN: %clang_cc1 -triple aarch64 -target-feature +sme -S -o /dev/null 
-Rpass-analysis=sme %s -mllvm -aarch64-new-sme-abi 2>&1 | FileCheck %s 
--check-prefix=CHECK-NEWLOWERING
+
+void private_za_callee_a();
+void private_za_callee_b();
+void private_za_callee_c();
+
+void test_za_merge_paths(int a) __arm_inout("za") {
+  if (a != 0)
+private_za_callee_a();
+  else
+private_za_callee_b();
+  // The new lowering won't report this call as the save is already needed due
+  // to the call to `private_za_callee_*()` calls on both paths to this BB.
+  private_za_callee_c();
+}
+
+void test_lazy_save_multiple_paths(int a) __arm_inout("za") {
+  if (a != 0)
+private_za_callee_a();
+  else {
+private_za_callee_b();
+// The new lowering won't report this call as the save is already needed 
due
+// to the call to `private_za_callee_b()`.
+private_za_callee_c();
+  }
+}
+
+//  CHECK:  sme-remarks.c:14:5: remark: call from 'test_za_merge_paths' to 
'unknown callee' sets up a lazy save for ZA [-Rpass-analysis=sme]
+// CHECK-NEXT: 14 | private_za_callee_b();
+// CHECK-NEXT:| ^
+// CHECK-NEXT:  sme-remarks.c:12:5: remark: call from 'test_za_merge_paths' to 
'unknown callee' sets up a lazy save for ZA [-Rpass-analysis=sme]
+// CHECK-NEXT: 12 | private_za_callee_a();
+// CHECK-NEXT:| ^
+// CHECK-NEXT:  sme-remarks.c:17:3: remark: call from 'test_za_merge_paths' to 
'unknown callee' sets up a lazy save for ZA [-Rpass-analysis=sme]
+// CHECK-NEXT: 17 |   private_za_callee_c();
+// CHECK-NEXT:|   ^
+
+//  CHECK:  sme-remarks.c:24:5: remark: call from 
'test_lazy_save_multiple_paths' to 'unknown callee' sets up a lazy save for ZA 
[-Rpass-analysis=sme]
+// CHECK-NEXT: 24 | private_za_callee_b();
+// CHECK-NEXT:| ^
+// CHECK-NEXT:  sme-remarks.c:27:5: remark: call from 
'test_lazy_save_multiple_paths' to 'unknown callee' sets up a lazy save for ZA 
[-Rpass-analysis=sme]
+// CHECK-NEXT: 27 | private_za_callee_c();
+// CHECK-NEXT:| ^
+// CHECK-NEXT:  sme-remarks.c:22:5: remark: call from 
'test_lazy_save_multiple_paths' to 'unknown callee' sets up a lazy save for ZA 
[-Rpass-analysis=sme]
+// CHECK-NEXT: 22 | private_za_callee_a();
+// CHECK-NEXT:| ^
+
+//  CHECK-NEWLOWERING:  sme-remarks.c:11:9: remark: lazy save of ZA 
emitted in 'test_za_merge_paths' [-Rpass-analysis=sme]
+// CHECK-NEWLOWERING-NEXT:11 |   if (a != 0)
+// CHECK-NEWLOWERING-NEXT:   | ^
+// CHECK-NEWLOWERING-NEXT:  sme-remarks.c:12:5: remark: call to 
'private_za_callee_a' requires ZA save [-Rpass-analysis=sme]
+// CHECK-NEWLOWERING-NEXT:12 | private_za_callee_a();
+// CHECK-NEWLOWERING-NEXT:   | ^
+// CHECK-NEWLOWERING-NEXT:  sme-remarks.c:14:5: remark: call to 
'private_za_callee_b' requires ZA save [-Rpass-analysis=sme]
+// CHECK-NEWLOWERING-NEXT:14 | private_za_callee_b();
+// CHECK-NEWLOWERING-NEXT:   | ^
+
+//  CHECK-NEWLOWERING:  sme-remarks.c:21:9: remark: lazy save of ZA 
emitted in 'test_lazy_save_multiple_paths' [-Rpass-analysis=sme]
+// CHECK-N

[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)

2025-12-16 Thread Benjamin Maxwell via cfe-commits

https://github.com/MacDue updated 
https://github.com/llvm/llvm-project/pull/170277

>From af452bdabbad1131817f3c898ff0060a4ed2e665 Mon Sep 17 00:00:00 2001
From: Benjamin Maxwell 
Date: Mon, 1 Dec 2025 11:33:14 +
Subject: [PATCH 1/2] [AArch64][SME] Add pass remarks to the MachineSMEABIPass

This patch implements SME ABI pass remarks for when:

* a lazy ZA save is set up
* a full/agnostic ZA save is set up
* a ZT0 spill is emitted

These remarks can be enabled with `--pass-remarks-analysis=sme` (like
the current SME remarks).

The remarks work by noting where the save/spill was emitted, then
pointing out calls later in the function that require the save. The
remarks stop at the first call found along any path.

For example:

```
 7:  void merge_paths(bool a) __arm_inout("za") {
 8:if (a)
 9:  private_za_callee_a();
10:else
11:  private_za_callee_b();
12:private_za_callee_c(); // no remark (does not require a new save)
13:  }
```

Results in the following remarks:

```
remark: foo.c:8:7: lazy save of ZA emitted in 'merge_paths'
remark: foo.c:9:5: call to 'private_za_callee_a' requires ZA save
remark: foo.c:11:5: call to 'private_za_callee_b' requires ZA save
```

Change-Id: Ia7abd6f4dbeca3c9ac359df7f5251f41d1f68a8c
---
 llvm/lib/Target/AArch64/MachineSMEABIPass.cpp | 124 +-
 .../AArch64/sme-abi-save-call-remarks.ll  | 119 +
 .../AArch64/sme-lazy-save-call-remarks.ll |  25 
 3 files changed, 239 insertions(+), 29 deletions(-)
 create mode 100644 llvm/test/CodeGen/AArch64/sme-abi-save-call-remarks.ll
 delete mode 100644 llvm/test/CodeGen/AArch64/sme-lazy-save-call-remarks.ll

diff --git a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp 
b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
index b3e1ddbb91f79..98d14d238aad1 100644
--- a/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
+++ b/llvm/lib/Target/AArch64/MachineSMEABIPass.cpp
@@ -63,6 +63,7 @@
 #include "llvm/CodeGen/LivePhysRegs.h"
 #include "llvm/CodeGen/MachineBasicBlock.h"
 #include "llvm/CodeGen/MachineFunctionPass.h"
+#include "llvm/CodeGen/MachineOptimizationRemarkEmitter.h"
 #include "llvm/CodeGen/MachineRegisterInfo.h"
 #include "llvm/CodeGen/TargetRegisterInfo.h"
 
@@ -303,6 +304,7 @@ struct MachineSMEABI : public MachineFunctionPass {
   void getAnalysisUsage(AnalysisUsage &AU) const override {
 AU.setPreservesCFG();
 AU.addRequired();
+AU.addRequired();
 AU.addPreservedID(MachineLoopInfoID);
 AU.addPreservedID(MachineDominatorsID);
 MachineFunctionPass::getAnalysisUsage(AU);
@@ -391,6 +393,19 @@ struct MachineSMEABI : public MachineFunctionPass {
 return emitAllocateLazySaveBuffer(Context, MBB, MBBI);
   }
 
+  /// Collects the reachable calls from \p MBBI marked with \p Marker. This is
+  /// intended to be used to emit lazy save remarks. Note: This stops at the
+  /// first marked call along any path.
+  void collectReachableMarkedCalls(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl 
&Calls,
+   unsigned Marker) const;
+
+  void emitCallSaveRemarks(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI, DebugLoc DL,
+   unsigned Marker, StringRef RemarkName,
+   StringRef SaveName) const;
+
   /// Save live physical registers to virtual registers.
   PhysRegSave createPhysRegSave(LiveRegs PhysLiveRegs, MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI, DebugLoc DL);
@@ -406,6 +421,8 @@ struct MachineSMEABI : public MachineFunctionPass {
   const AArch64RegisterInfo *TRI = nullptr;
   const AArch64FunctionInfo *AFI = nullptr;
   const TargetInstrInfo *TII = nullptr;
+
+  MachineOptimizationRemarkEmitter *ORE = nullptr;
   MachineRegisterInfo *MRI = nullptr;
   MachineLoopInfo *MLI = nullptr;
 };
@@ -706,9 +723,91 @@ void MachineSMEABI::insertStateChanges(EmitContext 
&Context,
 
 static DebugLoc getDebugLoc(MachineBasicBlock &MBB,
 MachineBasicBlock::iterator MBBI) {
-  if (MBBI != MBB.end())
-return MBBI->getDebugLoc();
-  return DebugLoc();
+  if (MBB.empty())
+return DebugLoc();
+  return MBBI != MBB.end() ? MBBI->getDebugLoc() : MBB.back().getDebugLoc();
+}
+
+static bool findMarkedCall(const MachineBasicBlock &MBB,
+   MachineBasicBlock::const_iterator MBBI,
+   SmallVectorImpl &Calls,
+   unsigned Marker, unsigned CallDestroyOpcode) {
+  auto IsMarker = [&](auto &MI) { return MI.getOpcode() == Marker; };
+  auto MarkerInst = std::find_if(MBBI, MBB.end(), IsMarker);
+  if (MarkerInst == MBB.end())
+return false;
+  MachineBasicBlock::const_iterator I = MarkerInst;
+  while (++I != MBB.end()) {
+if (I->isCall() || I->getOpcode() == CallDestroyOpcode)
+  break;
+