Skip to content

[InstCombine] Fold fabs over selects #86390

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 22, 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: 8 additions & 2 deletions llvm/lib/Transforms/InstCombine/InstCombineCalls.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2497,10 +2497,16 @@ Instruction *InstCombinerImpl::visitCallInst(CallInst &CI) {
if (match(II->getArgOperand(0),
m_Select(m_Value(Cond), m_Value(TVal), m_Value(FVal)))) {
// fabs (select Cond, TrueC, FalseC) --> select Cond, AbsT, AbsF
if (isa<Constant>(TVal) && isa<Constant>(FVal)) {
if (isa<Constant>(TVal) || isa<Constant>(FVal)) {
CallInst *AbsT = Builder.CreateCall(II->getCalledFunction(), {TVal});
CallInst *AbsF = Builder.CreateCall(II->getCalledFunction(), {FVal});
return SelectInst::Create(Cond, AbsT, AbsF);
SelectInst *SI = SelectInst::Create(Cond, AbsT, AbsF);
FastMathFlags FMF1 = II->getFastMathFlags();
FastMathFlags FMF2 =
cast<SelectInst>(II->getArgOperand(0))->getFastMathFlags();
FMF2.setNoSignedZeros(false);
SI->setFastMathFlags(FMF1 | FMF2);
return SI;
}
// fabs (select Cond, -FVal, FVal) --> fabs FVal
if (match(TVal, m_FNeg(m_Specific(FVal))))
Expand Down
6 changes: 3 additions & 3 deletions llvm/test/Transforms/InstCombine/fabs.ll
Original file line number Diff line number Diff line change
Expand Up @@ -179,9 +179,9 @@ define float @fabs_select_constant_neg0(i32 %c) {
define float @fabs_select_var_constant_negative(i32 %c, float %x) {
; CHECK-LABEL: @fabs_select_var_constant_negative(
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[C:%.*]], 0
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[CMP]], float [[X:%.*]], float -1.000000e+00
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: ret float [[FABS]]
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT:%.*]])
; CHECK-NEXT: [[FABS1:%.*]] = select i1 [[CMP]], float [[FABS]], float 1.000000e+00
; CHECK-NEXT: ret float [[FABS1]]
;
%cmp = icmp eq i32 %c, 0
%select = select i1 %cmp, float %x, float -1.0
Expand Down
64 changes: 64 additions & 0 deletions llvm/test/Transforms/InstCombine/intrinsic-select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -280,3 +280,67 @@ entry:
%ret = icmp eq i64 %masked, 0
ret i1 %ret
}

