-
Notifications
You must be signed in to change notification settings - Fork 13.4k
[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
Conversation
@llvm/pr-subscribers-llvm-analysis @llvm/pr-subscribers-llvm-transforms Author: Yingwei Zheng (dtcxzyw) ChangesThis patch generalizes
Alive2: https://alive2.llvm.org/ce/z/9rydcx This patch and #80986 will fix the regression introduced by #80941. Full diff: https://github.com/llvm/llvm-project/pull/81027.diff 3 Files Affected:
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 01b017142cfcb..51e258d69e9e2 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -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;
diff --git a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
index 24dac97672f71..12c608cd6c2bb 100644
--- a/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
+++ b/llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
diff --git a/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll
index d898df0b32f2b..4b2ff1b3d050c 100644
--- a/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll
+++ b/llvm/test/Transforms/InstSimplify/logic-of-fcmps.ll
@@ -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
+}
|
) This patch generalizes #81027 to handle pattern `and/or (fcmp ord/uno X, 0), (fcmp pred fabs(X), Y)`. Alive2: https://alive2.llvm.org/ce/z/tsgUrz The correctness is straightforward because `fcmp ord/uno X, 0.0` is equivalent to `fcmp ord/uno fabs(X), 0.0`. We may generalize it to handle fneg as well. Address comment #116065 (review)
This patch generalizes
simplifyAndOrOfFCmps
to simplify patterns like:Alive2: https://alive2.llvm.org/ce/z/9rydcx
This patch and #80986 will fix the regression introduced by #80941.
See also the IR diff dtcxzyw/llvm-opt-benchmark#199 (comment).