[llvm] [GVN] Replace cmp with not instruction if inv cmp is found (PR #223171)

via llvm-commits llvm-commits at lists.llvm.org
Sat Sep 12 13:31:34 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: Andreas Jonson (andjo403)

<details>
<summary>Changes</summary>



---
Full diff: https://github.com/llvm/llvm-project/pull/223171.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+22-10) 
- (added) llvm/test/Transforms/GVN/inverse-cmp.ll (+52) 


``````````diff
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index c8989a4c8e0d4..acad4b311b2cf 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -3445,18 +3445,30 @@ bool GVNPass::processInstruction(Instruction *I) {
     }
   }
 
-  // If the number we were assigned was a brand new VN, then we don't
-  // need to do a lookup to see if the number already exists
-  // somewhere in the domtree: it can't!
-  if (Num >= NextNum) {
-    LeaderTable.insert(Num, I, I->getParent());
-    return false;
-  }
-
   // Perform fast-path value-number based elimination of values inherited from
-  // dominators.
-  Value *Repl = findLeader(I->getParent(), Num);
+  // dominators, unless if the number we were assigned was a brand new VN, then
+  // we don't need to do a lookup to see if the number already exists somewhere
+  // in the domtree: it can't!
+  Value *Repl = Num < NextNum ? findLeader(I->getParent(), Num) : nullptr;
   if (!Repl) {
+    // substiut cmp instruction with not if possible.
+    if (CmpInst *Cmp = dyn_cast<CmpInst>(I)) {
+      uint32_t NextNumNot = VN.getNextUnusedValueNumber();
+      uint32_t NotNum =
+          VN.lookupOrAddCmp(Cmp->getOpcode(), Cmp->getInversePredicate(),
+                            Cmp->getOperand(0), Cmp->getOperand(1));
+      if (NotNum < NextNumNot) {
+        Value *NotRepl = findLeader(I->getParent(), NotNum);
+        if (NotRepl && NotRepl != I) {
+          BinaryOperator *Not = BinaryOperator::CreateNot(
+              NotRepl, NotRepl->getName() + ".not", I->getIterator());
+          Not->setDebugLoc(I->getDebugLoc());
+          I->replaceAllUsesWith(Not);
+          salvageAndRemoveInstruction(I);
+          return true;
+        }
+      }
+    }
     // Failure, just remember this instance for future use.
     LeaderTable.insert(Num, I, I->getParent());
     return false;
diff --git a/llvm/test/Transforms/GVN/inverse-cmp.ll b/llvm/test/Transforms/GVN/inverse-cmp.ll
new file mode 100644
index 0000000000000..b874cd55b873a
--- /dev/null
+++ b/llvm/test/Transforms/GVN/inverse-cmp.ll
@@ -0,0 +1,52 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 6
+; RUN: opt -passes=gvn -S < %s | FileCheck %s
+
+declare void @use(i1)
+
+define void @inverse_icmp(i32 %x,i32 %y) {
+; CHECK-LABEL: define void @inverse_icmp(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[UGT1:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT:    call void @use(i1 [[UGT1]])
+; CHECK-NEXT:    [[UGT1_NOT:%.*]] = xor i1 [[UGT1]], true
+; CHECK-NEXT:    call void @use(i1 [[UGT1_NOT]])
+; CHECK-NEXT:    ret void
+;
+  %ugt1 = icmp ugt i32 %x, %y
+  call void @use(i1 %ugt1)
+  %ule1 = icmp ule i32 %x, %y
+  call void @use(i1 %ule1)
+  ret void
+}
+
+define void @inverse_fcmp(double %x,double %y) {
+; CHECK-LABEL: define void @inverse_fcmp(
+; CHECK-SAME: double [[X:%.*]], double [[Y:%.*]]) {
+; CHECK-NEXT:    [[OGT1:%.*]] = fcmp ogt double [[X]], [[Y]]
+; CHECK-NEXT:    call void @use(i1 [[OGT1]])
+; CHECK-NEXT:    [[OGT1_NOT:%.*]] = xor i1 [[OGT1]], true
+; CHECK-NEXT:    call void @use(i1 [[OGT1_NOT]])
+; CHECK-NEXT:    ret void
+;
+  %ogt1 = fcmp ogt double %x, %y
+  call void @use(i1 %ogt1)
+  %ule1 = fcmp ule double %x, %y
+  call void @use(i1 %ule1)
+  ret void
+}
+
+define void @inverse_icmp_swaped(i32 %x,i32 %y) {
+; CHECK-LABEL: define void @inverse_icmp_swaped(
+; CHECK-SAME: i32 [[X:%.*]], i32 [[Y:%.*]]) {
+; CHECK-NEXT:    [[UGT1:%.*]] = icmp ugt i32 [[X]], [[Y]]
+; CHECK-NEXT:    call void @use(i1 [[UGT1]])
+; CHECK-NEXT:    [[UGT1_NOT:%.*]] = xor i1 [[UGT1]], true
+; CHECK-NEXT:    call void @use(i1 [[UGT1_NOT]])
+; CHECK-NEXT:    ret void
+;
+  %ugt = icmp ugt i32 %x, %y
+  call void @use(i1 %ugt)
+  %ule = icmp uge i32 %y, %x
+  call void @use(i1 %ule)
+  ret void
+}

``````````

</details>


https://github.com/llvm/llvm-project/pull/223171


More information about the llvm-commits mailing list