Bug type: miscompilation
Component: InstCombine
Bug location: llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp: InstCombinerImpl::SimplifyDemandedUseBits
Issue title: [InstCombine] Vector `fshl` retains invalid `range` after demanded-bits simplification
Labels: miscompilation
llvm:instcombine
Reported by: cardigan1008

In https://github.com/llvm/llvm-project/pull/124429, the patch correctly drops `range` for scalar `fshl` when operands are simplified based on demanded bits, but it does not consistently do so for vector `fshl`.

In the vector case, `SimplifyDemandedBits` can still change the operands such that the original `range` no longer holds, yet the `range` attribute is preserved, causing the `fshl` result to become poison.

For example, we have this vector case:

```llvm
%zext = zext <2 x i1> %x to <2 x i32>
%or   = or disjoint <2 x i32> %zext, <i32 -2, i32 -2>
%fshl = call <2 x i32> @llvm.fshl.v2i32(
           <2 x i32> %or,
           <2 x i32> <i32 -2, i32 -2>,
           <2 x i32> <i32 1,  i32 1>),
         !range !{i32 -4, i32 2}
%tr   = trunc <2 x i32> %fshl to <2 x i8>
```

After demanded-bits simplification, `%or` is rewritten to `<126, 126>`, which changes the result of fshl to `<253, 253>`.

However, the original `range [-4, 2)` attribute is still preserved on the vector `fshl`, even though the new value clearly violates it. As a result, the `fshl` produces `poison`. 

Alive2 proof: https://alive2.llvm.org/ce/z/JTXAYD

Exposed from https://github.com/llvm/llvm-project/commit/2131115be5b9d8b39af80973d9b64c0adc41d38d, cc @MaskRay 

Comments: author: cardigan1008
body: I can propose a patch for this. Please assign it to me, thanks. 

Fix patch:
commit 144dc7464fcfde796401acf7784e084d0e66d15c
Author: Yunbo Ni <ybni@cse.cuhk.edu.hk>
Date:   Tue Dec 30 00:05:49 2025 +0800

    [InstCombine] Drop range metadata when simplifying `fshl` with demanded bits (#173864)
    
    InstCombine may rewrite `llvm.fshl` operands when simplifying based on
    demanded bits, which can invalidate previously attached return value
    constraints. Except from range attribute, `!range` metadata could also
    be not dropped after operand rewriting, leading to stale
    poison-generating metadata and potential miscompilations.
    
    This patch drops poison-generating annotations when `fshl` operands are
    simplified, ensuring that `!range` metadata is cleared consistently with
    return attributes.
    
    Alive2 proof: https://alive2.llvm.org/ce/z/EVUvY6
    
    Fixes #173793

diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 519e32157207..45fa8ee8b33a 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -1105,8 +1105,8 @@ Value *InstCombinerImpl::SimplifyDemandedUseBits(Instruction *I,
                                    Depth + 1) ||
               SimplifyDemandedBits(I, 1, DemandedMaskRHS, RHSKnown, Q,
                                    Depth + 1)) {
-            // Range attribute may no longer hold.
-            I->dropPoisonGeneratingReturnAttributes();
+            // Range attribute or metadata may no longer hold.
+            I->dropPoisonGeneratingAnnotations();
             return I;
           }
         } else { // fshl is a rotate


Regression tests:
file: llvm/test/Transforms/InstCombine/fsh.ll
commands: opt < %s -passes=instcombine -S
tests: test_name: fshl_range_vec
test_body: define <2 x i8> @fshl_range_vec(<2 x i1> %x) {
  %zext = zext <2 x i1> %x to <2 x i32>
  %or = or disjoint <2 x i32> %zext, splat (i32 -2)
  %fshl = call <2 x i32> @llvm.fshl.v2i32(<2 x i32> %or, <2 x i32> splat (i32 -2), <2 x i32> splat (i32 1)), !range !0
  %tr = trunc <2 x i32> %fshl to <2 x i8>
  ret <2 x i8> %tr
}

; Function Attrs: nocallback nofree nosync nounwind speculatable willreturn memory(none)
declare <2 x i32> @llvm.fshl.v2i32(<2 x i32>, <2 x i32>, <2 x i32>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }

!0 = !{i32 -4, i32 2}