Skip to content

Commit

Permalink
[InstSimplify] Generalize simplifyAndOrOfFCmps (llvm#81027)
Browse files Browse the repository at this point in the history
This patch generalizes `simplifyAndOrOfFCmps` to simplify patterns like:
```
define i1 @src(float %x, float %y) {
  %or.cond.i = fcmp ord float %x, 0.000000e+00
  %cmp.i.i34 = fcmp olt float %x, %y
  %cmp.i2.sink.i = and i1 %or.cond.i, %cmp.i.i34
  ret i1 %cmp.i2.sink.i
}

define i1 @tgt(float %x, float %y) {
  %cmp.i.i34 = fcmp olt float %x, %y
  ret i1 %cmp.i.i34
}
```
Alive2: https://alive2.llvm.org/ce/z/9rydcx

This patch and llvm#80986 will fix the regression introduced by llvm#80941.
See also the IR diff
dtcxzyw/llvm-opt-benchmark#199 (comment).
  • Loading branch information
dtcxzyw authored Feb 8, 2024
1 parent c8ca98a commit e17dded
Show file tree
Hide file tree
Showing 3 changed files with 199 additions and 31 deletions.
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
}

0 comments on commit e17dded

Please sign in to comment.