Skip to content

Commit

Permalink
InstCombine: Add some additional is.fpclass tests
Browse files Browse the repository at this point in the history
Test some more cases related to compare with 0 and inf.
  • Loading branch information
arsenm committed Feb 9, 2023
1 parent e5489f7 commit 0b5c51b
Show file tree
Hide file tree
Showing 3 changed files with 502 additions and 6 deletions.
106 changes: 106 additions & 0 deletions llvm/test/Transforms/InstCombine/combine-is.fpclass-and-fcmp.ll
Expand Up @@ -222,6 +222,58 @@ define i1 @fcmp_oeq_zero_or_class_normal(half %x) {
ret i1 %or
}

define i1 @fcmp_oeq_zero_or_class_normal_daz(half %x) #1 {
; CHECK-LABEL: @fcmp_oeq_zero_or_class_normal_daz(
; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[OEQ_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%oeq.inf = fcmp oeq half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %oeq.inf, %class
ret i1 %or
}

define <2 x i1> @fcmp_oeq_zero_or_class_normal_daz_v2f16(<2 x half> %x) #1 {
; CHECK-LABEL: @fcmp_oeq_zero_or_class_normal_daz_v2f16(
; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq <2 x half> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[OEQ_INF]], [[CLASS]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%oeq.inf = fcmp oeq <2 x half> %x, zeroinitializer
%class = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %x, i32 264)
%or = or <2 x i1> %oeq.inf, %class
ret <2 x i1> %or
}

