Skip to content

[InstCombine] Fold fcmp into select #86482

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 4 commits into from
Apr 23, 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
2 changes: 2 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8052,6 +8052,8 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
m_Select(m_Value(), m_Value(X), m_FNeg(m_Deferred(X)))) ||
match(LHSI, m_Select(m_Value(), m_FNeg(m_Value(X)), m_Deferred(X)))))
return replaceOperand(I, 0, X);
if (Instruction *NV = FoldOpIntoSelect(I, cast<SelectInst>(LHSI)))
Copy link
Contributor

Choose a reason for hiding this comment

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

Should we update constantFoldOperationIntoSelectOperand to recognize fcmp?

Copy link
Member Author

Choose a reason for hiding this comment

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

It should be done in a separate patch.
Related patch: https://reviews.llvm.org/D146349

return NV;
break;
Copy link
Contributor

Choose a reason for hiding this comment

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

If both arms are constant, should we allow multiuse select?

Copy link
Member Author

Choose a reason for hiding this comment

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

Yeah, we can relax it in InstCombinerImpl::FoldOpIntoSelect.

Copy link
Contributor

Choose a reason for hiding this comment

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

IMO here, we have the argument FoldWithMultiUse and it would be a bit confusing if we started to surreptitiously assume it.

case Instruction::PHI:
if (Instruction *NV = foldOpIntoPhi(I, cast<PHINode>(LHSI)))
Expand Down
120 changes: 120 additions & 0 deletions llvm/test/Transforms/InstCombine/fcmp-select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
; RUN: opt < %s -passes=instcombine -S | FileCheck %s

declare void @use(i1)
declare void @usef64(double)

; X == 42.0 ? X : 42.0 --> 42.0

Expand Down Expand Up @@ -148,3 +149,122 @@ define i1 @fcmp_ogt_select(i1 %cond, float %a, float %b) {
%res = fcmp ogt float %lhs, %rhs
ret i1 %res
}

