Bug type: miscompilation
Component: BDCE
Bug location: llvm/lib/Transforms/Scalar/BDCE.cpp: clearAssumptionsOfUsers
Issue title: Wrong code at -O2/3 on x86-64_linux-gnu (recent regression)
Labels: miscompilation
llvm:transforms
Reported by: shao-hua-li

clang at -O2/3 produced the wrong code. This is a recent regression.

Bisected to 20737825c9122b6e0a8912731cfa7e0558fe025d, which was committed by @antoniofrighetto 

Compiler explorer: https://godbolt.org/z/55z1WT3MM

```console
% cat reduced.c
int printf(const char *, ...);
short a, f = 6;
int b, e, g;
int c[7][1];
static int *d = &b;
long h;
int *const *i;
static unsigned char j(long k, short *n) {
  int *l = &c[5][0];
  int *const **m = &i;
  i = &l;
  *d = 0;
  for (; e < 60; e++)
    ***m = ((h = *d == (1 ^ k)) & *n + f) - 2;
  return 0;
}
int main() {
  j(1, &a);
  printf("%d\n", c[5][0]);
}
%
% clang -O0 reduced.c &&./a.out
-2
% clang -O2 reduced.c &&./a.out
4
%
```

Comments: author: nikic
body: Looks like poison flags don't get cleared as expected.
author: nikic
body: Minimized:
```llvm
define i32 @test(i64 %x) {
  %and = and i64 %x, 1
  %trunc = trunc i64 %and to i32
  %or = or disjoint i32 %trunc, -2
  ret i32 %or
}
```
The `%and` gets dropped but `disjoint` is kept.
author: antoniofrighetto
body: @nikic, could you kindly elaborate this? I'm having a hard time getting this, the transformation looks correct with simple `or` (https://alive2.llvm.org/ce/z/ui3yFf). Semantics for `disjoint`:
> If the disjoint flag is set, and the or has a one and the same bit in both arguments, the result is poison.

However, here:
```llvm
  %add = add nuw nsw i64 %conv5, %conv4
  %and = and i64 %add, 1
  %2 = trunc i64 %and to i32
  %conv7 = or disjoint i32 %2, -2
```
The two or operands do not seem to have any same bit in both arguments.
author: antoniofrighetto
body: OK, I got it now, the `disjoint` should not be there at all after the transformation. Makes sense, thank you.
author: nikic
body: Fixed another issue I noticed in this code in https://github.com/llvm/llvm-project/commit/cb6240d247b3419dea29eb99261171ea239b1c5c.

Fix patch:
commit b210cbbd0eb8ef7cd2735e99570474e6e53ee00b
Author: Nikita Popov <npopov@redhat.com>
Date:   Wed Jan 31 11:01:03 2024 +0100

    [BDCE] Fix clearing of poison-generating flags
    
    If the demanded bits of an instruction are full, we don't have to
    recurse to its users, but we may still have to clear flags on the
    instruction itself.
    
    Fixes https://github.com/llvm/llvm-project/issues/80113.

diff --git a/llvm/lib/Transforms/Scalar/BDCE.cpp b/llvm/lib/Transforms/Scalar/BDCE.cpp
index e99210ce2f22..6e6fa6c8ffc4 100644
--- a/llvm/lib/Transforms/Scalar/BDCE.cpp
+++ b/llvm/lib/Transforms/Scalar/BDCE.cpp
@@ -45,15 +45,17 @@ static void clearAssumptionsOfUsers(Instruction *I, DemandedBits &DB) {
   assert(I->getType()->isIntOrIntVectorTy() &&
          "Trivializing a non-integer value?");
 
+  // If all bits of a user are demanded, then we know that nothing below that
+  // in the def-use chain needs to be changed.
+  if (DB.getDemandedBits(I).isAllOnes())
+    return;
+
   // Initialize the worklist with eligible direct users.
   SmallPtrSet<Instruction *, 16> Visited;
   SmallVector<Instruction *, 16> WorkList;
   for (User *JU : I->users()) {
-    // If all bits of a user are demanded, then we know that nothing below that
-    // in the def-use chain needs to be changed.
-    auto *J = dyn_cast<Instruction>(JU);
-    if (J && J->getType()->isIntOrIntVectorTy() &&
-        !DB.getDemandedBits(J).isAllOnes()) {
+    auto *J = cast<Instruction>(JU);
+    if (J->getType()->isIntOrIntVectorTy()) {
       Visited.insert(J);
       WorkList.push_back(J);
     }
@@ -79,12 +81,14 @@ static void clearAssumptionsOfUsers(Instruction *I, DemandedBits &DB) {
     // 1. llvm.assume demands its operand, so trivializing can't change it.
     // 2. range metadata only applies to memory accesses which demand all bits.
 
+    // If all bits of a user are demanded, then we know that nothing below
+    // that in the def-use chain needs to be changed.
+    if (DB.getDemandedBits(J).isAllOnes())
+      continue;
+
     for (User *KU : J->users()) {
-      // If all bits of a user are demanded, then we know that nothing below
-      // that in the def-use chain needs to be changed.
-      auto *K = dyn_cast<Instruction>(KU);
-      if (K && Visited.insert(K).second && K->getType()->isIntOrIntVectorTy() &&
-          !DB.getDemandedBits(K).isAllOnes())
+      auto *K = cast<Instruction>(KU);
+      if (Visited.insert(K).second && K->getType()->isIntOrIntVectorTy())
         WorkList.push_back(K);
     }
   }


Regression tests:
file: llvm/test/Transforms/BDCE/invalidate-assumptions.ll
commands: opt -passes=bdce %s -S
tests: test_name: disjoint_indirect
test_body: define i32 @disjoint_indirect(i64 %x) {
  %and = and i64 %x, 1
  %trunc = trunc i64 %and to i32
  %or = or disjoint i32 %trunc, -2
  ret i32 %or
}

test_name: disjoint
test_body: define i64 @disjoint(i64 %x) {
  %and = and i64 %x, 1
  %or = or disjoint i64 %and, -2
  ret i64 %or
}