Skip to content

[InstCombine] Fold fneg over select #89947

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Apr 25, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineAddSub.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2781,6 +2781,16 @@ Instruction *InstCombinerImpl::visitFNeg(UnaryOperator &I) {
propagateSelectFMF(NewSel, P == X);
return NewSel;
}

// -(Cond ? X : C) --> Cond ? -X : -C
// -(Cond ? C : Y) --> Cond ? -C : -Y
if (match(X, m_ImmConstant()) || match(Y, m_ImmConstant())) {
Value *NegX = Builder.CreateFNegFMF(X, &I, X->getName() + ".neg");
Value *NegY = Builder.CreateFNegFMF(Y, &I, Y->getName() + ".neg");
SelectInst *NewSel = SelectInst::Create(Cond, NegX, NegY);
propagateSelectFMF(NewSel, /*CommonOperand=*/true);
return NewSel;
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Can we use FoldOpIntoSelect here instead?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No. FoldOpIntoSelect doesn't propagate FMF flags from fneg to select.
See #86390. nsz flag is not always safe to be propagated. So they would be better to be handled separately.

}

// fneg (copysign x, y) -> copysign x, (fneg y)
Expand Down
123 changes: 122 additions & 1 deletion llvm/test/Transforms/InstCombine/fneg.ll
Original file line number Diff line number Diff line change
Expand Up @@ -980,12 +980,133 @@ define float @fneg_ldexp_contract(float %x, i32 %n) {
define float @fneg_ldexp_metadata(float %x, i32 %n) {
; CHECK-LABEL: @fneg_ldexp_metadata(
; CHECK-NEXT: [[TMP1:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]), !arst !0
; CHECK-NEXT: [[NEG:%.*]] = call float @llvm.ldexp.f32.i32(float [[TMP1]], i32 [[N:%.*]]), !arst [[META0:![0-9]+]]
; CHECK-NEXT: ret float [[NEG]]
;
%ldexp = call float @llvm.ldexp.f32.i32(float %x, i32 %n), !arst !0
%neg = fneg float %ldexp
ret float %neg
}

define float @test_fneg_select_constants(i1 %cond) {
; CHECK-LABEL: @test_fneg_select_constants(
; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float 0.000000e+00
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float 0.0, float -0.0
%neg = fneg float %sel1
ret float %neg
}

define <2 x float> @test_fneg_vec(<2 x i1> %cond) {
; CHECK-LABEL: @test_fneg_vec(
; CHECK-NEXT: [[NEG:%.*]] = select <2 x i1> [[COND:%.*]], <2 x float> <float -0.000000e+00, float 0.000000e+00>, <2 x float> <float 0.000000e+00, float -0.000000e+00>
; CHECK-NEXT: ret <2 x float> [[NEG]]
;
%sel1 = select <2 x i1> %cond, <2 x float> <float 0.0, float -0.0>, <2 x float> <float -0.0, float 0.0>
%neg = fneg <2 x float> %sel1
ret <2 x float> %neg
}

define float @test_fneg_select_var_constant(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_var_constant(
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float [[X_NEG]], float 0.000000e+00
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float %x, float -0.0
%neg = fneg float %sel1
ret float %neg
}

; nsz can be preserved.

define float @test_fneg_select_var_constant_fmf1(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_var_constant_fmf1(
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[NEG:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], float [[X_NEG]], float -1.000000e+00
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select nnan ninf nsz i1 %cond, float %x, float 1.0
%neg = fneg float %sel1
ret float %neg
}

define float @test_fneg_select_var_constant_fmf2(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_var_constant_fmf2(
; CHECK-NEXT: [[X_NEG:%.*]] = fneg nnan ninf nsz float [[X:%.*]]
; CHECK-NEXT: [[NEG:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], float [[X_NEG]], float -1.000000e+00
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float %x, float 1.0
%neg = fneg nnan ninf nsz float %sel1
ret float %neg
}

define float @test_fneg_select_constant_var(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_constant_var(
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X:%.*]]
; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[X_NEG]]
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float 0.0, float %x
%neg = fneg float %sel1
ret float %neg
}

; Make sure nabs is generated.

define float @test_fneg_select_abs(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_abs(
; CHECK-NEXT: [[ABSX:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[ABSX_NEG:%.*]] = fneg float [[ABSX]]
; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[ABSX_NEG]]
; CHECK-NEXT: ret float [[NEG]]
;
%absx = call float @llvm.fabs.f32(float %x)
%sel1 = select i1 %cond, float 0.0, float %absx
%neg = fneg float %sel1
ret float %neg
}

define float @test_fneg_fabs_select(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_fabs_select(
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X:%.*]])
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[NEG:%.*]] = select i1 [[COND:%.*]], float -0.000000e+00, float [[DOTNEG]]
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float 0.0, float %x
%abs = call float @llvm.fabs.f32(float %sel1)
%neg = fneg float %abs
ret float %neg
}

define float @test_fneg_select_constant_var_multiuse(i1 %cond, float %x) {
; CHECK-LABEL: @test_fneg_select_constant_var_multiuse(
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[COND:%.*]], float 0.000000e+00, float [[X:%.*]]
; CHECK-NEXT: call void @use(float [[SEL1]])
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[SEL1]]
; CHECK-NEXT: ret float [[NEG]]
;
%sel1 = select i1 %cond, float 0.0, float %x
call void @use(float %sel1)
%neg = fneg float %sel1
ret float %neg
}

; Don't break fmax idioms.

define float @test_fneg_select_maxnum(float %x) {
; CHECK-LABEL: @test_fneg_select_maxnum(
; CHECK-NEXT: [[SEL1:%.*]] = call nnan nsz float @llvm.maxnum.f32(float [[X:%.*]], float 1.000000e+00)
; CHECK-NEXT: [[NEG:%.*]] = fneg float [[SEL1]]
; CHECK-NEXT: ret float [[NEG]]
;
%cmp1 = fcmp ogt float %x, 1.0
%sel1 = select nnan nsz i1 %cmp1, float %x, float 1.0
%neg = fneg float %sel1
ret float %neg
}

!0 = !{}
64 changes: 32 additions & 32 deletions llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
Original file line number Diff line number Diff line change
Expand Up @@ -364,8 +364,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__select_chain_inf_nan_1(i1 %cond,
define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[FABS]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[TMP1]]
;
%select = select i1 %cond, float %x, float 0xFFF0000000000000
%fabs = call float @llvm.fabs.f32(float %select)
Expand All @@ -376,8 +376,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_ninf_rhs(i1 %cond, f
define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[FABS]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[TMP1]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fabs = call float @llvm.fabs.f32(float %select)
Expand All @@ -400,8 +400,8 @@ define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__fabs_
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[FABS]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[TMP1]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fabs = call float @llvm.fabs.f32(float %select)
Expand Down Expand Up @@ -435,8 +435,8 @@ define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_na
define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[FNEG]]
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[X_NEG]]
;
%select = select i1 %cond, float %x, float 0xFFF0000000000000
%fneg = fneg float %select
Expand All @@ -447,8 +447,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__fneg_select_ninf_rhs(i1 %cond, f
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[FNEG]]
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[X_NEG]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fneg = fneg float %select
Expand All @@ -459,8 +459,8 @@ define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___
define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf nzero nsub nnorm) float @ret_nofpclass_nonegatives_noinf___fneg_select_ninf_lhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[FNEG]]
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: ret float [[X_NEG]]
;
%select = select i1 %cond, float 0xFFF0000000000000, float %x
%fneg = fneg float %select
Expand All @@ -470,8 +470,8 @@ define nofpclass(inf nnorm nsub nzero) float @ret_nofpclass_nonegatives_noinf___
define nofpclass(pzero psub pnorm pinf) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives___fneg_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[SELECT]]
; CHECK-NEXT: [[X_NEG:%.*]] = fneg float [[X]]
; CHECK-NEXT: [[FNEG:%.*]] = select i1 [[COND]], float [[X_NEG]], float 0xFFF0000000000000
; CHECK-NEXT: ret float [[FNEG]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand All @@ -483,9 +483,9 @@ define nofpclass(pzero psub pnorm pinf) float @ret_nofpclass_nopositives___fneg_
define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[FNEG]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[DOTNEG]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fabs = call float @llvm.fabs.f32(float %select)
Expand All @@ -497,9 +497,9 @@ define nofpclass(inf) float @ret_nofpclass_inf__fneg_fabs_select_pinf_rhs(i1 %co
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_nonegatives__fneg_fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[FNEG:%.*]] = fneg float [[FABS]]
; CHECK-NEXT: ret float [[FNEG]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[DOTNEG]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fabs = call float @llvm.fabs.f32(float %select)
Expand Down Expand Up @@ -535,8 +535,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__copysign_unknown_select_pinf_rhs
define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_positive_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[COPYSIGN]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[TMP1]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%copysign = call float @llvm.copysign.f32(float %select, float 1.0)
Expand All @@ -547,8 +547,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rh
; CHECK-LABEL: define nofpclass(inf) float @ret_nofpclass_inf__copysign_negative_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[COPYSIGN]]
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: ret float [[DOTNEG]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%copysign = call float @llvm.copysign.f32(float %select, float -1.0)
Expand Down Expand Up @@ -627,8 +627,8 @@ define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_nonegatives_non
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs(i1 %cond, float %x, float %sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_nopositives__copysign_fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[SIGN:%.*]]) {
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[COPYSIGN]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: ret float [[TMP1]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
%fabs.sign = call float @llvm.fabs.f32(float %sign)
Expand Down Expand Up @@ -678,9 +678,9 @@ define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copys
define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(pinf pzero psub pnorm) float @ret_nofpclass_no_positives__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
; CHECK-NEXT: [[TMP2:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[TMP2]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[DOTNEG]], float 0xFFF0000000000000
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand All @@ -705,9 +705,9 @@ define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_no
define nofpclass(nan pinf pnorm psub pzero) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(nan pinf pzero psub pnorm) float @ret_nofpclass_no_positives_nonan__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
; CHECK-NEXT: [[TMP2:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[TMP1:%.*]] = select i1 [[COND]], float [[TMP2]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[DOTNEG:%.*]] = fneg float [[TMP1]]
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[DOTNEG]], float 0xFFF0000000000000
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand Down