[llvm] [InstCombine] Don't reuse a sibling binop with extra flags via demanded elts (#199782) (PR #201545)

via llvm-commits llvm-commits at lists.llvm.org
Thu Jun 4 03:57:23 PDT 2026


llvmorg-github-actions[bot] wrote:


<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-llvm-transforms

Author: lijinpei-amd

<details>
<summary>Changes</summary>

SimplifyDemandedVectorElts can replace a vector binop with a sibling binop. But if the sibling carries a flag the original lacked, it could produce a result the original never would. E.g.

  Reusing `sub nuw`   could make the result poison on wrap.
  Reusing `fmul nsz`  could flip the sign of a zero.
  Reusing `fdiv arcp` could make the result less accurate.

Fix by only reusing the sibling when its flags are a subset of the replaced binop's.

https://alive2.llvm.org/ce/z/9yEaG7
Fixes #<!-- -->199782.

---
Full diff: https://github.com/llvm/llvm-project/pull/201545.diff


2 Files Affected:

- (modified) llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp (+21-1) 
- (modified) llvm/test/Transforms/InstCombine/vec_demanded_elts.ll (+153-3) 


``````````diff
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
index 83ea2d2932ac9..efcd9c8c9a0f8 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineSimplifyDemanded.cpp
@@ -1972,6 +1972,26 @@ Value *InstCombinerImpl::SimplifyDemandedVectorElts(Value *V,
     if (DemandedElts == 1 && !X->hasOneUse() && !Y->hasOneUse() &&
         BO->hasOneUse() ) {
 
+      // Reuse the sibling only if its flags are a subset of BO's, otherwise the
+      // sibling could produce a result BO never would. (See issue #199782.)
+      auto flagsSubsumedByBO = [&](User *U) {
+        auto *UI = cast<Instruction>(U);
+        if (isa<OverflowingBinaryOperator>(UI) &&
+            ((UI->hasNoUnsignedWrap() && !BO->hasNoUnsignedWrap()) ||
+             (UI->hasNoSignedWrap() && !BO->hasNoSignedWrap())))
+          return false;
+        assert(!isa<PossiblyExactOperator>(UI) &&
+               "exact operator should have been excluded");
+        if (auto *UPD = dyn_cast<PossiblyDisjointInst>(UI))
+          if (UPD->isDisjoint() &&
+              !cast<PossiblyDisjointInst>(BO)->isDisjoint())
+            return false;
+        FastMathFlags UFMF = UI->getFastMathFlagsOrNone();
+        if ((UFMF & BO->getFastMathFlagsOrNone()) != UFMF)
+          return false;
+        return true;
+      };
+
       auto findShufBO = [&](bool MatchShufAsOp0) -> User * {
         // Try to use shuffle-of-operand in place of an operand:
         // bo X, Y --> bo (shuf X), Y
@@ -1993,7 +2013,7 @@ Value *InstCombinerImpl::SimplifyDemandedVectorElts(Value *V,
                         ? match(U, m_BinOp(Opcode, Shuf, m_Specific(OtherOp)))
                         : match(U, m_BinOp(Opcode, m_Specific(OtherOp), Shuf)))
             if (match(Mask, m_ZeroMask()) && Mask[0] != PoisonMaskElem)
-              if (DT.dominates(U, I))
+              if (DT.dominates(U, I) && flagsSubsumedByBO(U))
                 return U;
         }
         return nullptr;
diff --git a/llvm/test/Transforms/InstCombine/vec_demanded_elts.ll b/llvm/test/Transforms/InstCombine/vec_demanded_elts.ll
index 7e24ddfac5b1b..e60fad28b5351 100644
--- a/llvm/test/Transforms/InstCombine/vec_demanded_elts.ll
+++ b/llvm/test/Transforms/InstCombine/vec_demanded_elts.ll
@@ -1021,11 +1021,12 @@ define float @common_binop_demand_via_extelt_op1(<2 x float> %p, <2 x float> %y)
 
 define float @common_binop_demand_via_extelt_op0_commute(<2 x float> %p, <2 x float> %q) {
 ; CHECK-LABEL: @common_binop_demand_via_extelt_op0_commute(
-; CHECK-NEXT:    [[X:%.*]] = fsub nnan <2 x float> <float 0.000000e+00, float poison>, [[P:%.*]]
-; CHECK-NEXT:    [[Y:%.*]] = fsub nnan <2 x float> <float 3.000000e+00, float 2.000000e+00>, [[Q:%.*]]
+; CHECK-NEXT:    [[X:%.*]] = fsub <2 x float> <float 0.000000e+00, float 1.000000e+00>, [[P:%.*]]
+; CHECK-NEXT:    [[Y:%.*]] = fsub <2 x float> <float 3.000000e+00, float 2.000000e+00>, [[Q:%.*]]
 ; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X]], <2 x float> poison, <2 x i32> zeroinitializer
 ; CHECK-NEXT:    [[B_Y_XSHUF:%.*]] = fmul nnan <2 x float> [[Y]], [[XSHUF]]
-; CHECK-NEXT:    [[B_XY0:%.*]] = extractelement <2 x float> [[B_Y_XSHUF]], i64 0
+; CHECK-NEXT:    [[B_XY:%.*]] = fmul ninf <2 x float> [[X]], [[Y]]
+; CHECK-NEXT:    [[B_XY0:%.*]] = extractelement <2 x float> [[B_XY]], i64 0
 ; CHECK-NEXT:    call void @use_fp(<2 x float> [[B_Y_XSHUF]])
 ; CHECK-NEXT:    ret float [[B_XY0]]
 ;
@@ -1059,6 +1060,155 @@ define i4 @common_binop_demand_via_extelt_op1_commute(<2 x i4> %p, <2 x i4> %q)
   ret i4 %b_xy0
 }
 
+define i4 @common_binop_demand_via_extelt_nuw_only_on_sibling(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_nuw_only_on_sibling(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x i4> [[X:%.*]], <2 x i4> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = sub nuw <2 x i4> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = sub <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i4> [[BO]], i64 0
+; CHECK-NEXT:    call void @use(<2 x i4> [[SIB]])
+; CHECK-NEXT:    ret i4 [[E]]
+;
+  %xshuf = shufflevector <2 x i4> %x, <2 x i4> poison, <2 x i32> zeroinitializer
+  %sib = sub nuw <2 x i4> %xshuf, %y
+  %bo = sub <2 x i4> %x, %y
+  %e = extractelement <2 x i4> %bo, i32 0
+  call void @use(<2 x i4> %sib)
+  ret i4 %e
+}
+
+define i4 @common_binop_demand_via_extelt_nsw_only_on_extracted(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_nsw_only_on_extracted(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x i4> [[X:%.*]], <2 x i4> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = sub <2 x i4> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i4> [[SIB]], i64 0
+; CHECK-NEXT:    call void @use(<2 x i4> [[SIB]])
+; CHECK-NEXT:    ret i4 [[E]]
+;
+  %xshuf = shufflevector <2 x i4> %x, <2 x i4> poison, <2 x i32> zeroinitializer
+  %sib = sub <2 x i4> %xshuf, %y
+  %bo = sub nsw <2 x i4> %x, %y
+  %e = extractelement <2 x i4> %bo, i32 0
+  call void @use(<2 x i4> %sib)
+  ret i4 %e
+}
+
+define i4 @common_binop_demand_via_extelt_disjoint_only_on_sibling(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_disjoint_only_on_sibling(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x i4> [[X:%.*]], <2 x i4> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = or disjoint <2 x i4> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = or <2 x i4> [[X]], [[Y]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i4> [[BO]], i64 0
+; CHECK-NEXT:    call void @use(<2 x i4> [[SIB]])
+; CHECK-NEXT:    ret i4 [[E]]
+;
+  %xshuf = shufflevector <2 x i4> %x, <2 x i4> poison, <2 x i32> zeroinitializer
+  %sib = or disjoint <2 x i4> %xshuf, %y
+  %bo = or <2 x i4> %x, %y
+  %e = extractelement <2 x i4> %bo, i32 0
+  call void @use(<2 x i4> %sib)
+  ret i4 %e
+}
+
+define i4 @common_binop_demand_via_extelt_disjoint_only_on_extracted(<2 x i4> %x, <2 x i4> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_disjoint_only_on_extracted(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x i4> [[X:%.*]], <2 x i4> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = or <2 x i4> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x i4> [[SIB]], i64 0
+; CHECK-NEXT:    call void @use(<2 x i4> [[SIB]])
+; CHECK-NEXT:    ret i4 [[E]]
+;
+  %xshuf = shufflevector <2 x i4> %x, <2 x i4> poison, <2 x i32> zeroinitializer
+  %sib = or <2 x i4> %xshuf, %y
+  %bo = or disjoint <2 x i4> %x, %y
+  %e = extractelement <2 x i4> %bo, i32 0
+  call void @use(<2 x i4> %sib)
+  ret i4 %e
+}
+
+define float @common_binop_demand_via_extelt_nnan_only_on_sibling(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_nnan_only_on_sibling(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = fadd nnan <2 x float> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[X]], [[Y]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x float> [[BO]], i64 0
+; CHECK-NEXT:    call void @use_fp(<2 x float> [[SIB]])
+; CHECK-NEXT:    ret float [[E]]
+;
+  %xshuf = shufflevector <2 x float> %x, <2 x float> poison, <2 x i32> zeroinitializer
+  %sib = fadd nnan <2 x float> %xshuf, %y
+  %bo = fadd <2 x float> %x, %y
+  %e = extractelement <2 x float> %bo, i32 0
+  call void @use_fp(<2 x float> %sib)
+  ret float %e
+}
+
+define float @common_binop_demand_via_extelt_ninf_only_on_extracted(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_ninf_only_on_extracted(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = fadd <2 x float> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x float> [[SIB]], i64 0
+; CHECK-NEXT:    call void @use_fp(<2 x float> [[SIB]])
+; CHECK-NEXT:    ret float [[E]]
+;
+  %xshuf = shufflevector <2 x float> %x, <2 x float> poison, <2 x i32> zeroinitializer
+  %sib = fadd <2 x float> %xshuf, %y
+  %bo = fadd ninf <2 x float> %x, %y
+  %e = extractelement <2 x float> %bo, i32 0
+  call void @use_fp(<2 x float> %sib)
+  ret float %e
+}
+
+define float @common_binop_demand_via_extelt_nsz_only_on_sibling(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_nsz_only_on_sibling(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = fadd nsz <2 x float> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = fadd <2 x float> [[X]], [[Y]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x float> [[BO]], i64 0
+; CHECK-NEXT:    call void @use_fp(<2 x float> [[SIB]])
+; CHECK-NEXT:    ret float [[E]]
+;
+  %xshuf = shufflevector <2 x float> %x, <2 x float> poison, <2 x i32> zeroinitializer
+  %sib = fadd nsz <2 x float> %xshuf, %y
+  %bo = fadd <2 x float> %x, %y
+  %e = extractelement <2 x float> %bo, i32 0
+  call void @use_fp(<2 x float> %sib)
+  ret float %e
+}
+
+define float @common_binop_demand_via_extelt_contract_only_on_extracted(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_contract_only_on_extracted(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = fmul <2 x float> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x float> [[SIB]], i64 0
+; CHECK-NEXT:    call void @use_fp(<2 x float> [[SIB]])
+; CHECK-NEXT:    ret float [[E]]
+;
+  %xshuf = shufflevector <2 x float> %x, <2 x float> poison, <2 x i32> zeroinitializer
+  %sib = fmul <2 x float> %xshuf, %y
+  %bo = fmul contract <2 x float> %x, %y
+  %e = extractelement <2 x float> %bo, i32 0
+  call void @use_fp(<2 x float> %sib)
+  ret float %e
+}
+
+define float @common_binop_demand_via_extelt_reassoc_only_on_sibling(<2 x float> %x, <2 x float> %y) {
+; CHECK-LABEL: @common_binop_demand_via_extelt_reassoc_only_on_sibling(
+; CHECK-NEXT:    [[XSHUF:%.*]] = shufflevector <2 x float> [[X:%.*]], <2 x float> poison, <2 x i32> zeroinitializer
+; CHECK-NEXT:    [[SIB:%.*]] = fmul reassoc <2 x float> [[XSHUF]], [[Y:%.*]]
+; CHECK-NEXT:    [[BO:%.*]] = fmul <2 x float> [[X]], [[Y]]
+; CHECK-NEXT:    [[E:%.*]] = extractelement <2 x float> [[BO]], i64 0
+; CHECK-NEXT:    call void @use_fp(<2 x float> [[SIB]])
+; CHECK-NEXT:    ret float [[E]]
+;
+  %xshuf = shufflevector <2 x float> %x, <2 x float> poison, <2 x i32> zeroinitializer
+  %sib = fmul reassoc <2 x float> %xshuf, %y
+  %bo = fmul <2 x float> %x, %y
+  %e = extractelement <2 x float> %bo, i32 0
+  call void @use_fp(<2 x float> %sib)
+  ret float %e
+}
+
 ; negative test - wrong operands for sub
 
 define i4 @common_binop_demand_via_extelt_op0_wrong_commute(<2 x i4> %x, <2 x i4> %y) {

``````````

</details>


https://github.com/llvm/llvm-project/pull/201545


More information about the llvm-commits mailing list