Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp: InstCombinerImpl::convertOrOfShiftsToFunnelShift
Issue title: [InstCombine] Missing poison check when reusing existing value in def-use chain
Labels: miscompilation
llvm:instcombine
generated by fuzzer
Reported by: dtcxzyw

Reproducer: https://alive2.llvm.org/ce/z/H_tcBV
```
define i16 @src(i4 %x, i12 %y) {
  %x.fr = freeze i4 %x
  %zext.x = zext i4 %x.fr to i16
  %slx = shl nuw nsw i16 %zext.x, 12
  %zext.y = zext i12 %y to i16
  %xy = or disjoint i16 %slx, %zext.y
  call void @use(i16 %xy)
  %sly = shl nuw i16 %zext.y, 4
  %yx = or disjoint i16 %sly, %zext.x
  ret i16 %yx
}

define i16 @tgt(i4 %x, i12 %y) {
  %x.fr = freeze i4 %x
  %zext.x = zext i4 %x.fr to i16
  %slx = shl nuw nsw i16 %zext.x, 12
  %zext.y = zext i12 %y to i16
  %xy = or disjoint i16 %slx, %zext.y
  call void @use(i16 %xy)
  ;%sly = shl nuw i16 %zext.y, 4
  ;%yx = or disjoint i16 %sly, %zext.x
  %yx = call i16 @llvm.fshl.i16(i16 %xy, i16 %xy, i16 4)
  ret i16 %yx
}

declare void @use(i16)
```
```
Transformation doesn't verify!

ERROR: Target is more poisonous than source

Example:
i4 %x = #x8 (8, -8)
i12 %y = #x000 (0)

Source:
i4 %x.fr = #x8 (8, -8)
i16 %zext.x = #x0008 (8)
i16 %slx = poison
i16 %zext.y = #x0000 (0)
i16 %xy = poison
Function @use returned
i16 %sly = #x0000 (0)
i16 %yx = #x0008 (8)

SOURCE MEMORY STATE
===================
NON-LOCAL BLOCKS:
Block 0 >	size: 0	align: 1	alloc type: 0	alive: false	address: #x0
Block 1 >	size: 0	align: 1	alloc type: 0	alive: true	address: #x1

Target:
i4 %x.fr = #x8 (8, -8)
i16 %zext.x = #x0008 (8)
i16 %slx = poison
i16 %zext.y = #x0000 (0)
i16 %xy = poison
Function @use returned
i16 %yx = poison

TARGET MEMORY STATE
===================
NON-LOCAL BLOCKS:
Block 0 >	size: 0	align: 1	alloc type: 0	alive: false	address: #x0
Block 1 >	size: 0	align: 1	alloc type: 0	alive: true	address: #x1
Source value: #x0008 (8)
Target value: poison
```

It is caused by https://github.com/llvm/llvm-project/pull/68502.



Fix patch:
commit c09054866a1ad6c250e6c972d369b9023abb4b3b
Author: Yingwei Zheng <dtcxzyw2333@gmail.com>
Date:   Wed Oct 1 22:02:08 2025 +0800

    [InstCombine] Drop poison-generating flags when reusing existing or instruction (#161504)
    
    Closes https://github.com/llvm/llvm-project/issues/161493.

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
index 4b7793f6e010..9b272c4721cb 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineAndOrXor.cpp
@@ -3080,6 +3080,13 @@ InstCombinerImpl::convertOrOfShiftsToFunnelShift(Instruction &Or) {
       assert(ZextLowShlAmt->uge(HighSize) &&
              ZextLowShlAmt->ule(Width - LowSize) && "Invalid concat");
 
+      // We cannot reuse the result if it may produce poison.
+      // Drop poison generating flags in the expression tree.
+      // Or
+      cast<Instruction>(U)->dropPoisonGeneratingFlags();
+      // Shl
+      cast<Instruction>(X)->dropPoisonGeneratingFlags();
+
       FShiftArgs = {U, U, ConstantInt::get(Or0->getType(), *ZextHighShlAmt)};
       break;
     }


Regression tests:
file: llvm/test/Transforms/InstCombine/funnel.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: test_rotl_and_neg_wrong_mask
test_body: target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"

define i32 @test_rotl_and_neg_wrong_mask(i32 %x, i32 %shamt) {
  %shl = shl i32 %x, %shamt
  %neg = sub i32 0, %shamt
  %and = and i32 %neg, 15
  %shr = lshr i32 %x, %and
  %or = or i32 %shl, %shr
  ret i32 %or
}

test_name: fshl_concat_vector_may_produce_poison
test_body: target datalayout = "e-p:32:32:32-i1:8:8-i8:8:8-i16:16:16-i32:32:32-i64:32:64-f32:32:32-f64:32:64-v64:64:64-v128:128:128-a0:0:64-f80:128:128"

declare void @use(i16)

define i16 @fshl_concat_vector_may_produce_poison(i4 %x, i12 %y) {
  %x.fr = freeze i4 %x
  %zext.x = zext i4 %x.fr to i16
  %slx = shl nuw nsw i16 %zext.x, 12
  %zext.y = zext i12 %y to i16
  %xy = or disjoint i16 %slx, %zext.y
  call void @use(i16 %xy)
  %sly = shl nuw i16 %zext.y, 4
  %yx = or disjoint i16 %sly, %zext.x
  ret i16 %yx
}