[clang] [llvm] [AArch64][SME] Add pass remarks to the MachineSMEABIPass (PR #170277)
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)
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)
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)
@@ -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)
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)
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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
@@ -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)
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)
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;
+
