Skip to content

[GVN] Handle not in equality propagation #151942

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from

Conversation

nikic
Copy link
Contributor

@nikic nikic commented Aug 4, 2025

Look through not when propagating equalities in GVN. Usually these will be canonicalized away, but they may be retained due to multi-use or involvement in logical expressions.

Fixes #143529.

@andjo403
Copy link
Contributor

andjo403 commented Aug 4, 2025

looks good to me.
it also closes #143529

@nikic nikic marked this pull request as ready for review August 4, 2025 13:24
@nikic nikic requested review from fhahn, andjo403 and dtcxzyw August 4, 2025 13:25
@llvmbot
Copy link
Member

llvmbot commented Aug 4, 2025

@llvm/pr-subscribers-llvm-transforms

Author: Nikita Popov (nikic)

Changes

Look through not when propagating equalities in GVN. Usually these will be canonicalized away, but they may be retained due to multi-use or involvement in logical expressions.

Fixes #143529.


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

2 Files Affected:

  • (modified) llvm/lib/Transforms/Scalar/GVN.cpp (+5)
  • (modified) llvm/test/Transforms/GVN/condprop.ll (+82)
diff --git a/llvm/lib/Transforms/Scalar/GVN.cpp b/llvm/lib/Transforms/Scalar/GVN.cpp
index fa6ee95d33d10..3a73b42455b0d 100644
--- a/llvm/lib/Transforms/Scalar/GVN.cpp
+++ b/llvm/lib/Transforms/Scalar/GVN.cpp
@@ -2683,6 +2683,11 @@ bool GVNPass::propagateEquality(Value *LHS, Value *RHS,
       Worklist.emplace_back(A, ConstantInt::get(A->getType(), IsKnownTrue));
       continue;
     }
+
+    if (match(LHS, m_Not(m_Value(A)))) {
+      Worklist.emplace_back(A, ConstantInt::get(A->getType(), !IsKnownTrue));
+      continue;
+    }
   }
 
   return Changed;
diff --git a/llvm/test/Transforms/GVN/condprop.ll b/llvm/test/Transforms/GVN/condprop.ll
index 3babdd8173a21..15ffcbff1e157 100644
--- a/llvm/test/Transforms/GVN/condprop.ll
+++ b/llvm/test/Transforms/GVN/condprop.ll
@@ -999,5 +999,87 @@ loop.latch:
   br label %loop
 }
 
+define i1 @not_cond(i1 %c) {
+; CHECK-LABEL: @not_cond(
+; CHECK-NEXT:    [[C_NOT:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT:    br i1 [[C_NOT]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+  %c.not = xor i1 %c, true
+  br i1 %c.not, label %if, label %else
+
+if:
+  ret i1 %c
+
+else:
+  ret i1 %c
+}
+
+define i32 @not_cond_icmp(i32 %x) {
+; CHECK-LABEL: @not_cond_icmp(
+; CHECK-NEXT:    [[CMP:%.*]] = icmp eq i32 [[X:%.*]], 42
+; CHECK-NEXT:    [[CMP_NOT:%.*]] = xor i1 [[CMP]], true
+; CHECK-NEXT:    br i1 [[CMP_NOT]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    ret i32 [[X]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i32 42
+;
+  %cmp = icmp eq i32 %x, 42
+  %cmp.not = xor i1 %cmp, true
+  br i1 %cmp.not, label %if, label %else
+
+if:
+  ret i32 %x
+
+else:
+  ret i32 %x
+}
+
+define i1 @not_cond_logic1(i1 %c, i1 %d) {
+; CHECK-LABEL: @not_cond_logic1(
+; CHECK-NEXT:    [[C_NOT:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT:    [[AND:%.*]] = and i1 [[C_NOT]], [[D:%.*]]
+; CHECK-NEXT:    br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    ret i1 false
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 [[C]]
+;
+  %c.not = xor i1 %c, true
+  %and = and i1 %c.not, %d
+  br i1 %and, label %if, label %else
+
+if:
+  ret i1 %c
+
+else:
+  ret i1 %c
+}
+
+define i1 @not_cond_logic2(i1 %c, i1 %d) {
+; CHECK-LABEL: @not_cond_logic2(
+; CHECK-NEXT:    [[C_NOT:%.*]] = xor i1 [[C:%.*]], true
+; CHECK-NEXT:    [[AND:%.*]] = or i1 [[C_NOT]], [[D:%.*]]
+; CHECK-NEXT:    br i1 [[AND]], label [[IF:%.*]], label [[ELSE:%.*]]
+; CHECK:       if:
+; CHECK-NEXT:    ret i1 [[C]]
+; CHECK:       else:
+; CHECK-NEXT:    ret i1 true
+;
+  %c.not = xor i1 %c, true
+  %or = or i1 %c.not, %d
+  br i1 %or, label %if, label %else
+
+if:
+  ret i1 %c
+
+else:
+  ret i1 %c
+}
+
 declare void @use_bool(i1)
 declare void @use_ptr(ptr)

Copy link
Contributor

@fhahn fhahn left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM, thanks

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Missed optimization: propagate not of trunc nuw ... it1 equalities
5 participants