[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