define double @test_fabs_select1(double %a) {
; CHECK-LABEL: @test_fabs_select1(
; CHECK-NEXT: [[COND:%.*]] = fcmp uno double [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[COND]], double 0x7FF8000000000000, double [[A]]
; CHECK-NEXT: ret double [[SEL1]]
;
%cond = fcmp uno double %a, 0.000000e+00
%sel1 = select i1 %cond, double 0x7FF8000000000000, double %a
%fabs = call double @llvm.fabs.f64(double %sel1)
%sel2 = select i1 %cond, double %fabs, double %a
ret double %sel2
}

define <2 x double> @test_fabs_select1_vec(<2 x double> %a) {
; CHECK-LABEL: @test_fabs_select1_vec(
; CHECK-NEXT: [[COND:%.*]] = fcmp uno <2 x double> [[A:%.*]], zeroinitializer
; CHECK-NEXT: [[SEL2:%.*]] = select <2 x i1> [[COND]], <2 x double> <double 0x7FF8000000000000, double 0x7FF8000000000000>, <2 x double> [[A]]
; CHECK-NEXT: ret <2 x double> [[SEL2]]
;
%cond = fcmp uno <2 x double> %a, zeroinitializer
%sel1 = select <2 x i1> %cond, <2 x double> splat(double 0x7FF8000000000000), <2 x double> %a
%fabs = call <2 x double> @llvm.fabs.v2f64(<2 x double> %sel1)
%sel2 = select <2 x i1> %cond, <2 x double> %fabs, <2 x double> %a
ret <2 x double> %sel2
}

define double @test_fabs_select2(double %a) {
; CHECK-LABEL: @test_fabs_select2(
; CHECK-NEXT: [[ABS1:%.*]] = call double @llvm.fabs.f64(double [[A:%.*]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq double [[ABS1]], 0x7FF0000000000000
; CHECK-NEXT: [[ABS2:%.*]] = select i1 [[CMP]], double 0.000000e+00, double [[ABS1]]
; CHECK-NEXT: ret double [[ABS2]]
;
%abs1 = call double @llvm.fabs.f64(double %a)
%cmp = fcmp oeq double %abs1, 0x7FF0000000000000
%sel = select i1 %cmp, double -0.000000e+00, double %abs1
%abs2 = call double @llvm.fabs.f64(double %sel)
ret double %abs2
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Test vectors and flag preservation

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we handle fneg? Does the fneg+fabs combo fold the same?

Copy link
Member Author

Choose a reason for hiding this comment

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

Test vectors and flag preservation

Done. Alive2: https://alive2.llvm.org/ce/z/ijP-me

Copy link
Member Author

Choose a reason for hiding this comment

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

Do we handle fneg?

No.

Does the fneg+fabs combo fold the same?

Can you explain it a bit more?

Copy link
Contributor

Choose a reason for hiding this comment

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

I mean the same should be applied with fneg, and with fneg(fabs(x))


; nsz flag should be dropped.

define double @test_fabs_select_fmf1(i1 %cond, double %a) {
; CHECK-LABEL: @test_fabs_select_fmf1(
; CHECK-NEXT: [[A:%.*]] = call double @llvm.fabs.f64(double [[A1:%.*]])
; CHECK-NEXT: [[FABS:%.*]] = select nnan ninf i1 [[COND:%.*]], double 0.000000e+00, double [[A]]
; CHECK-NEXT: ret double [[FABS]]
;
%sel1 = select nnan ninf nsz i1 %cond, double 0.0, double %a
%fabs = call double @llvm.fabs.f64(double %sel1)
ret double %fabs
}

define double @test_fabs_select_fmf2(i1 %cond, double %a) {
; CHECK-LABEL: @test_fabs_select_fmf2(
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[A:%.*]])
; CHECK-NEXT: [[SEL1:%.*]] = select nnan ninf nsz i1 [[COND:%.*]], double 0.000000e+00, double [[TMP1]]
; CHECK-NEXT: ret double [[SEL1]]
;
%sel1 = select i1 %cond, double 0.0, double %a
%fabs = call nnan ninf nsz double @llvm.fabs.f64(double %sel1)
ret double %fabs
}
24 changes: 12 additions & 12 deletions llvm/test/Transforms/InstCombine/simplify-demanded-fpclass.ll
Original file line number Diff line number Diff line change
Expand Up @@ -387,8 +387,8 @@ define nofpclass(inf) float @ret_nofpclass_inf__fabs_select_pinf_rhs(i1 %cond, f
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
; CHECK-NEXT: ret float [[FABS]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand All @@ -411,8 +411,8 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__fabs_
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs(i1 %cond, float %x) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nan__fabs_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[FABS:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[FABS:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
; CHECK-NEXT: ret float [[FABS]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand Down Expand Up @@ -665,8 +665,8 @@ define nofpclass(inf pnorm psub pzero) float @ret_nofpclass_no_positives_noinf__
define nofpclass(ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand All @@ -678,8 +678,8 @@ 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; 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: ret float [[COPYSIGN]]
;
Expand All @@ -692,8 +692,8 @@ define nofpclass(pinf pnorm psub pzero) float @ret_nofpclass_no_positives__copys
define nofpclass(nan ninf nnorm nsub nzero) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs(i1 %cond, float %x, float %unknown.sign) {
; CHECK-LABEL: define nofpclass(nan ninf nzero nsub nnorm) float @ret_nofpclass_no_negatives_nonan__copysign_unknown_select_pinf_rhs
; CHECK-SAME: (i1 [[COND:%.*]], float [[X:%.*]], float [[UNKNOWN_SIGN:%.*]]) {
; CHECK-NEXT: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[COPYSIGN:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[X]])
; CHECK-NEXT: [[COPYSIGN:%.*]] = select i1 [[COND]], float [[TMP1]], float 0x7FF0000000000000
; CHECK-NEXT: ret float [[COPYSIGN]]
;
%select = select i1 %cond, float %x, float 0x7FF0000000000000
Expand All @@ -705,8 +705,8 @@ 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: [[SELECT:%.*]] = select i1 [[COND]], float [[X]], float 0x7FF0000000000000
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[SELECT]])
; 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: ret float [[COPYSIGN]]
;
Expand Down