Bug type: miscompilation
Component: InstCombine
ValueTracking
Bug location: llvm/lib/Analysis/ValueTracking.cpp: llvm::isKnownNegation
matchMinMax
llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp: Negator::visitImpl
Issue title: miscompile of vector double-negation + select by InstCombine
Labels: miscompilation
llvm:instcombine
Reported by: regehr

https://alive2.llvm.org/ce/z/N1RVAr

this:
```llvm
define <4 x i32> @f(<4 x i32> %0) {
  %2 = sub <4 x i32> zeroinitializer, %0
  %3 = select <4 x i1> <i1 false, i1 true, i1 poison, i1 poison>, <4 x i32> %2, <4 x i32> %0
  %4 = sub <4 x i32> zeroinitializer, %3
  ret <4 x i32> %4
}
```
is being optimized to:
```llvm
define <4 x i32> @f(<4 x i32> %0) {
  ret <4 x i32> %0
}
```
here's Alive's work explaining why this is wrong:
```
ERROR: Value mismatch

Example:
<4 x i32> %#0 = < #x00000001 (1), poison, poison, poison >

Source:
<4 x i32> %#2 = < #xffffffff (4294967295, -1), poison, poison, poison >
<4 x i32> %#3 = < #x00000001 (1), poison, poison, poison >
<4 x i32> %#4 = < #xffffffff (4294967295, -1), poison, poison, poison >

Target:
Source value: < #xffffffff (4294967295, -1), poison, poison, poison >
Target value: < #x00000001 (1), poison, poison, poison >
```

cc @nunoplopes @hatsunespica



Comments: author: topperc
body: I think the problem is this code in Negator::visitImpl.

```
  case Instruction::Select: {
    if (isKnownNegation(I->getOperand(1), I->getOperand(2))) {                   
      // Of one hand of select is known to be negation of another hand,          
      // just swap the hands around.                                             
      auto *NewSelect = cast<SelectInst>(I->clone());                            
      // Just swap the operands of the select.                                   
      NewSelect->swapValues();                                                   
      // Don't swap prof metadata, we didn't change the branch behavior.         
      NewSelect->setName(I->getName() + ".neg");                                 
      Builder.Insert(NewSelect);                                                 
      return NewSelect;                                                          
    }   
```

The IR at the time of that code running was
```
%2 = sub <4 x i32> <i32 poison, i32 0, i32 0, i32 0>, %0
%3 = select <4 x i1> <i1 false, i1 true, i1 poison, i1 poison>, <4 x i32> %2, <4 x i32> %0
%4 = sub <4 x i32> zeroinitializer, %3
```

So operand element 0 of %2 is poison. This occurred because element 0 isn't selected so SimplifiedDemandedVectorElts replaced with poison.

Once Negator swaps the operands, now element 1 of %2 is never selected so we end up with `sub <4 x i32> poison, %0`

It doesn't look like swapping the operands of the select is poison safe.

CC @nikic 
author: nikic
body: Yeah, that analysis sounds right to me. With that in mind, a more direct test case would be:
```llvm
define <2 x i32> @f(<2 x i1> %c, <2 x i32> %x) {
  %neg = sub <2 x i32> <i32 0, i32 poison>, %x
  %sel = select <2 x i1> %c, <2 x i32> %neg, <2 x i32> %x
  %neg2 = sub <2 x i32> zeroinitializer, %sel
  ret <2 x i32> %neg2
}
```
author: regehr
body: off topic but do we want an llvm-reduce pass that shrinks vectors? and maybe also shrinks lane sizes? if so I could work on that sort of thing this summer
author: XChy
body: > off topic but do we want an llvm-reduce pass that shrinks vectors? and maybe also shrinks lane sizes? if so I could work on that sort of thing this summer

Sounds great to me. I think some SLPVectorizer testcases that involve 16 or even 32 lanes should be further reduced.

