[llvm] e51b7bf - [InstCombine] Fix inversion of constants

Roman Lebedev via llvm-commits llvm-commits at lists.llvm.org
Tue Dec 20 07:20:45 PST 2022


Author: Roman Lebedev
Date: 2022-12-20T18:20:32+03:00
New Revision: e51b7bff192f5c2712009a28eed1544ff45913c1

URL: https://github.com/llvm/llvm-project/commit/e51b7bff192f5c2712009a28eed1544ff45913c1
DIFF: https://github.com/llvm/llvm-project/commit/e51b7bff192f5c2712009a28eed1544ff45913c1.diff

LOG: [InstCombine] Fix inversion of constants

`canFreelyInvertAllUsersOf()`, in general, does not make sense
for constants, and constant expressions are likely even more problematic.
For those, we just want to create a simple constant expression and be done.

Fixes https://github.com/llvm/llvm-project/issues/59613

Added: 
    llvm/test/Transforms/InstCombine/pr59613.ll

Modified: 
    llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
    llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
index 92df0e403508b..a876385581e72 100644
--- a/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
+++ b/llvm/include/llvm/Transforms/InstCombine/InstCombiner.h
@@ -273,9 +273,10 @@ class LLVM_LIBRARY_VISIBILITY InstCombiner {
 
   /// Given i1 V, can every user of V be freely adapted if V is changed to !V ?
   /// InstCombine's freelyInvertAllUsersOf() must be kept in sync with this fn.
+  /// NOTE: for Instructions only!
   ///
   /// See also: isFreeToInvert()
-  static bool canFreelyInvertAllUsersOf(Value *V, Value *IgnoredUser) {
+  static bool canFreelyInvertAllUsersOf(Instruction *V, Value *IgnoredUser) {
     // Look at every user of V.
     for (Use &U : V->uses()) {
       if (U.getUser() == IgnoredUser)

diff  --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 5634008b91fc6..784343532c223 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3678,17 +3678,24 @@ bool InstCombinerImpl::sinkNotIntoLogicalOp(Instruction &I) {
 
   // And can the operands be adapted?
   for (Value *Op : {Op0, Op1})
-    if (!InstCombiner::isFreeToInvert(Op, /*WillInvertAllUses=*/true) ||
-        !InstCombiner::canFreelyInvertAllUsersOf(Op, /*IgnoredUser=*/&I))
+    if (!(InstCombiner::isFreeToInvert(Op, /*WillInvertAllUses=*/true) &&
+          (isa<Constant>(Op) ||
+           InstCombiner::canFreelyInvertAllUsersOf(cast<Instruction>(Op),
+                                                   /*IgnoredUser=*/&I))))
       return false;
 
   for (Value **Op : {&Op0, &Op1}) {
-    Builder.SetInsertPoint(
-        &*cast<Instruction>(*Op)->getInsertionPointAfterDef());
-    Value *NotOp = Builder.CreateNot(*Op, (*Op)->getName() + ".not");
-    (*Op)->replaceUsesWithIf(NotOp,
-                             [NotOp](Use &U) { return U.getUser() != NotOp; });
-    freelyInvertAllUsersOf(NotOp, /*IgnoredUser=*/&I);
+    Value *NotOp;
+    if (auto *C = dyn_cast<Constant>(*Op)) {
+      NotOp = ConstantExpr::getNot(C);
+    } else {
+      Builder.SetInsertPoint(
+          &*cast<Instruction>(*Op)->getInsertionPointAfterDef());
+      NotOp = Builder.CreateNot(*Op, (*Op)->getName() + ".not");
+      (*Op)->replaceUsesWithIf(
+          NotOp, [NotOp](Use &U) { return U.getUser() != NotOp; });
+      freelyInvertAllUsersOf(NotOp, /*IgnoredUser=*/&I);
+    }
     *Op = NotOp;
   }
 
@@ -3726,12 +3733,15 @@ bool InstCombinerImpl::sinkNotIntoOtherHandOfLogicalOp(Instruction &I) {
   Value **OpToInvert = nullptr;
   if (match(Op0, m_Not(m_Value(NotOp0))) &&
       InstCombiner::isFreeToInvert(Op1, /*WillInvertAllUses=*/true) &&
-      InstCombiner::canFreelyInvertAllUsersOf(Op1, /*IgnoredUser=*/&I)) {
+      (isa<Constant>(Op1) || InstCombiner::canFreelyInvertAllUsersOf(
+                                 cast<Instruction>(Op1), /*IgnoredUser=*/&I))) {
     Op0 = NotOp0;
     OpToInvert = &Op1;
   } else if (match(Op1, m_Not(m_Value(NotOp1))) &&
              InstCombiner::isFreeToInvert(Op0, /*WillInvertAllUses=*/true) &&
-             InstCombiner::canFreelyInvertAllUsersOf(Op0, /*IgnoredUser=*/&I)) {
+             (isa<Constant>(Op0) ||
+              InstCombiner::canFreelyInvertAllUsersOf(cast<Instruction>(Op0),
+                                                      /*IgnoredUser=*/&I))) {
     Op1 = NotOp1;
     OpToInvert = &Op0;
   } else
@@ -3741,15 +3751,19 @@ bool InstCombinerImpl::sinkNotIntoOtherHandOfLogicalOp(Instruction &I) {
   if (!InstCombiner::canFreelyInvertAllUsersOf(&I, /*IgnoredUser=*/nullptr))
     return false;
 
-  Builder.SetInsertPoint(
-      &*cast<Instruction>(*OpToInvert)->getInsertionPointAfterDef());
-  Value *NotOpToInvert =
-      Builder.CreateNot(*OpToInvert, (*OpToInvert)->getName() + ".not");
-  (*OpToInvert)->replaceUsesWithIf(NotOpToInvert, [NotOpToInvert](Use &U) {
-    return U.getUser() != NotOpToInvert;
-  });
-  freelyInvertAllUsersOf(NotOpToInvert, /*IgnoredUser=*/&I);
-  *OpToInvert = NotOpToInvert;
+  if (auto *C = dyn_cast<Constant>(*OpToInvert)) {
+    *OpToInvert = ConstantExpr::getNot(C);
+  } else {
+    Builder.SetInsertPoint(
+        &*cast<Instruction>(*OpToInvert)->getInsertionPointAfterDef());
+    Value *NotOpToInvert =
+        Builder.CreateNot(*OpToInvert, (*OpToInvert)->getName() + ".not");
+    (*OpToInvert)->replaceUsesWithIf(NotOpToInvert, [NotOpToInvert](Use &U) {
+      return U.getUser() != NotOpToInvert;
+    });
+    freelyInvertAllUsersOf(NotOpToInvert, /*IgnoredUser=*/&I);
+    *OpToInvert = NotOpToInvert;
+  }
 
   Builder.SetInsertPoint(&*I.getInsertionPointAfterDef());
   Value *NewBinOp;
@@ -3861,8 +3875,9 @@ Instruction *InstCombinerImpl::foldNot(BinaryOperator &I) {
   // not (cmp A, B) = !cmp A, B
   CmpInst::Predicate Pred;
   if (match(NotOp, m_Cmp(Pred, m_Value(), m_Value())) &&
-      (NotOp->hasOneUse() || InstCombiner::canFreelyInvertAllUsersOf(
-                                 NotOp, /*IgnoredUser=*/nullptr))) {
+      (NotOp->hasOneUse() ||
+       InstCombiner::canFreelyInvertAllUsersOf(cast<Instruction>(NotOp),
+                                               /*IgnoredUser=*/nullptr))) {
     cast<CmpInst>(NotOp)->setPredicate(CmpInst::getInversePredicate(Pred));
     freelyInvertAllUsersOf(NotOp);
     return &I;

diff  --git a/llvm/test/Transforms/InstCombine/pr59613.ll b/llvm/test/Transforms/InstCombine/pr59613.ll
new file mode 100644
index 0000000000000..a669a0d4207e9
--- /dev/null
+++ b/llvm/test/Transforms/InstCombine/pr59613.ll
@@ -0,0 +1,16 @@
+; NOTE: Assertions have been autogenerated by utils/update_test_checks.py
+; RUN: opt < %s -passes=instcombine -S | FileCheck %s
+
+; This used to crash, depending on the particular worklist iteration order.
+define void @pr59613(<6 x i16> %0) {
+; CHECK-LABEL: @pr59613(
+; CHECK-NEXT:    store <6 x i16> poison, ptr null, align 4294967296
+; CHECK-NEXT:    ret void
+;
+  %cmp1 = icmp ne <6 x i16> %0, zeroinitializer
+  %or = or <6 x i1> <i1 true, i1 false, i1 false, i1 false, i1 undef, i1 undef>, %cmp1
+  %sext = sext <6 x i1> %or to <6 x i16>
+  %not = xor <6 x i16> %sext, <i16 -1, i16 -1, i16 -1, i16 -1, i16 -1, i16 -1>
+  store <6 x i16> %not, ptr null, align 16
+  ret void
+}


        


More information about the llvm-commits mailing list