define i1 @test_fcmp_select_const_const(double %x) {
; CHECK-LABEL: @test_fcmp_select_const_const(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp1 = fcmp ord double %x, 0.000000e+00
%sel = select i1 %cmp1, double 0xFFFFFFFFFFFFFFFF, double 0.000000e+00
%cmp2 = fcmp oeq double %sel, 0.000000e+00
ret i1 %cmp2
}

define i1 @test_fcmp_select_var_const(double %x, double %y) {
; CHECK-LABEL: @test_fcmp_select_var_const(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ule double [[X:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[TMP1:%.*]] = fcmp olt double [[Y:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[TMP1]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = fcmp ogt double %x, 0x3E80000000000000
%sel = select i1 %cmp1, double %y, double 0.000000e+00
%cmp2 = fcmp olt double %sel, 0x3E80000000000000
ret i1 %cmp2
}

define i1 @test_fcmp_select_var_const_fmf(double %x, double %y) {
; CHECK-LABEL: @test_fcmp_select_var_const_fmf(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ule double [[X:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[TMP1:%.*]] = fcmp nnan olt double [[Y:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 true, i1 [[TMP1]]
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = fcmp ogt double %x, 0x3E80000000000000
%sel = select i1 %cmp1, double %y, double 0.000000e+00
%cmp2 = fcmp nnan olt double %sel, 0x3E80000000000000
ret i1 %cmp2
}

define <2 x i1> @test_fcmp_select_const_const_vec(<2 x double> %x) {
; CHECK-LABEL: @test_fcmp_select_const_const_vec(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp uno <2 x double> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[CMP1]]
;
%cmp1 = fcmp ord <2 x double> %x, zeroinitializer
%sel = select <2 x i1> %cmp1, <2 x double> <double 0xFFFFFFFFFFFFFFFF, double 0xFFFFFFFFFFFFFFFF>, <2 x double> zeroinitializer
%cmp2 = fcmp oeq <2 x double> %sel, zeroinitializer
ret <2 x i1> %cmp2
}

; Don't break clamp idioms

define double @test_fcmp_select_clamp(double %x) {
; CHECK-LABEL: @test_fcmp_select_clamp(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ogt double [[X:%.*]], 9.000000e-01
; CHECK-NEXT: [[SEL1:%.*]] = select i1 [[CMP1]], double 9.000000e-01, double [[X]]
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt double [[SEL1]], 5.000000e-01
; CHECK-NEXT: [[SEL2:%.*]] = select i1 [[CMP2]], double 5.000000e-01, double [[SEL1]]
; CHECK-NEXT: ret double [[SEL2]]
;
%cmp1 = fcmp ogt double %x, 9.000000e-01
%sel1 = select i1 %cmp1, double 9.000000e-01, double %x
%cmp2 = fcmp olt double %sel1, 5.000000e-01
%sel2 = select i1 %cmp2, double 5.000000e-01, double %sel1
ret double %sel2
}

; Don't break fmin/fmax idioms

define double @test_fcmp_select_maxnum(double %x) {
; CHECK-LABEL: @test_fcmp_select_maxnum(
; CHECK-NEXT: [[SEL1:%.*]] = call nnan nsz double @llvm.maxnum.f64(double [[X:%.*]], double 1.000000e+00)
; CHECK-NEXT: [[SEL2:%.*]] = call nnan nsz double @llvm.minnum.f64(double [[SEL1]], double 2.550000e+02)
; CHECK-NEXT: ret double [[SEL2]]
;
%cmp1 = fcmp ogt double %x, 1.0
%sel1 = select nnan nsz i1 %cmp1, double %x, double 1.0
%cmp2 = fcmp olt double %sel1, 255.0
%sel2 = select nnan nsz i1 %cmp2, double %sel1, double 255.0
ret double %sel2
}

define i1 @test_fcmp_select_const_const_multiuse(double %x) {
; CHECK-LABEL: @test_fcmp_select_const_const_multiuse(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], double 0xFFFFFFFFFFFFFFFF, double 0.000000e+00
; CHECK-NEXT: call void @usef64(double [[SEL]])
; CHECK-NEXT: [[CMP2:%.*]] = fcmp oeq double [[SEL]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = fcmp ord double %x, 0.000000e+00
%sel = select i1 %cmp1, double 0xFFFFFFFFFFFFFFFF, double 0.000000e+00
call void @usef64(double %sel)
%cmp2 = fcmp oeq double %sel, 0.000000e+00
ret i1 %cmp2
}

define i1 @test_fcmp_select_const_const_unordered(double %x) {
; CHECK-LABEL: @test_fcmp_select_const_const_unordered(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord double [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP1]]
;
%cmp1 = fcmp uno double %x, 0.000000e+00
%sel = select i1 %cmp1, double 0xFFFFFFFFFFFFFFFF, double 0.000000e+00
%cmp2 = fcmp oeq double %sel, 0.000000e+00
ret i1 %cmp2
}

define i1 @test_fcmp_select_var_const_unordered(double %x, double %y) {
; CHECK-LABEL: @test_fcmp_select_var_const_unordered(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ult double [[X:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[TMP1:%.*]] = fcmp ugt double [[Y:%.*]], 0x3E80000000000000
; CHECK-NEXT: [[CMP2:%.*]] = select i1 [[CMP1]], i1 [[TMP1]], i1 false
; CHECK-NEXT: ret i1 [[CMP2]]
;
%cmp1 = fcmp ult double %x, 0x3E80000000000000
%sel = select i1 %cmp1, double %y, double 0.000000e+00
%cmp2 = fcmp ugt double %sel, 0x3E80000000000000
ret i1 %cmp2
}
7 changes: 3 additions & 4 deletions llvm/test/Transforms/InstCombine/select-select.ll
Original file line number Diff line number Diff line change
Expand Up @@ -18,11 +18,10 @@ define float @foo1(float %a) {

define float @foo2(float %a) {
; CHECK-LABEL: @foo2(
; CHECK-NEXT: [[B:%.*]] = fcmp ogt float [[A:%.*]], 0.000000e+00
; CHECK-NEXT: [[C:%.*]] = select i1 [[B]], float [[A]], float 0.000000e+00
; CHECK-NEXT: [[B:%.*]] = fcmp ule float [[C:%.*]], 0.000000e+00
; CHECK-NEXT: [[D:%.*]] = fcmp olt float [[C]], 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = select i1 [[B]], float [[A]], float 0.000000e+00
; CHECK-NEXT: [[F:%.*]] = select i1 [[D]], float [[E]], float 1.000000e+00
; CHECK-NEXT: [[E:%.*]] = select i1 [[D]], float [[C]], float 1.000000e+00
; CHECK-NEXT: [[F:%.*]] = select i1 [[B]], float 0.000000e+00, float [[E]]
; CHECK-NEXT: ret float [[F]]
;
%b = fcmp ogt float %a, 0.0
Expand Down