Fix patch:
commit a1b1c4a6d1d52916c5d885170a5f54632d579cdc
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Apr 24 10:56:26 2024 +0900

    [InstCombine] Fix miscompile in negation of select (#89698)
    
    Swapping the operands of a select is not valid if one hand is more
    poisonous that the other, because the negation zero contains poison
    elements.
    
    Fix this by adding an extra parameter to isKnownNegation() to forbid
    poison elements.
    
    I've implemented this using manual checks to avoid needing four variants
    for the NeedsNSW/AllowPoison combinations. Maybe there is a better way
    to do this...
    
    Fixes https://github.com/llvm/llvm-project/issues/89669.

diff --git a/llvm/include/llvm/Analysis/ValueTracking.h b/llvm/include/llvm/Analysis/ValueTracking.h
index a2fa8f6064e1..571e44cdac26 100644
--- a/llvm/include/llvm/Analysis/ValueTracking.h
+++ b/llvm/include/llvm/Analysis/ValueTracking.h
@@ -131,7 +131,8 @@ bool isKnownNonZero(const Value *V, const SimplifyQuery &Q, unsigned Depth = 0);
 /// Currently can recoginze Value pair:
 /// 1: <X, Y> if X = sub (0, Y) or Y = sub (0, X)
 /// 2: <X, Y> if X = sub (A, B) and Y = sub (B, A)
-bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false);
+bool isKnownNegation(const Value *X, const Value *Y, bool NeedNSW = false,
+                     bool AllowPoison = true);
 
 /// Returns true if the give value is known to be non-negative.
 bool isKnownNonNegative(const Value *V, const SimplifyQuery &SQ,
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 21e3f8a4cc52..7501f78ca23b 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -8042,17 +8042,27 @@ static SelectPatternResult matchMinMax(CmpInst::Predicate Pred,
   return {SPF_UNKNOWN, SPNB_NA, false};
 }
 
-bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW) {
+bool llvm::isKnownNegation(const Value *X, const Value *Y, bool NeedNSW,
+                           bool AllowPoison) {
   assert(X && Y && "Invalid operand");
 
-  // X = sub (0, Y) || X = sub nsw (0, Y)
-  if ((!NeedNSW && match(X, m_Sub(m_ZeroInt(), m_Specific(Y)))) ||
-      (NeedNSW && match(X, m_NSWNeg(m_Specific(Y)))))
+  auto IsNegationOf = [&](const Value *X, const Value *Y) {
+    if (!match(X, m_Neg(m_Specific(Y))))
+      return false;
+
+    auto *BO = cast<BinaryOperator>(X);
+    if (NeedNSW && !BO->hasNoSignedWrap())
+      return false;
+
+    auto *Zero = cast<Constant>(BO->getOperand(0));
+    if (!AllowPoison && !Zero->isNullValue())
+      return false;
+
     return true;
+  };
 
-  // Y = sub (0, X) || Y = sub nsw (0, X)
-  if ((!NeedNSW && match(Y, m_Sub(m_ZeroInt(), m_Specific(X)))) ||
-      (NeedNSW && match(Y, m_NSWNeg(m_Specific(X)))))
+  // X = -Y or Y = -X
+  if (IsNegationOf(X, Y) || IsNegationOf(Y, X))
     return true;
 
   // X = sub (A, B), Y = sub (B, A) || X = sub nsw (A, B), Y = sub nsw (B, A)
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
index d697f361dec0..ed2a98ba4ae4 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineNegator.cpp
@@ -320,7 +320,8 @@ std::array<Value *, 2> Negator::getSortedOperandsOfBinOp(Instruction *I) {
     return NegatedPHI;
   }
   case Instruction::Select: {
-    if (isKnownNegation(I->getOperand(1), I->getOperand(2))) {
+    if (isKnownNegation(I->getOperand(1), I->getOperand(2), /*NeedNSW=*/false,
+                        /*AllowPoison=*/false)) {
       // Of one hand of select is known to be negation of another hand,
       // just swap the hands around.
       auto *NewSelect = cast<SelectInst>(I->clone());


Regression tests:
file: llvm/test/Transforms/InstCombine/sub-of-negatible.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: negate_select_of_negation_poison
test_body: define <2 x i32> @negate_select_of_negation_poison(<2 x i1> %c, <2 x i32> %x) {
  %neg = sub <2 x i32> <i32 0, i32 poison>, %x
  %sel = select <2 x i1> %c, <2 x i32> %neg, <2 x i32> %x
  %neg2 = sub <2 x i32> zeroinitializer, %sel
  ret <2 x i32> %neg2
}

test_name: dont_negate_ordinary_select
test_body: define i8 @dont_negate_ordinary_select(i8 %x, i8 %y, i8 %z, i1 %c) {
  %t0 = select i1 %c, i8 %x, i8 %y
  %t1 = sub i8 %z, %t0
  ret i8 %t1
}