Skip to content

[InstCombine] fold cond ? x : -x == 0 into x == 0 #85673

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 6 commits into from
Apr 20, 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
8 changes: 8 additions & 0 deletions llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8045,6 +8045,14 @@ Instruction *InstCombinerImpl::visitFCmpInst(FCmpInst &I) {
Constant *RHSC;
if (match(Op0, m_Instruction(LHSI)) && match(Op1, m_Constant(RHSC))) {
switch (LHSI->getOpcode()) {
case Instruction::Select:
// fcmp eq (cond ? x : -x), 0 --> fcmp eq x, 0
if (FCmpInst::isEquality(Pred) && match(RHSC, m_AnyZeroFP()) &&
(match(LHSI,
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);
break;
case Instruction::PHI:
if (Instruction *NV = foldOpIntoPhi(I, cast<PHINode>(LHSI)))
return NV;
Expand Down
232 changes: 232 additions & 0 deletions llvm/test/Transforms/InstCombine/fcmp.ll
Copy link
Member

@elhewaty elhewaty Mar 22, 2024

Choose a reason for hiding this comment

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

Can you please split the patch into two separate commits, so it's easier to see the diff?

Original file line number Diff line number Diff line change
Expand Up @@ -1486,3 +1486,235 @@ define i1 @fcmp_fadd_fast_zero(float %x, float %y) {
%cmp = fcmp ugt float %add, %y
ret i1 %cmp
}

define i1 @fcmp_ueq_sel_x_negx(float %x) {
; CHECK-LABEL: @fcmp_ueq_sel_x_negx(
; CHECK-NEXT: [[RES:%.*]] = fcmp ueq float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp ueq float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp ueq float %sel, 0.000000e+00
ret i1 %res
}

define i1 @fcmp_une_sel_x_negx(float %x) {
; CHECK-LABEL: @fcmp_une_sel_x_negx(
; CHECK-NEXT: [[RES:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp une float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp une float %sel, 0.000000e+00
ret i1 %res
}

define i1 @fcmp_oeq_sel_x_negx(float %x) {
; CHECK-LABEL: @fcmp_oeq_sel_x_negx(
; CHECK-NEXT: [[RES:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp oeq float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp oeq float %sel, 0.000000e+00
ret i1 %res
}

define i1 @fcmp_one_sel_x_negx(float %x) {
; CHECK-LABEL: @fcmp_one_sel_x_negx(
; CHECK-NEXT: [[RES:%.*]] = fcmp one float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp one float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp one float %sel, 0.000000e+00
ret i1 %res
}

define i1 @fcmp_ueq_sel_x_negx_nzero(float %x) {
; CHECK-LABEL: @fcmp_ueq_sel_x_negx_nzero(
; CHECK-NEXT: [[RES:%.*]] = fcmp ueq float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp ueq float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp ueq float %sel, -0.000000e+00
ret i1 %res
}

define i1 @fcmp_une_sel_x_negx_nzero(float %x) {
; CHECK-LABEL: @fcmp_une_sel_x_negx_nzero(
; CHECK-NEXT: [[RES:%.*]] = fcmp une float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp une float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp une float %sel, -0.000000e+00
ret i1 %res
}

define i1 @fcmp_oeq_sel_x_negx_nzero(float %x) {
; CHECK-LABEL: @fcmp_oeq_sel_x_negx_nzero(
; CHECK-NEXT: [[RES:%.*]] = fcmp oeq float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp oeq float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp oeq float %sel, -0.000000e+00
ret i1 %res
}

define i1 @fcmp_one_sel_x_negx_nzero(float %x) {
; CHECK-LABEL: @fcmp_one_sel_x_negx_nzero(
; CHECK-NEXT: [[RES:%.*]] = fcmp one float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%f = fcmp one float %x, 0.000000e+00
%neg = fneg float %x
%sel = select i1 %f, float %x, float %neg
%res = fcmp one float %sel, -0.000000e+00
ret i1 %res
}

define <8 x i1> @fcmp_ueq_sel_x_negx_vec(<8 x float> %x) {
; CHECK-LABEL: @fcmp_ueq_sel_x_negx_vec(
; CHECK-NEXT: [[RES:%.*]] = fcmp ueq <8 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <8 x i1> [[RES]]
;
%f = fcmp ueq <8 x float> %x, zeroinitializer
%neg = fneg <8 x float> %x
%sel = select <8 x i1> %f, <8 x float> %x, <8 x float> %neg
%res = fcmp ueq <8 x float> %sel, zeroinitializer
ret <8 x i1> %res
}

define <8 x i1> @fcmp_une_sel_x_negx_vec(<8 x float> %x) {
; CHECK-LABEL: @fcmp_une_sel_x_negx_vec(
; CHECK-NEXT: [[RES:%.*]] = fcmp une <8 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <8 x i1> [[RES]]
;
%f = fcmp une <8 x float> %x, zeroinitializer
%neg = fneg <8 x float> %x
%sel = select <8 x i1> %f, <8 x float> %x, <8 x float> %neg
%res = fcmp une <8 x float> %sel, zeroinitializer
ret <8 x i1> %res
}

define <8 x i1> @fcmp_oeq_sel_x_negx_vec(<8 x float> %x) {
; CHECK-LABEL: @fcmp_oeq_sel_x_negx_vec(
; CHECK-NEXT: [[RES:%.*]] = fcmp oeq <8 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <8 x i1> [[RES]]
;
%f = fcmp oeq <8 x float> %x, zeroinitializer
%neg = fneg <8 x float> %x
%sel = select <8 x i1> %f, <8 x float> %x, <8 x float> %neg
%res = fcmp oeq <8 x float> %sel, zeroinitializer
ret <8 x i1> %res
}

define <8 x i1> @fcmp_one_sel_x_negx_vec(<8 x float> %x) {
; CHECK-LABEL: @fcmp_one_sel_x_negx_vec(
; CHECK-NEXT: [[RES:%.*]] = fcmp one <8 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <8 x i1> [[RES]]
;
%f = fcmp one <8 x float> %x, zeroinitializer
%neg = fneg <8 x float> %x
%sel = select <8 x i1> %f, <8 x float> %x, <8 x float> %neg
%res = fcmp one <8 x float> %sel, zeroinitializer
ret <8 x i1> %res
}

define <2 x i1> @fcmp_oeq_sel_x_negx_with_any_fpzero_ninf_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_oeq_sel_x_negx_with_any_fpzero_ninf_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp ninf oeq <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp ninf oeq <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_one_sel_x_negx_with_any_fpzero_ninf_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_one_sel_x_negx_with_any_fpzero_ninf_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp ninf one <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp ninf one <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_ueq_sel_x_negx_with_any_fpzero_ninf_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_ueq_sel_x_negx_with_any_fpzero_ninf_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp ninf ueq <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp ninf ueq <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_une_sel_x_negx_with_any_fpzero_ninf_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_une_sel_x_negx_with_any_fpzero_ninf_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp ninf une <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp ninf une <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_oeq_sel_x_negx_with_any_fpzero_nnan_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_oeq_sel_x_negx_with_any_fpzero_nnan_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp nnan oeq <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp nnan oeq <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_one_sel_x_negx_with_any_fpzero_nnan_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_one_sel_x_negx_with_any_fpzero_nnan_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp nnan one <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp nnan one <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_ueq_sel_x_negx_with_any_fpzero_nnan_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_ueq_sel_x_negx_with_any_fpzero_nnan_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp nnan ueq <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp nnan ueq <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}

define <2 x i1> @fcmp_une_sel_x_negx_with_any_fpzero_nnan_vec(<2 x i1> %cond, <2 x float> %x) {
; CHECK-LABEL: @fcmp_une_sel_x_negx_with_any_fpzero_nnan_vec(
; CHECK-NEXT: [[ICMP:%.*]] = fcmp nnan une <2 x float> [[X:%.*]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[ICMP]]
;
%fneg = fneg <2 x float> %x
%sel = select <2 x i1> %cond, <2 x float> %x, <2 x float> %fneg
%icmp = fcmp nnan une <2 x float> %sel, <float 0.0, float -0.0>
ret <2 x i1> %icmp
}
Copy link
Contributor

Choose a reason for hiding this comment

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

Tests with -0s

Copy link
Contributor

Choose a reason for hiding this comment

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

And a test with denormal-fp-math=dynamic,dynamic

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I'm not familiar with this what it is flag in opt.

Copy link
Contributor

Choose a reason for hiding this comment

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

It's an attribute, see the LangRef

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I used -denormal-fp-math=dynamic in comment script, but I didn't see any difference in these tests.

Copy link
Contributor

Choose a reason for hiding this comment

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

I don't expect to see a difference, but alive should catch violations if it's wrong

Copy link
Contributor

Choose a reason for hiding this comment

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

I also think you should just directly add the attribute to a reference test or 2, not use the opt flag

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I apologize for the delay. I tried adding the flag "denormal-fp-math=dynamic" after function signature but I didn't see any difference.

Copy link
Contributor

Choose a reason for hiding this comment

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

Correct. You should not see a difference. you should still have the test showing that it does not make a difference. Also, it should be "dynamic,dynamic" for the value

Loading