[llvm-branch-commits] [llvm] [InstCombine] Canonicalize atomicrmw sub of a constant to add (PR #232626)

Harrison Hao via llvm-branch-commits llvm-branch-commits at lists.llvm.org
Fri Oct 16 00:04:25 PDT 2026


https://github.com/harrisonGPU created https://github.com/llvm/llvm-project/pull/232626

Rewrite `atomicrmw sub ptr, C` as `atomicrmw add ptr, -C`. This
matches the canonical form InstCombine already uses for plain `sub`.
In wrapping arithmetic $old - C = old + (-C)$, so both the stored
value and the returned old value stay the same, including when C is
`INT_MIN`. Ordering, syncscope and metadata are kept.

```llvm
; before
%old = atomicrmw sub ptr %p, i32 1 syncscope("agent") monotonic
; after
%old = atomicrmw add ptr %p, i32 -1 syncscope("agent") monotonic
```
This benefits AMDGPU, for example: https://godbolt.org/z/39xsYro3o

---

<sub>Stack created with <a href="https://github.com/github/gh-stack">GitHub Stacks CLI</a> • <a href="https://gh.io/stacks-feedback">Give Feedback 💬</a></sub>

>From a494c7b7c8f0f643033bda1e1ae760df2f100224 Mon Sep 17 00:00:00 2001
From: Harrison Hao <tsworld1314 at gmail.com>
Date: Fri, 16 Oct 2026 14:35:13 +0800
Subject: [PATCH] [InstCombine] Canonicalize atomicrmw sub of a constant to add

Rewrite `atomicrmw sub ptr, C` as `atomicrmw add ptr, -C`. This
matches the canonical form InstCombine already uses for plain `sub`.
In wrapping arithmetic $old - C = old + (-C)$, so both the stored
value and the returned old value stay the same, including when C is
`INT_MIN`. Ordering, syncscope and metadata are kept.

```llvm
; before
%old = atomicrmw sub ptr %p, i32 1 syncscope("agent") monotonic
; after
%old = atomicrmw add ptr %p, i32 -1 syncscope("agent") monotonic
```
This benefits AMDGPU, for example: https://godbolt.org/z/39xsYro3o
---
 llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp | 7 +++++++
 llvm/test/Transforms/InstCombine/atomicrmw-add-neg.ll    | 4 ++--
 2 files changed, 9 insertions(+), 2 deletions(-)

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
index 4d6b0684abe4da..f9eab910fc56ae 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAtomicRMW.cpp
@@ -134,6 +134,13 @@ Instruction *InstCombinerImpl::visitAtomicRMWInst(AtomicRMWInst &RMWI) {
                                                  : AtomicRMWInst::Add);
       return replaceOperand(RMWI, 1, X);
     }
+
+    // atomicrmw sub(ptr, C) -> atomicrmw add(ptr, -C)
+    const APInt *C;
+    if (Op == AtomicRMWInst::Sub && match(Val, m_APInt(C)) && !C->isZero()) {
+      RMWI.setOperation(AtomicRMWInst::Add);
+      return replaceOperand(RMWI, 1, ConstantInt::get(RMWI.getType(), -*C));
+    }
   }
 
   if (!isIdempotentRMW(RMWI))
diff --git a/llvm/test/Transforms/InstCombine/atomicrmw-add-neg.ll b/llvm/test/Transforms/InstCombine/atomicrmw-add-neg.ll
index 05f38e749910d6..48212c9df7a8d8 100644
--- a/llvm/test/Transforms/InstCombine/atomicrmw-add-neg.ll
+++ b/llvm/test/Transforms/InstCombine/atomicrmw-add-neg.ll
@@ -97,7 +97,7 @@ define i64 @fn_add_of_two_vars(ptr %p, i64 %a, i64 %b) {
 define i32 @fn_sub_const(ptr %a) {
 ; CHECK-LABEL: define i32 @fn_sub_const(
 ; CHECK-SAME: ptr [[A:%.*]]) {
-; CHECK-NEXT:    [[OLD:%.*]] = atomicrmw sub ptr [[A]], i32 5 syncscope("agent") acq_rel, align 4
+; CHECK-NEXT:    [[OLD:%.*]] = atomicrmw add ptr [[A]], i32 -5 syncscope("agent") acq_rel, align 4
 ; CHECK-NEXT:    ret i32 [[OLD]]
 ;
   %old = atomicrmw sub ptr %a, i32 5 syncscope("agent") acq_rel
@@ -107,7 +107,7 @@ define i32 @fn_sub_const(ptr %a) {
 define i64 @fn_sub_const_int_min(ptr %a) {
 ; CHECK-LABEL: define i64 @fn_sub_const_int_min(
 ; CHECK-SAME: ptr [[A:%.*]]) {
-; CHECK-NEXT:    [[OLD:%.*]] = atomicrmw sub ptr [[A]], i64 -9223372036854775808 monotonic, align 8
+; CHECK-NEXT:    [[OLD:%.*]] = atomicrmw add ptr [[A]], i64 -9223372036854775808 monotonic, align 8
 ; CHECK-NEXT:    ret i64 [[OLD]]
 ;
   %old = atomicrmw sub ptr %a, i64 -9223372036854775808 monotonic



More information about the llvm-branch-commits mailing list