Skip to content

[InstSimplify] Generalize simplifyAndOrOfFCmps #81027

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
Feb 8, 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
43 changes: 22 additions & 21 deletions llvm/lib/Analysis/InstructionSimplify.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1853,35 +1853,36 @@ static Value *simplifyAndOrOfFCmps(const SimplifyQuery &Q, FCmpInst *LHS,
return nullptr;

FCmpInst::Predicate PredL = LHS->getPredicate(), PredR = RHS->getPredicate();
if ((PredL == FCmpInst::FCMP_ORD && PredR == FCmpInst::FCMP_ORD && IsAnd) ||
(PredL == FCmpInst::FCMP_UNO && PredR == FCmpInst::FCMP_UNO && !IsAnd)) {
// (fcmp ord NNAN, X) & (fcmp ord X, Y) --> fcmp ord X, Y
// (fcmp ord NNAN, X) & (fcmp ord Y, X) --> fcmp ord Y, X
// (fcmp ord X, NNAN) & (fcmp ord X, Y) --> fcmp ord X, Y
// (fcmp ord X, NNAN) & (fcmp ord Y, X) --> fcmp ord Y, X
// (fcmp uno NNAN, X) | (fcmp uno X, Y) --> fcmp uno X, Y
// (fcmp uno NNAN, X) | (fcmp uno Y, X) --> fcmp uno Y, X
// (fcmp uno X, NNAN) | (fcmp uno X, Y) --> fcmp uno X, Y
// (fcmp uno X, NNAN) | (fcmp uno Y, X) --> fcmp uno Y, X
if ((PredL == FCmpInst::FCMP_ORD || PredL == FCmpInst::FCMP_UNO) &&
((FCmpInst::isOrdered(PredR) && IsAnd) ||
(FCmpInst::isUnordered(PredR) && !IsAnd))) {
// (fcmp ord X, NNAN) & (fcmp o** X, Y) --> fcmp o** X, Y
// (fcmp uno X, NNAN) & (fcmp o** X, Y) --> false
// (fcmp uno X, NNAN) | (fcmp u** X, Y) --> fcmp u** X, Y
// (fcmp ord X, NNAN) | (fcmp u** X, Y) --> true
if (((LHS1 == RHS0 || LHS1 == RHS1) &&
isKnownNeverNaN(LHS0, /*Depth=*/0, Q)) ||
((LHS0 == RHS0 || LHS0 == RHS1) &&
isKnownNeverNaN(LHS1, /*Depth=*/0, Q)))
return RHS;

// (fcmp ord X, Y) & (fcmp ord NNAN, X) --> fcmp ord X, Y
// (fcmp ord Y, X) & (fcmp ord NNAN, X) --> fcmp ord Y, X
// (fcmp ord X, Y) & (fcmp ord X, NNAN) --> fcmp ord X, Y
// (fcmp ord Y, X) & (fcmp ord X, NNAN) --> fcmp ord Y, X
// (fcmp uno X, Y) | (fcmp uno NNAN, X) --> fcmp uno X, Y
// (fcmp uno Y, X) | (fcmp uno NNAN, X) --> fcmp uno Y, X
// (fcmp uno X, Y) | (fcmp uno X, NNAN) --> fcmp uno X, Y
// (fcmp uno Y, X) | (fcmp uno X, NNAN) --> fcmp uno Y, X
return FCmpInst::isOrdered(PredL) == FCmpInst::isOrdered(PredR)
? static_cast<Value *>(RHS)
: ConstantInt::getBool(LHS->getType(), !IsAnd);
}

if ((PredR == FCmpInst::FCMP_ORD || PredR == FCmpInst::FCMP_UNO) &&
((FCmpInst::isOrdered(PredL) && IsAnd) ||
(FCmpInst::isUnordered(PredL) && !IsAnd))) {
// (fcmp o** X, Y) & (fcmp ord X, NNAN) --> fcmp o** X, Y
// (fcmp o** X, Y) & (fcmp uno X, NNAN) --> false
// (fcmp u** X, Y) | (fcmp uno X, NNAN) --> fcmp u** X, Y
// (fcmp u** X, Y) | (fcmp ord X, NNAN) --> true
if (((RHS1 == LHS0 || RHS1 == LHS1) &&
isKnownNeverNaN(RHS0, /*Depth=*/0, Q)) ||
((RHS0 == LHS0 || RHS0 == LHS1) &&
isKnownNeverNaN(RHS1, /*Depth=*/0, Q)))
return LHS;
return FCmpInst::isOrdered(PredL) == FCmpInst::isOrdered(PredR)
? static_cast<Value *>(LHS)
: ConstantInt::getBool(LHS->getType(), !IsAnd);
}

return nullptr;
Expand Down
20 changes: 10 additions & 10 deletions llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
Original file line number Diff line number Diff line change
Expand Up @@ -1100,8 +1100,8 @@ define i1 @uge_smallest_normal_or_ord(half %x) #0 {
; -> nan | pnormal | pinf
define i1 @uge_smallest_normal_or_uno(half %x) #0 {
; CHECK-LABEL: @uge_smallest_normal_or_uno(
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 771)
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: [[CMP_SMALLEST_NORMAL:%.*]] = fcmp uge half [[X:%.*]], 0xH0400
; CHECK-NEXT: ret i1 [[CMP_SMALLEST_NORMAL]]
;
%uno = fcmp uno half %x, 0.0
%cmp.smallest.normal = fcmp uge half %x, 0xH0400
Expand Down Expand Up @@ -1307,8 +1307,8 @@ define i1 @oge_fabs_eq_inf_and_ord(half %x) #0 {

define i1 @oge_eq_inf_and_ord(half %x) #0 {
; CHECK-LABEL: @oge_eq_inf_and_ord(
; CHECK-NEXT: [[AND:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
; CHECK-NEXT: ret i1 [[AND]]
; CHECK-NEXT: [[OGE_FABS_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH7C00
; CHECK-NEXT: ret i1 [[OGE_FABS_INF]]
;
%oge.fabs.inf = fcmp oge half %x, 0xH7C00
%ord = fcmp ord half %x, 0xH0000
Expand Down Expand Up @@ -1379,8 +1379,8 @@ define i1 @ult_fabs_eq_inf_or_uno(half %x) #0 {

define i1 @ult_eq_inf_or_uno(half %x) #0 {
; CHECK-LABEL: @ult_eq_inf_or_uno(
; CHECK-NEXT: [[OR:%.*]] = fcmp une half [[X:%.*]], 0xH7C00
; CHECK-NEXT: ret i1 [[OR]]
; CHECK-NEXT: [[ULT_FABS_INF:%.*]] = fcmp une half [[X:%.*]], 0xH7C00
; CHECK-NEXT: ret i1 [[ULT_FABS_INF]]
;
%ult.fabs.inf = fcmp ult half %x, 0xH7C00
%uno = fcmp uno half %x, 0xH0000
Expand Down Expand Up @@ -1465,8 +1465,8 @@ define i1 @oeq_neginfinity_or_ord(half %x) #0 {
; -> ninf
define i1 @oeq_neginfinity_and_ord(half %x) #0 {
; CHECK-LABEL: @oeq_neginfinity_and_ord(
; CHECK-NEXT: [[CLASS:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: [[OEQ_NEG_INFINITY:%.*]] = fcmp oeq half [[X:%.*]], 0xHFC00
; CHECK-NEXT: ret i1 [[OEQ_NEG_INFINITY]]
;
%oeq.neg.infinity = fcmp oeq half %x, 0xHFC00
%ord = fcmp ord half %x, 0.0
Expand Down Expand Up @@ -1597,8 +1597,8 @@ define i1 @ueq_neginfinity_and_olt_smallest_normal(half %x) #0 {
; -> nan|ninf
define i1 @ueq_neginfinity_or_uno(half %x) #0 {
; CHECK-LABEL: @ueq_neginfinity_or_uno(
; CHECK-NEXT: [[CLASS:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
; CHECK-NEXT: ret i1 [[CLASS]]
; CHECK-NEXT: [[UEQ_NEG_INFINITY:%.*]] = fcmp ueq half [[X:%.*]], 0xHFC00
; CHECK-NEXT: ret i1 [[UEQ_NEG_INFINITY]]
;
%ueq.neg.infinity = fcmp ueq half %x, 0xHFC00
%uno = fcmp uno half %x, 0.0
Expand Down
167 changes: 167 additions & 0 deletions llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll
Original file line number Diff line number Diff line change
Expand Up @@ -259,3 +259,170 @@ define <2 x i1> @uno8(<2 x double> %x, <2 x double> %y) {
%r = or <2 x i1> %cmp1, %cmp2
ret <2 x i1> %r
}

define i1 @olt_implies_ord(float %x, float %y) {
; CHECK-LABEL: @olt_implies_ord(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[OLT]]
;
%ord = fcmp ord float %x, 0.000000e+00
%olt = fcmp olt float %x, %y
%ret = and i1 %olt, %ord
ret i1 %ret
}

define i1 @olt_implies_ord_commuted1(float %x, float %y) {
; CHECK-LABEL: @olt_implies_ord_commuted1(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[OLT]]
;
%ord = fcmp ord float %x, 0.000000e+00
%olt = fcmp olt float %y, %x
%ret = and i1 %olt, %ord
ret i1 %ret
}

define i1 @olt_implies_ord_commuted2(float %x, float %y) {
; CHECK-LABEL: @olt_implies_ord_commuted2(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[OLT]]
;
%ord = fcmp ord float %x, 0.000000e+00
%olt = fcmp olt float %x, %y
%ret = and i1 %ord, %olt
ret i1 %ret
}

define i1 @olt_implies_ord_commuted3(float %x, float %y) {
; CHECK-LABEL: @olt_implies_ord_commuted3(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[Y:%.*]], [[X:%.*]]
; CHECK-NEXT: ret i1 [[OLT]]
;
%ord = fcmp ord float %x, 0.000000e+00
%olt = fcmp olt float %y, %x
%ret = and i1 %ord, %olt
ret i1 %ret
}

define <2 x i1> @olt_implies_ord_vec(<2 x float> %x, <2 x float> %y) {
; CHECK-LABEL: @olt_implies_ord_vec(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt <2 x float> [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret <2 x i1> [[OLT]]
;
%ord = fcmp ord <2 x float> %x, zeroinitializer
%olt = fcmp olt <2 x float> %x, %y
%ret = and <2 x i1> %ord, %olt
ret <2 x i1> %ret
}

define i1 @ord_implies_ord(float %x, float %y) {
; CHECK-LABEL: @ord_implies_ord(
; CHECK-NEXT: [[ORD2:%.*]] = fcmp ord float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[ORD2]]
;
%ord = fcmp ord float %x, 0.000000e+00
%ord2 = fcmp ord float %x, %y
%ret = and i1 %ord, %ord2
ret i1 %ret
}

define i1 @olt_implies_uno(float %x, float %y) {
; CHECK-LABEL: @olt_implies_uno(
; CHECK-NEXT: ret i1 false
;
%uno = fcmp uno float %x, 0.000000e+00
%olt = fcmp olt float %x, %y
%ret = and i1 %olt, %uno
ret i1 %ret
}

define i1 @ult_implies_uno(float %x, float %y) {
; CHECK-LABEL: @ult_implies_uno(
; CHECK-NEXT: [[ULT:%.*]] = fcmp ult float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[ULT]]
;
%uno = fcmp uno float %x, 0.000000e+00
%ult = fcmp ult float %x, %y
%ret = or i1 %ult, %uno
ret i1 %ret
}

define i1 @uno_implies_uno(float %x, float %y) {
; CHECK-LABEL: @uno_implies_uno(
; CHECK-NEXT: [[UNO2:%.*]] = fcmp uno float [[X:%.*]], [[Y:%.*]]
; CHECK-NEXT: ret i1 [[UNO2]]
;
%uno = fcmp uno float %x, 0.000000e+00
%uno2 = fcmp uno float %x, %y
%ret = or i1 %uno, %uno2
ret i1 %ret
}

define i1 @ult_implies_ord(float %x, float %y) {
; CHECK-LABEL: @ult_implies_ord(
; CHECK-NEXT: ret i1 true
;
%ord = fcmp ord float %x, 0.000000e+00
%ult = fcmp ult float %x, %y
%ret = or i1 %ult, %ord
ret i1 %ret
}

; TODO: %cmp1 is false implies %cmp3 is true
define float @test_ord_implies_uno(float %x) {
; CHECK-LABEL: @test_ord_implies_uno(
; CHECK-NEXT: [[CMP1:%.*]] = fcmp ord float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[CMP2:%.*]] = fcmp olt float [[X]], 0.000000e+00
; CHECK-NEXT: [[CMP3:%.*]] = fcmp uno float [[X]], 0.000000e+00
; CHECK-NEXT: [[SEL:%.*]] = select i1 [[CMP1]], i1 [[CMP2]], i1 [[CMP3]]
; CHECK-NEXT: [[RET:%.*]] = select i1 [[SEL]], float 0.000000e+00, float [[X]]
; CHECK-NEXT: ret float [[RET]]
;
%cmp1 = fcmp ord float %x, 0.000000e+00
%cmp2 = fcmp olt float %x, 0.000000e+00
%cmp3 = fcmp uno float %x, 0.000000e+00
%sel = select i1 %cmp1, i1 %cmp2, i1 %cmp3
%ret = select i1 %sel, float 0.000000e+00, float %x
ret float %ret
}

; Negative tests

define i1 @olt_implies_ord_fail(float %x, float %y, float %z) {
; CHECK-LABEL: @olt_implies_ord_fail(
; CHECK-NEXT: [[ORD:%.*]] = fcmp ord float [[X:%.*]], [[Z:%.*]]
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[X]], [[Y:%.*]]
; CHECK-NEXT: [[RET:%.*]] = and i1 [[OLT]], [[ORD]]
; CHECK-NEXT: ret i1 [[RET]]
;
%ord = fcmp ord float %x, %z
%olt = fcmp olt float %x, %y
%ret = and i1 %olt, %ord
ret i1 %ret
}

define i1 @ult_implies_uno_and(float %x, float %y) {
; CHECK-LABEL: @ult_implies_uno_and(
; CHECK-NEXT: [[UNO:%.*]] = fcmp uno float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[ULT:%.*]] = fcmp ult float [[X]], [[Y:%.*]]
; CHECK-NEXT: [[RET:%.*]] = and i1 [[ULT]], [[UNO]]
; CHECK-NEXT: ret i1 [[RET]]
;
%uno = fcmp uno float %x, 0.000000e+00
%ult = fcmp ult float %x, %y
%ret = and i1 %ult, %uno
ret i1 %ret
}

define i1 @olt_implies_olt_fail(float %x, float %y) {
; CHECK-LABEL: @olt_implies_olt_fail(
; CHECK-NEXT: [[OLT:%.*]] = fcmp olt float [[X:%.*]], 0.000000e+00
; CHECK-NEXT: [[OLT2:%.*]] = fcmp olt float [[X]], [[Y:%.*]]
; CHECK-NEXT: [[RET:%.*]] = and i1 [[OLT]], [[OLT2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%olt = fcmp olt float %x, 0.000000e+00
%olt2 = fcmp olt float %x, %y
%ret = and i1 %olt, %olt2
ret i1 %ret
}