[llvm] [RISCV] Port RISCVZacasABIFix to NewPM (PR #214866)
Sam Elliott via llvm-commits
llvm-commits at lists.llvm.org
Fri Aug 7 15:50:15 PDT 2026
https://github.com/lenary updated https://github.com/llvm/llvm-project/pull/214866
>From 4b606a61a8c70b88afc6592dba0b4cd8fac2fe09 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 15:23:10 -0700
Subject: [PATCH 1/2] [RISCV] Port RISCVZacasABIFix to NewPM
Assisted-by: AI
---
llvm/lib/Target/RISCV/RISCV.h | 11 +++-
.../Target/RISCV/RISCVCodeGenPassBuilder.cpp | 2 +-
llvm/lib/Target/RISCV/RISCVPassRegistry.def | 1 +
llvm/lib/Target/RISCV/RISCVTargetMachine.cpp | 1 +
llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp | 66 +++++++++++++------
llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll | 1 +
llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll | 1 +
.../test/CodeGen/RISCV/riscv-zacas-abi-fix.ll | 41 ++++++++++++
8 files changed, 101 insertions(+), 23 deletions(-)
create mode 100644 llvm/test/CodeGen/RISCV/riscv-zacas-abi-fix.ll
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index 013cb57565d93..f66291d7ae755 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -112,8 +112,17 @@ void initializeRISCVLoadStoreOptPass(PassRegistry &);
FunctionPass *createRISCVPreAllocZilsdOptPass();
void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
+class RISCVZacasABIFixPass
+ : public RequiredPassInfoMixin<RISCVZacasABIFixPass> {
+private:
+ const RISCVTargetMachine *TM;
+
+public:
+ RISCVZacasABIFixPass(const RISCVTargetMachine *TM) : TM(TM) {}
+ PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
+};
FunctionPass *createRISCVZacasABIFixPass();
-void initializeRISCVZacasABIFixPass(PassRegistry &);
+void initializeRISCVZacasABIFixLegacyPass(PassRegistry &);
InstructionSelector *
createRISCVInstructionSelector(const RISCVTargetMachine &,
diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index d198392ce8599..7ccaa74cbb208 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -65,7 +65,7 @@ class RISCVCodeGenPassBuilder
void RISCVCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) const {
addFunctionPass(AtomicExpandPass(TM), PMW);
- // TODO: RISCVZacasABIFixPass
+ addFunctionPass(RISCVZacasABIFixPass(&TM), PMW);
if (getOptLevel() != CodeGenOptLevel::None) {
addFunctionPass(LoopDataPrefetchPass(), PMW);
diff --git a/llvm/lib/Target/RISCV/RISCVPassRegistry.def b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
index b42e8ea5b9f35..d954cf36e85e1 100644
--- a/llvm/lib/Target/RISCV/RISCVPassRegistry.def
+++ b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
@@ -17,6 +17,7 @@
#define FUNCTION_PASS(NAME, CREATE_PASS)
#endif
FUNCTION_PASS("riscv-codegenprepare", RISCVCodeGenPreparePass(this))
+FUNCTION_PASS("riscv-zacas-abi-fix", RISCVZacasABIFixPass(this))
#undef FUNCTION_PASS
#ifndef MACHINE_FUNCTION_PASS
diff --git a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
index 517e48faa1043..e5ebd2a071d05 100644
--- a/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
+++ b/llvm/lib/Target/RISCV/RISCVTargetMachine.cpp
@@ -129,6 +129,7 @@ extern "C" LLVM_ABI LLVM_EXTERNAL_VISIBILITY void LLVMInitializeRISCVTarget() {
initializeRISCVQCRelaxMarkingPass(*PR);
initializeRISCVGatherScatterLoweringPass(*PR);
initializeRISCVCodeGenPrepareLegacyPassPass(*PR);
+ initializeRISCVZacasABIFixLegacyPass(*PR);
initializeRISCVPostRAExpandPseudoPass(*PR);
initializeRISCVMergeBaseOffsetOptPass(*PR);
initializeRISCVOptWInstrsPass(*PR);
diff --git a/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp b/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
index 613b434e9222a..57dd10dbeb951 100644
--- a/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
+++ b/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
@@ -29,15 +29,23 @@ using namespace llvm;
#define PASS_NAME "RISC-V Zacas ABI fix"
namespace {
-
-class RISCVZacasABIFix : public FunctionPass,
- public InstVisitor<RISCVZacasABIFix, bool> {
+class RISCVZacasABIFix : public InstVisitor<RISCVZacasABIFix, bool> {
const RISCVSubtarget *ST;
+public:
+ RISCVZacasABIFix(const RISCVSubtarget *ST) : ST(ST) {}
+ bool run(Function &F);
+ bool visitInstruction(Instruction &I) { return false; }
+ bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
+};
+} // namespace
+
+namespace {
+class RISCVZacasABIFixLegacy : public FunctionPass {
public:
static char ID;
- RISCVZacasABIFix() : FunctionPass(ID) {}
+ RISCVZacasABIFixLegacy() : FunctionPass(ID) {}
bool runOnFunction(Function &F) override;
@@ -47,12 +55,8 @@ class RISCVZacasABIFix : public FunctionPass,
AU.setPreservesCFG();
AU.addRequired<TargetPassConfig>();
}
-
- bool visitInstruction(Instruction &I) { return false; }
- bool visitAtomicCmpXchgInst(AtomicCmpXchgInst &I);
};
-
-} // end anonymous namespace
+} // namespace
// Insert a leading fence (needed for broadest atomics ABI compatibility)
// only if the Zacas extension is enabled and the AtomicCmpXchgInst has a
@@ -67,14 +71,7 @@ bool RISCVZacasABIFix::visitAtomicCmpXchgInst(AtomicCmpXchgInst &I) {
return true;
}
-bool RISCVZacasABIFix::runOnFunction(Function &F) {
- auto &TPC = getAnalysis<TargetPassConfig>();
- auto &TM = TPC.getTM<RISCVTargetMachine>();
- ST = &TM.getSubtarget<RISCVSubtarget>(F);
-
- if (skipFunction(F) || !ST->hasStdExtZacas())
- return false;
-
+bool RISCVZacasABIFix::run(Function &F) {
bool MadeChange = false;
for (auto &BB : F)
for (Instruction &I : llvm::make_early_inc_range(BB))
@@ -83,12 +80,39 @@ bool RISCVZacasABIFix::runOnFunction(Function &F) {
return MadeChange;
}
-INITIALIZE_PASS_BEGIN(RISCVZacasABIFix, DEBUG_TYPE, PASS_NAME, false, false)
+bool RISCVZacasABIFixLegacy::runOnFunction(Function &F) {
+ auto &TPC = getAnalysis<TargetPassConfig>();
+ auto &TM = TPC.getTM<RISCVTargetMachine>();
+ auto *ST = &TM.getSubtarget<RISCVSubtarget>(F);
+
+ if (skipFunction(F) || !ST->hasStdExtZacas())
+ return false;
+
+ return RISCVZacasABIFix(ST).run(F);
+}
+
+INITIALIZE_PASS_BEGIN(RISCVZacasABIFixLegacy, DEBUG_TYPE, PASS_NAME, false,
+ false)
INITIALIZE_PASS_DEPENDENCY(TargetPassConfig)
-INITIALIZE_PASS_END(RISCVZacasABIFix, DEBUG_TYPE, PASS_NAME, false, false)
+INITIALIZE_PASS_END(RISCVZacasABIFixLegacy, DEBUG_TYPE, PASS_NAME, false, false)
-char RISCVZacasABIFix::ID = 0;
+char RISCVZacasABIFixLegacy::ID = 0;
FunctionPass *llvm::createRISCVZacasABIFixPass() {
- return new RISCVZacasABIFix();
+ return new RISCVZacasABIFixLegacy();
+}
+
+PreservedAnalyses RISCVZacasABIFixPass::run(Function &F,
+ FunctionAnalysisManager &FAM) {
+ auto *ST = &TM->getSubtarget<RISCVSubtarget>(F);
+ if (!ST->hasStdExtZacas())
+ return PreservedAnalyses::all();
+
+ bool Changed = RISCVZacasABIFix(ST).run(F);
+ if (!Changed)
+ return PreservedAnalyses::all();
+
+ PreservedAnalyses PA = PreservedAnalyses::none();
+ PA.preserveSet<CFGAnalyses>();
+ return PA;
}
diff --git a/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
index 92d894d445447..291a95830dfd3 100644
--- a/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O1-newpm-pipeline.ll
@@ -14,6 +14,7 @@
; CHECK-NEXT: function
; CHECK-NEXT: expand-ir-insts<O1>
; CHECK-NEXT: atomic-expand
+; CHECK-NEXT: riscv-zacas-abi-fix
; CHECK-NEXT: loop-data-prefetch
; CHECK-NEXT: interleaved-access
; CHECK-NEXT: riscv-codegenprepare
diff --git a/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
index 8fc45d046384e..69db5f46c3268 100644
--- a/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
+++ b/llvm/test/CodeGen/RISCV/O3-newpm-pipeline.ll
@@ -14,6 +14,7 @@
; CHECK-NEXT: function
; CHECK-NEXT: expand-ir-insts<O3>
; CHECK-NEXT: atomic-expand
+; CHECK-NEXT: riscv-zacas-abi-fix
; CHECK-NEXT: loop-data-prefetch
; CHECK-NEXT: interleaved-access
; CHECK-NEXT: riscv-codegenprepare
diff --git a/llvm/test/CodeGen/RISCV/riscv-zacas-abi-fix.ll b/llvm/test/CodeGen/RISCV/riscv-zacas-abi-fix.ll
new file mode 100644
index 0000000000000..6c280c73a9dd6
--- /dev/null
+++ b/llvm/test/CodeGen/RISCV/riscv-zacas-abi-fix.ll
@@ -0,0 +1,41 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt %s -S -riscv-zacas-abi-fix -mtriple=riscv64 -mattr=+a,+zacas | FileCheck %s --check-prefixes=CHECK,ZACAS
+; RUN: opt %s -S -passes=riscv-zacas-abi-fix -mtriple=riscv64 -mattr=+a,+zacas | FileCheck %s --check-prefixes=CHECK,ZACAS
+; RUN: opt %s -S -riscv-zacas-abi-fix -mtriple=riscv64 -mattr=+a | FileCheck %s --check-prefixes=CHECK,NOZACAS
+; RUN: opt %s -S -passes=riscv-zacas-abi-fix -mtriple=riscv64 -mattr=+a | FileCheck %s --check-prefixes=CHECK,NOZACAS
+
+; A cmpxchg with a seq_cst failure ordering needs a leading fence for the
+; broadest atomics ABI compatibility, but only when Zacas is enabled.
+
+define i32 @cmpxchg_seq_cst_failure(ptr %ptr, i32 %cmp, i32 %new) {
+; ZACAS-LABEL: define i32 @cmpxchg_seq_cst_failure(
+; ZACAS-SAME: ptr [[PTR:%.*]], i32 [[CMP:%.*]], i32 [[NEW:%.*]]) #[[ATTR0:[0-9]+]] {
+; ZACAS-NEXT: fence seq_cst
+; ZACAS-NEXT: [[RES:%.*]] = cmpxchg ptr [[PTR]], i32 [[CMP]], i32 [[NEW]] seq_cst seq_cst, align 4
+; ZACAS-NEXT: [[VAL:%.*]] = extractvalue { i32, i1 } [[RES]], 0
+; ZACAS-NEXT: ret i32 [[VAL]]
+;
+; NOZACAS-LABEL: define i32 @cmpxchg_seq_cst_failure(
+; NOZACAS-SAME: ptr [[PTR:%.*]], i32 [[CMP:%.*]], i32 [[NEW:%.*]]) #[[ATTR0:[0-9]+]] {
+; NOZACAS-NEXT: [[RES:%.*]] = cmpxchg ptr [[PTR]], i32 [[CMP]], i32 [[NEW]] seq_cst seq_cst, align 4
+; NOZACAS-NEXT: [[VAL:%.*]] = extractvalue { i32, i1 } [[RES]], 0
+; NOZACAS-NEXT: ret i32 [[VAL]]
+;
+ %res = cmpxchg ptr %ptr, i32 %cmp, i32 %new seq_cst seq_cst
+ %val = extractvalue { i32, i1 } %res, 0
+ ret i32 %val
+}
+
+; A cmpxchg with a weaker failure ordering never needs a leading fence.
+
+define i32 @cmpxchg_monotonic_failure(ptr %ptr, i32 %cmp, i32 %new) {
+; CHECK-LABEL: define i32 @cmpxchg_monotonic_failure(
+; CHECK-SAME: ptr [[PTR:%.*]], i32 [[CMP:%.*]], i32 [[NEW:%.*]]) #[[ATTR0:[0-9]+]] {
+; CHECK-NEXT: [[RES:%.*]] = cmpxchg ptr [[PTR]], i32 [[CMP]], i32 [[NEW]] seq_cst monotonic, align 4
+; CHECK-NEXT: [[VAL:%.*]] = extractvalue { i32, i1 } [[RES]], 0
+; CHECK-NEXT: ret i32 [[VAL]]
+;
+ %res = cmpxchg ptr %ptr, i32 %cmp, i32 %new seq_cst monotonic
+ %val = extractvalue { i32, i1 } %res, 0
+ ret i32 %val
+}
>From ca74a0533f7879a6c7ad498560b9717321ef7b97 Mon Sep 17 00:00:00 2001
From: Sam Elliott <aelliott at qti.qualcomm.com>
Date: Fri, 7 Aug 2026 15:49:17 -0700
Subject: [PATCH 2/2] Use const reference for RISCVTargetMachine
---
llvm/lib/Target/RISCV/RISCV.h | 4 ++--
llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp | 2 +-
llvm/lib/Target/RISCV/RISCVPassRegistry.def | 2 +-
llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp | 2 +-
4 files changed, 5 insertions(+), 5 deletions(-)
diff --git a/llvm/lib/Target/RISCV/RISCV.h b/llvm/lib/Target/RISCV/RISCV.h
index f66291d7ae755..33d824c94c1ef 100644
--- a/llvm/lib/Target/RISCV/RISCV.h
+++ b/llvm/lib/Target/RISCV/RISCV.h
@@ -115,10 +115,10 @@ void initializeRISCVPreAllocZilsdOptPass(PassRegistry &);
class RISCVZacasABIFixPass
: public RequiredPassInfoMixin<RISCVZacasABIFixPass> {
private:
- const RISCVTargetMachine *TM;
+ const RISCVTargetMachine &TM;
public:
- RISCVZacasABIFixPass(const RISCVTargetMachine *TM) : TM(TM) {}
+ RISCVZacasABIFixPass(const RISCVTargetMachine &TM) : TM(TM) {}
PreservedAnalyses run(Function &F, FunctionAnalysisManager &FAM);
};
FunctionPass *createRISCVZacasABIFixPass();
diff --git a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
index 7ccaa74cbb208..3613f9c20dd31 100644
--- a/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
+++ b/llvm/lib/Target/RISCV/RISCVCodeGenPassBuilder.cpp
@@ -65,7 +65,7 @@ class RISCVCodeGenPassBuilder
void RISCVCodeGenPassBuilder::addIRPasses(PassManagerWrapper &PMW) const {
addFunctionPass(AtomicExpandPass(TM), PMW);
- addFunctionPass(RISCVZacasABIFixPass(&TM), PMW);
+ addFunctionPass(RISCVZacasABIFixPass(TM), PMW);
if (getOptLevel() != CodeGenOptLevel::None) {
addFunctionPass(LoopDataPrefetchPass(), PMW);
diff --git a/llvm/lib/Target/RISCV/RISCVPassRegistry.def b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
index d954cf36e85e1..0c5921f306b75 100644
--- a/llvm/lib/Target/RISCV/RISCVPassRegistry.def
+++ b/llvm/lib/Target/RISCV/RISCVPassRegistry.def
@@ -17,7 +17,7 @@
#define FUNCTION_PASS(NAME, CREATE_PASS)
#endif
FUNCTION_PASS("riscv-codegenprepare", RISCVCodeGenPreparePass(this))
-FUNCTION_PASS("riscv-zacas-abi-fix", RISCVZacasABIFixPass(this))
+FUNCTION_PASS("riscv-zacas-abi-fix", RISCVZacasABIFixPass(*this))
#undef FUNCTION_PASS
#ifndef MACHINE_FUNCTION_PASS
diff --git a/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp b/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
index 57dd10dbeb951..1d8a96e4e59d6 100644
--- a/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
+++ b/llvm/lib/Target/RISCV/RISCVZacasABIFix.cpp
@@ -104,7 +104,7 @@ FunctionPass *llvm::createRISCVZacasABIFixPass() {
PreservedAnalyses RISCVZacasABIFixPass::run(Function &F,
FunctionAnalysisManager &FAM) {
- auto *ST = &TM->getSubtarget<RISCVSubtarget>(F);
+ auto *ST = &TM.getSubtarget<RISCVSubtarget>(F);
if (!ST->hasStdExtZacas())
return PreservedAnalyses::all();
More information about the llvm-commits
mailing list