[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