define i1 @fcmp_oeq_zero_or_class_normal_dynamic(half %x) #2 {
; CHECK-LABEL: @fcmp_oeq_zero_or_class_normal_dynamic(
; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[OEQ_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%oeq.inf = fcmp oeq half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %oeq.inf, %class
ret i1 %or
}

define <2 x i1> @fcmp_oeq_zero_or_class_normal_dynamic_v2f16(<2 x half> %x) #2 {
; CHECK-LABEL: @fcmp_oeq_zero_or_class_normal_dynamic_v2f16(
; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq <2 x half> [[X:%.*]], zeroinitializer
; CHECK-NEXT: [[CLASS:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or <2 x i1> [[OEQ_INF]], [[CLASS]]
; CHECK-NEXT: ret <2 x i1> [[OR]]
;
%oeq.inf = fcmp oeq <2 x half> %x, zeroinitializer
%class = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> %x, i32 264)
%or = or <2 x i1> %oeq.inf, %class
ret <2 x i1> %or
}

define i1 @class_normal_or_fcmp_oeq_zero(half %x) {
; CHECK-LABEL: @class_normal_or_fcmp_oeq_zero(
; CHECK-NEXT: [[OEQ_INF:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000
Expand Down Expand Up @@ -274,6 +326,32 @@ define i1 @fcmp_one_zero_or_class_normal(half %x) {
ret i1 %or
}

define i1 @fcmp_one_zero_or_class_normal_daz(half %x) #1 {
; CHECK-LABEL: @fcmp_one_zero_or_class_normal_daz(
; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp one half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[ONE_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%one.inf = fcmp one half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %one.inf, %class
ret i1 %or
}

define i1 @fcmp_one_zero_or_class_normal_dynamic(half %x) #2 {
; CHECK-LABEL: @fcmp_one_zero_or_class_normal_dynamic(
; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp one half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[ONE_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%one.inf = fcmp one half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %one.inf, %class
ret i1 %or
}

define i1 @class_normal_or_fcmp_one_zero(half %x) {
; CHECK-LABEL: @class_normal_or_fcmp_one_zero(
; CHECK-NEXT: [[ONE_INF:%.*]] = fcmp one half [[X:%.*]], 0xH0000
Expand Down Expand Up @@ -313,6 +391,32 @@ define i1 @class_normal_or_fcmp_une_zero(half %x) {
ret i1 %or
}

define i1 @class_normal_or_fcmp_une_zero_daz(half %x) #1 {
; CHECK-LABEL: @class_normal_or_fcmp_une_zero_daz(
; CHECK-NEXT: [[UNE_INF:%.*]] = fcmp une half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[UNE_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%une.inf = fcmp une half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %une.inf, %class
ret i1 %or
}

define i1 @class_normal_or_fcmp_une_zero_dynamic(half %x) #2 {
; CHECK-LABEL: @class_normal_or_fcmp_une_zero_dynamic(
; CHECK-NEXT: [[UNE_INF:%.*]] = fcmp une half [[X:%.*]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X]], i32 264)
; CHECK-NEXT: [[OR:%.*]] = or i1 [[UNE_INF]], [[CLASS]]
; CHECK-NEXT: ret i1 [[OR]]
;
%une.inf = fcmp une half %x, 0.0
%class = call i1 @llvm.is.fpclass.f16(half %x, i32 264)
%or = or i1 %une.inf, %class
ret i1 %or
}

define i1 @fcmp_oeq_inf_xor_class_normal(half %x) {
; CHECK-LABEL: @fcmp_oeq_inf_xor_class_normal(
; CHECK-NEXT: [[CLASS:%.*]] = call i1 @llvm.is.fpclass.f16(half [[X:%.*]], i32 776)
Expand Down Expand Up @@ -343,3 +447,5 @@ declare i1 @llvm.is.fpclass.f16(half, i32 immarg) #0
declare <2 x i1> @llvm.is.fpclass.v2f16(<2 x half>, i32 immarg) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #1 = { "denormal-fp-math"="ieee,preserve-sign" }
attributes #2 = { "denormal-fp-math"="ieee,dynamic" }
138 changes: 138 additions & 0 deletions llvm/test/Transforms/InstCombine/create-class-from-logic-fcmp.ll
Expand Up @@ -2049,8 +2049,146 @@ define i1 @fabs_ueq_neginfinity_or_fabs_uge_smallest_normal(half %x) #0 {
ret i1 %class
}

; --------------------------------------------------------------------
; Test denormal mode handling with x == 0
; --------------------------------------------------------------------

; Base pattern !isfinite(x) || x == 0.0, with input denormals flushed to 0
define i1 @not_isfinite_or_zero_f16_daz(half %x) #1 {
; CHECK-LABEL: @not_isfinite_or_zero_f16_daz(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
; CHECK-NEXT: ret i1 [[CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%cmpinf = fcmp ueq half %fabs, 0xH7C00
%cmpzero = fcmp oeq half %x, 0xH0000
%class = or i1 %cmpzero, %cmpinf
ret i1 %class
}

define <2 x i1> @not_isfinite_or_zero_v2f16_daz(<2 x half> %x) #1 {
; CHECK-LABEL: @not_isfinite_or_zero_v2f16_daz(
; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]])
; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq <2 x half> [[FABS]], <half 0xH7C00, half 0xH7C00>
; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq <2 x half> [[X]], zeroinitializer
; CHECK-NEXT: [[CLASS:%.*]] = or <2 x i1> [[CMPZERO]], [[CMPINF]]
; CHECK-NEXT: ret <2 x i1> [[CLASS]]
;
%fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
%cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
%cmpzero = fcmp oeq <2 x half> %x, zeroinitializer
%class = or <2 x i1> %cmpzero, %cmpinf
ret <2 x i1> %class
}

; Base pattern !isfinite(x) || x == 0.0, with unknown input denormal treatment
define i1 @not_isfinite_or_zero_f16_dynamic(half %x) #2 {
; CHECK-LABEL: @not_isfinite_or_zero_f16_dynamic(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq half [[FABS]], 0xH7C00
; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq half [[X]], 0xH0000
; CHECK-NEXT: [[CLASS:%.*]] = or i1 [[CMPZERO]], [[CMPINF]]
; CHECK-NEXT: ret i1 [[CLASS]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%cmpinf = fcmp ueq half %fabs, 0xH7C00
%cmpzero = fcmp oeq half %x, 0xH0000
%class = or i1 %cmpzero, %cmpinf
ret i1 %class
}

define <2 x i1> @not_isfinite_or_zero_v2f16_dynamic(<2 x half> %x) #2 {
; CHECK-LABEL: @not_isfinite_or_zero_v2f16_dynamic(
; CHECK-NEXT: [[FABS:%.*]] = call <2 x half> @llvm.fabs.v2f16(<2 x half> [[X:%.*]])
; CHECK-NEXT: [[CMPINF:%.*]] = fcmp ueq <2 x half> [[FABS]], <half 0xH7C00, half 0xH7C00>
; CHECK-NEXT: [[CMPZERO:%.*]] = fcmp oeq <2 x half> [[X]], zeroinitializer
; CHECK-NEXT: [[CLASS:%.*]] = or <2 x i1> [[CMPZERO]], [[CMPINF]]
; CHECK-NEXT: ret <2 x i1> [[CLASS]]
;
%fabs = call <2 x half> @llvm.fabs.v2f16(<2 x half> %x)
%cmpinf = fcmp ueq <2 x half> %fabs, <half 0xH7C00, half 0xH7C00>
%cmpzero = fcmp oeq <2 x half> %x, zeroinitializer
%class = or <2 x i1> %cmpzero, %cmpinf
ret <2 x i1> %class
}

define i1 @not_zero_and_subnormal_daz(half %x) #1 {
; CHECK-LABEL: @not_zero_and_subnormal_daz(
; CHECK-NEXT: [[OR:%.*]] = fcmp ord half [[X:%.*]], 0xH0000
; CHECK-NEXT: ret i1 [[OR]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%cmp.zero = fcmp one half %fabs, 0.0
%cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
%or = or i1 %cmp.smallest.normal, %cmp.zero
ret i1 %or
}

define i1 @not_zero_and_subnormal_dynamic(half %x) #2 {
; CHECK-LABEL: @not_zero_and_subnormal_dynamic(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[CMP_ZERO:%.*]] = fcmp one half [[X]], 0xH0000
; CHECK-NEXT: [[CMP_SMALLEST_NORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT: [[OR:%.*]] = or i1 [[CMP_SMALLEST_NORMAL]], [[CMP_ZERO]]
; CHECK-NEXT: ret i1 [[OR]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%cmp.zero = fcmp one half %fabs, 0.0
%cmp.smallest.normal = fcmp olt half %fabs, 0xH0400
%or = or i1 %cmp.smallest.normal, %cmp.zero
ret i1 %or
}

; TODO: This could fold to just fcmp olt half %fabs, 0xH0400
define i1 @subnormal_or_zero_ieee(half %x) #0 {
; CHECK-LABEL: @subnormal_or_zero_ieee(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq half [[X]], 0xH0000
; CHECK-NEXT: [[AND:%.*]] = or i1 [[IS_SUBNORMAL]], [[IS_ZERO]]
; CHECK-NEXT: ret i1 [[AND]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
%is.zero = fcmp oeq half %x, 0xH0000
%and = or i1 %is.subnormal, %is.zero
ret i1 %and
}

define i1 @subnormal_or_zero_daz(half %x) #1 {
; CHECK-LABEL: @subnormal_or_zero_daz(
; CHECK-NEXT: [[AND:%.*]] = fcmp oeq half [[X:%.*]], 0xH0000
; CHECK-NEXT: ret i1 [[AND]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
%is.zero = fcmp oeq half %x, 0xH0000
%and = or i1 %is.subnormal, %is.zero
ret i1 %and
}

define i1 @subnormal_or_zero_dynamic(half %x) #2 {
; CHECK-LABEL: @subnormal_or_zero_dynamic(
; CHECK-NEXT: [[FABS:%.*]] = call half @llvm.fabs.f16(half [[X:%.*]])
; CHECK-NEXT: [[IS_SUBNORMAL:%.*]] = fcmp olt half [[FABS]], 0xH0400
; CHECK-NEXT: [[IS_ZERO:%.*]] = fcmp oeq half [[X]], 0xH0000
; CHECK-NEXT: [[AND:%.*]] = or i1 [[IS_SUBNORMAL]], [[IS_ZERO]]
; CHECK-NEXT: ret i1 [[AND]]
;
%fabs = call half @llvm.fabs.f16(half %x)
%is.subnormal = fcmp olt half %fabs, 0xH0400
%is.zero = fcmp oeq half %x, 0xH0000
%and = or i1 %is.subnormal, %is.zero
ret i1 %and
}

declare half @llvm.fabs.f16(half) #0
declare half @llvm.canonicalize.f16(half) #0
declare <2 x half> @llvm.fabs.v2f16(<2 x half>) #0

attributes #0 = { nocallback nofree nosync nounwind speculatable willreturn memory(none) }
attributes #1 = { "denormal-fp-math"="ieee,preserve-sign" }
attributes #2 = { "denormal-fp-math"="ieee,dynamic" }

0 comments on commit 0b5c51b

Please sign in to comment.