llvm-project/llvm/test/Transforms/InstCombine/fpclass-check-idioms.ll
Yingwei Zheng a10f6c1e68
[InstCombine] Handle isnormal idiom (#125454)
This patch improves the codegen of Rust's `is_normal` implementation:
https://godbolt.org/z/1MPzcrrYG
Alive2: https://alive2.llvm.org/ce/z/hF9RWQ
2025-05-06 23:55:04 +08:00

1228 lines
43 KiB
LLVM

; NOTE: Assertions have been autogenerated by utils/update_test_checks.py UTC_ARGS: --version 4
; RUN: opt -S -passes=instcombine < %s | FileCheck %s
define i1 @f32_fcnan_fcinf(float %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq float [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0:[0-9]+]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 519)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_not_fcnan_fcinf(float %a) {
; CHECK-LABEL: define i1 @f32_not_fcnan_fcinf(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp one float [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp ne i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_not_fcnan_fcinf_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_not_fcnan_fcinf_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 504)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp ne i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f64_fcnan_fcinf(double %a) {
; CHECK-LABEL: define i1 @f64_fcnan_fcinf(
; CHECK-SAME: double [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq double [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast double %a to i64
%and = and i64 %i64, 9218868437227405312
%cmp = icmp eq i64 %and, 9218868437227405312
ret i1 %cmp
}
define i1 @f64_fcnan_fcinf_strictfp(double %a) strictfp {
; CHECK-LABEL: define i1 @f64_fcnan_fcinf_strictfp(
; CHECK-SAME: double [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f64(double [[A]], i32 519)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast double %a to i64
%and = and i64 %i64, 9218868437227405312
%cmp = icmp eq i64 %and, 9218868437227405312
ret i1 %cmp
}
define i1 @f32_fcinf(float %a) {
; CHECK-LABEL: define i1 @f32_fcinf(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2147483647
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcinf_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcinf_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 516)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2147483647
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf(float %a) {
; CHECK-LABEL: define i1 @f32_fcposinf(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposinf_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 512)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @f32_fcneginf(float %a) {
; CHECK-LABEL: define i1 @f32_fcneginf(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A]], 0xFFF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 4286578688
ret i1 %cmp
}
define i1 @f32_fcneginf_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcneginf_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 4)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 4286578688
ret i1 %cmp
}
define i1 @f32_fcposzero(float %a) {
; CHECK-LABEL: define i1 @f32_fcposzero(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 0
ret i1 %cmp
}
define i1 @f32_fcposzero_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposzero_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 64)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 0
ret i1 %cmp
}
define i1 @f32_fcnegzero(float %a) {
; CHECK-LABEL: define i1 @f32_fcnegzero(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2147483648
ret i1 %cmp
}
define i1 @f32_fcnegzero_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnegzero_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 32)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2147483648
ret i1 %cmp
}
define i1 @f32_fczero(float %a) {
; CHECK-LABEL: define i1 @f32_fczero(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2147483647
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_fczero_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fczero_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 96)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2147483647
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
; TODO: handle more fpclass check idioms
define i1 @f32_fcnan(float %a) {
; CHECK-LABEL: define i1 @f32_fcnan(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = fcmp uno float [[A]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RES]]
;
%i32 = bitcast float %a to i32
%and1 = and i32 %i32, 2139095040
%cmp1 = icmp eq i32 %and1, 2139095040
%and2 = and i32 %i32, 8388607
%cmp2 = icmp ne i32 %and2, 0
%res = and i1 %cmp1, %cmp2
ret i1 %res
}
define i1 @f32_fcnan_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND1:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP1:%.*]] = icmp eq i32 [[AND1]], 2139095040
; CHECK-NEXT: [[AND2:%.*]] = and i32 [[I32]], 8388607
; CHECK-NEXT: [[CMP2:%.*]] = icmp ne i32 [[AND2]], 0
; CHECK-NEXT: [[RES:%.*]] = and i1 [[CMP1]], [[CMP2]]
; CHECK-NEXT: ret i1 [[RES]]
;
%i32 = bitcast float %a to i32
%and1 = and i32 %i32, 2139095040
%cmp1 = icmp eq i32 %and1, 2139095040
%and2 = and i32 %i32, 8388607
%cmp2 = icmp ne i32 %and2, 0
%res = and i1 %cmp1, %cmp2
ret i1 %res
}
define <2 x i1> @f32_fcnan_fcinf_vec(<2 x float> %a) {
; CHECK-LABEL: define <2 x i1> @f32_fcnan_fcinf_vec(
; CHECK-SAME: <2 x float> [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp ueq <2 x float> [[TMP1]], splat (float 0x7FF0000000000000)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i32 = bitcast <2 x float> %a to <2 x i32>
%and = and <2 x i32> %i32, <i32 2139095040, i32 2139095040>
%cmp = icmp eq <2 x i32> %and, <i32 2139095040, i32 2139095040>
ret <2 x i1> %cmp
}
define <2 x i1> @f32_fcnan_fcinf_vec_strictfp(<2 x float> %a) strictfp {
; CHECK-LABEL: define <2 x i1> @f32_fcnan_fcinf_vec_strictfp(
; CHECK-SAME: <2 x float> [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[A]], i32 519)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i32 = bitcast <2 x float> %a to <2 x i32>
%and = and <2 x i32> %i32, <i32 2139095040, i32 2139095040>
%cmp = icmp eq <2 x i32> %and, <i32 2139095040, i32 2139095040>
ret <2 x i1> %cmp
}
define <2 x i1> @f32_fcinf_vec(<2 x float> %a) {
; CHECK-LABEL: define <2 x i1> @f32_fcinf_vec(
; CHECK-SAME: <2 x float> [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call <2 x float> @llvm.fabs.v2f32(<2 x float> [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp oeq <2 x float> [[TMP1]], splat (float 0x7FF0000000000000)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i32 = bitcast <2 x float> %a to <2 x i32>
%and = and <2 x i32> %i32, <i32 2147483647, i32 2147483647>
%cmp = icmp eq <2 x i32> %and, <i32 2139095040, i32 2139095040>
ret <2 x i1> %cmp
}
define <2 x i1> @f32_fcinf_vec_strictfp(<2 x float> %a) strictfp {
; CHECK-LABEL: define <2 x i1> @f32_fcinf_vec_strictfp(
; CHECK-SAME: <2 x float> [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[A]], i32 516)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i32 = bitcast <2 x float> %a to <2 x i32>
%and = and <2 x i32> %i32, <i32 2147483647, i32 2147483647>
%cmp = icmp eq <2 x i32> %and, <i32 2139095040, i32 2139095040>
ret <2 x i1> %cmp
}
; Negative tests
define i1 @f32_fcnan_fcinf_wrong_mask1(float %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask1(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095041
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095041
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_mask1_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask1_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095041
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095041
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_mask2(float %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask2(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2130706432
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2130706432
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_mask2_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_mask2_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2130706432
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2130706432
ret i1 %cmp
}
define i1 @f64_fcnan_fcinf_wrong_mask3(double %a) {
; CHECK-LABEL: define i1 @f64_fcnan_fcinf_wrong_mask3(
; CHECK-SAME: double [[A:%.*]]) {
; CHECK-NEXT: [[I64:%.*]] = bitcast double [[A]] to i64
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast double %a to i64
%and = and i64 %i64, 2139095040
%cmp = icmp eq i64 %and, 2139095040
ret i1 %cmp
}
define i1 @f64_fcnan_fcinf_wrong_mask3_strictfp(double %a) strictfp {
; CHECK-LABEL: define i1 @f64_fcnan_fcinf_wrong_mask3_strictfp(
; CHECK-SAME: double [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I64:%.*]] = bitcast double [[A]] to i64
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast double %a to i64
%and = and i64 %i64, 2139095040
%cmp = icmp eq i64 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_pred(float %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_pred(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call float @llvm.fabs.f32(float [[A]])
; CHECK-NEXT: [[CMP:%.*]] = fcmp one float [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp slt i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_pred_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_pred_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 504)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp slt i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposzero_wrong_pred(float %a) {
; CHECK-LABEL: define i1 @f32_fcposzero_wrong_pred(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp slt i32 %i32, 0
ret i1 %cmp
}
define i1 @f32_fcposzero_wrong_pred_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposzero_wrong_pred_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp slt i32 [[I32]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp slt i32 %i32, 0
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_type1(<2 x float> %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type1(
; CHECK-SAME: <2 x float> [[A:%.*]]) {
; CHECK-NEXT: [[I64:%.*]] = bitcast <2 x float> [[A]] to i64
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast <2 x float> %a to i64
%and = and i64 %i64, 2139095040
%cmp = icmp eq i64 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_type1_strictfp(<2 x float> %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type1_strictfp(
; CHECK-SAME: <2 x float> [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I64:%.*]] = bitcast <2 x float> [[A]] to i64
; CHECK-NEXT: [[AND:%.*]] = and i64 [[I64]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast <2 x float> %a to i64
%and = and i64 %i64, 2139095040
%cmp = icmp eq i64 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf_wrong_type1(<2 x float> %a) {
; CHECK-LABEL: define i1 @f32_fcposinf_wrong_type1(
; CHECK-SAME: <2 x float> [[A:%.*]]) {
; CHECK-NEXT: [[I64:%.*]] = bitcast <2 x float> [[A]] to i64
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[I64]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast <2 x float> %a to i64
%cmp = icmp eq i64 %i64, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf_wrong_type1_strictfp(<2 x float> %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposinf_wrong_type1_strictfp(
; CHECK-SAME: <2 x float> [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I64:%.*]] = bitcast <2 x float> [[A]] to i64
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i64 [[I64]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i64 = bitcast <2 x float> %a to i64
%cmp = icmp eq i64 %i64, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_type2(x86_fp80 %a) {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type2(
; CHECK-SAME: x86_fp80 [[A:%.*]]) {
; CHECK-NEXT: [[I80:%.*]] = bitcast x86_fp80 [[A]] to i80
; CHECK-NEXT: [[AND:%.*]] = and i80 [[I80]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i80 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i80 = bitcast x86_fp80 %a to i80
%and = and i80 %i80, 2139095040
%cmp = icmp eq i80 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_wrong_type2_strictfp(x86_fp80 %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_wrong_type2_strictfp(
; CHECK-SAME: x86_fp80 [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I80:%.*]] = bitcast x86_fp80 [[A]] to i80
; CHECK-NEXT: [[AND:%.*]] = and i80 [[I80]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i80 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i80 = bitcast x86_fp80 %a to i80
%and = and i80 %i80, 2139095040
%cmp = icmp eq i80 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposzero_wrong_type2(x86_fp80 %a) {
; CHECK-LABEL: define i1 @f32_fcposzero_wrong_type2(
; CHECK-SAME: x86_fp80 [[A:%.*]]) {
; CHECK-NEXT: [[I80:%.*]] = bitcast x86_fp80 [[A]] to i80
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i80 [[I80]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i80 = bitcast x86_fp80 %a to i80
%cmp = icmp eq i80 %i80, 0
ret i1 %cmp
}
define i1 @f32_fcposzero_wrong_type2_strictfp(x86_fp80 %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposzero_wrong_type2_strictfp(
; CHECK-SAME: x86_fp80 [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I80:%.*]] = bitcast x86_fp80 [[A]] to i80
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i80 [[I80]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i80 = bitcast x86_fp80 %a to i80
%cmp = icmp eq i80 %i80, 0
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_noimplicitfloat(float %a) #0 {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_noimplicitfloat(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1:[0-9]+]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcnan_fcinf_noimplicitfloat_strictfp(float %a) strictfp #0 {
; CHECK-LABEL: define i1 @f32_fcnan_fcinf_noimplicitfloat_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR2:[0-9]+]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2139095040
ret i1 %cmp
}
define i1 @f32_fcsubnormal_fczero(float %a) {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 240)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_not_fcsubnormal_fczero(float %a) {
; CHECK-LABEL: define i1 @f32_not_fcsubnormal_fczero(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 783)
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp ne i32 %and, 0
ret i1 %cmp
}
define <2 x i1> @f64_fcsubnormal_fczero_vec(<2 x double> %a) {
; CHECK-LABEL: define <2 x i1> @f64_fcsubnormal_fczero_vec(
; CHECK-SAME: <2 x double> [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f64(<2 x double> [[A]], i32 240)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i64 = bitcast <2 x double> %a to <2 x i64>
%and = and <2 x i64> %i64, splat(i64 9218868437227405312)
%cmp = icmp eq <2 x i64> %and, zeroinitializer
ret <2 x i1> %cmp
}
define <2 x i1> @f64_no_fcsubnormal_fczero_vec(<2 x double> %a) {
; CHECK-LABEL: define <2 x i1> @f64_no_fcsubnormal_fczero_vec(
; CHECK-SAME: <2 x double> [[A:%.*]]) {
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f64(<2 x double> [[A]], i32 783)
; CHECK-NEXT: ret <2 x i1> [[CMP]]
;
%i64 = bitcast <2 x double> %a to <2 x i64>
%and = and <2 x i64> %i64, splat(i64 9218868437227405312)
%cmp = icmp ne <2 x i64> %and, zeroinitializer
ret <2 x i1> %cmp
}
define i1 @f32_fcsubnormal_fczero_no_implicit_fp(float %a) #0 {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_no_implicit_fp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_fcsubnormal_fczero_invalid_constant1(float %a) {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_invalid_constant1(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095039
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095039
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_fcsubnormal_fczero_invalid_constant2(float %a) {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_invalid_constant2(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2130706432
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 2130706432
ret i1 %cmp
}
define i1 @ppc128_fcsubnormal_fczero(ppc_fp128 %a) {
; CHECK-LABEL: define i1 @ppc128_fcsubnormal_fczero(
; CHECK-SAME: ppc_fp128 [[A:%.*]]) {
; CHECK-NEXT: [[I128:%.*]] = bitcast ppc_fp128 [[A]] to i128
; CHECK-NEXT: [[AND:%.*]] = and i128 [[I128]], 170058106710732674489630815774616584192
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[AND]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i128 = bitcast ppc_fp128 %a to i128
%and = and i128 %i128, 170058106710732674489630815774616584192
%cmp = icmp eq i128 %and, 0
ret i1 %cmp
}
define i1 @f32_fcsubnormal_fczero_multiuse1(float %a) {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_multiuse1(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: call void @usei32(i32 [[I32]])
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
call void @usei32(i32 %i32)
%and = and i32 %i32, 2139095040
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_fcsubnormal_fczero_multiuse2(float %a) {
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_multiuse2(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
; CHECK-NEXT: call void @usei32(i32 [[AND]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%and = and i32 %i32, 2139095040
call void @usei32(i32 %and)
%cmp = icmp eq i32 %and, 0
ret i1 %cmp
}
define i1 @f32_fcposinf_noimplicitfloat(float %a) #0 {
; CHECK-LABEL: define i1 @f32_fcposinf_noimplicitfloat(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf_noimplicitfloat_strictfp(float %a) strictfp #0 {
; CHECK-LABEL: define i1 @f32_fcposinf_noimplicitfloat_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR2]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposnan(float %a) {
; CHECK-LABEL: define i1 @f32_fcposnan(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095041
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095041
ret i1 %cmp
}
define i1 @f32_fcposnan_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposnan_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095041
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
%cmp = icmp eq i32 %i32, 2139095041
ret i1 %cmp
}
define i1 @f32_fcposinf_multiuse(float %a) {
; CHECK-LABEL: define i1 @f32_fcposinf_multiuse(
; CHECK-SAME: float [[A:%.*]]) {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: call void @usei32(i32 [[I32]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
call void @usei32(i32 %i32)
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @f32_fcposinf_multiuse_strictfp(float %a) strictfp {
; CHECK-LABEL: define i1 @f32_fcposinf_multiuse_strictfp(
; CHECK-SAME: float [[A:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
; CHECK-NEXT: call void @usei32(i32 [[I32]])
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[I32]], 2139095040
; CHECK-NEXT: ret i1 [[CMP]]
;
%i32 = bitcast float %a to i32
call void @usei32(i32 %i32)
%cmp = icmp eq i32 %i32, 2139095040
ret i1 %cmp
}
define i1 @isnan_idiom(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[RET:%.*]] = fcmp uno double [[X]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define <2 x i1> @isnan_idiom_vec(<2 x double> %x) {
; CHECK-LABEL: define <2 x i1> @isnan_idiom_vec(
; CHECK-SAME: <2 x double> [[X:%.*]]) {
; CHECK-NEXT: [[RET:%.*]] = fcmp uno <2 x double> [[X]], zeroinitializer
; CHECK-NEXT: ret <2 x i1> [[RET]]
;
%bits = bitcast <2 x double> %x to <2 x i64>
%mask1 = and <2 x i64> %bits, splat(i64 9218868437227405312)
%cond1 = icmp eq <2 x i64> %mask1, splat(i64 9218868437227405312)
%mask2 = and <2 x i64> %bits, splat(i64 4503599627370495)
%cond2 = icmp ne <2 x i64> %mask2, zeroinitializer
%ret = and <2 x i1> %cond1, %cond2
ret <2 x i1> %ret
}
define i1 @isnan_idiom_commuted(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_commuted(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[RET:%.*]] = fcmp uno double [[X]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond2, %cond1
ret i1 %ret
}
define i1 @isnotnan_idiom(double %x) {
; CHECK-LABEL: define i1 @isnotnan_idiom(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[RET:%.*]] = fcmp ord double [[X]], 0.000000e+00
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp ne i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp eq i64 %mask2, 0
%ret = or i1 %cond1, %cond2
ret i1 %ret
}
; negative tests
define i1 @isnan_idiom_strictfp(double %x) strictfp {
; CHECK-LABEL: define i1 @isnan_idiom_strictfp(
; CHECK-SAME: double [[X:%.*]]) #[[ATTR0]] {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370495
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_pred1(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_pred1(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp ne i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370495
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp ne i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_pred2(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_pred2(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[TMP1:%.*]] = call double @llvm.fabs.f64(double [[X]])
; CHECK-NEXT: [[RET:%.*]] = fcmp oeq double [[TMP1]], 0x7FF0000000000000
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp eq i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_pred3(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_pred3(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370495
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = or i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = or i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_mask1(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_mask1(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405311
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405311
; CHECK-NEXT: ret i1 [[COND1]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405311
%cond1 = icmp eq i64 %mask1, 9218868437227405311
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_mask2(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_mask2(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370494
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370494
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_wrong_mask3(double %x) {
; CHECK-LABEL: define i1 @isnan_idiom_wrong_mask3(
; CHECK-SAME: double [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast double [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370495
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 4503599627370495
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast double %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 4503599627370495
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_invalid_bitcast(<2 x float> %x) {
; CHECK-LABEL: define i1 @isnan_idiom_invalid_bitcast(
; CHECK-SAME: <2 x float> [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast <2 x float> [[X]] to i64
; CHECK-NEXT: [[MASK1:%.*]] = and i64 [[BITS]], 9218868437227405312
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i64 [[MASK1]], 9218868437227405312
; CHECK-NEXT: [[MASK2:%.*]] = and i64 [[BITS]], 4503599627370495
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i64 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast <2 x float> %x to i64
%mask1 = and i64 %bits, 9218868437227405312
%cond1 = icmp eq i64 %mask1, 9218868437227405312
%mask2 = and i64 %bits, 4503599627370495
%cond2 = icmp ne i64 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @isnan_idiom_ppc_fp128(ppc_fp128 %x) {
; CHECK-LABEL: define i1 @isnan_idiom_ppc_fp128(
; CHECK-SAME: ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[MASK1:%.*]] = and i128 [[BITS]], 170058106710732674489630815774616584192
; CHECK-NEXT: [[COND1:%.*]] = icmp eq i128 [[MASK1]], 170058106710732674489630815774616584192
; CHECK-NEXT: [[MASK2:%.*]] = and i128 [[BITS]], 83076749736557242056487941267521535
; CHECK-NEXT: [[COND2:%.*]] = icmp ne i128 [[MASK2]], 0
; CHECK-NEXT: [[RET:%.*]] = and i1 [[COND1]], [[COND2]]
; CHECK-NEXT: ret i1 [[RET]]
;
%bits = bitcast ppc_fp128 %x to i128
%mask1 = and i128 %bits, 170058106710732674489630815774616584192
%cond1 = icmp eq i128 %mask1, 170058106710732674489630815774616584192
%mask2 = and i128 %bits, 83076749736557242056487941267521535
%cond2 = icmp ne i128 %mask2, 0
%ret = and i1 %cond1, %cond2
ret i1 %ret
}
define i1 @fpclass_test_normal(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NUM]], i32 264)
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp ne i32 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_half(half %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_half(
; CHECK-SAME: half [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call i1 @llvm.is.fpclass.f16(half [[NUM]], i32 264)
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast half %num to i16
%masked = and i16 %cast, 31744
%test1 = icmp ne i16 %masked, 31744
%test2 = icmp ne i16 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define <2 x i1> @fpclass_test_normal_half_vec(<2 x half> %num) {
; CHECK-LABEL: define <2 x i1> @fpclass_test_normal_half_vec(
; CHECK-SAME: <2 x half> [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f16(<2 x half> [[NUM]], i32 264)
; CHECK-NEXT: ret <2 x i1> [[RES]]
;
%cast = bitcast <2 x half> %num to <2 x i16>
%masked = and <2 x i16> %cast, splat(i16 31744)
%test1 = icmp ne <2 x i16> %masked, splat(i16 31744)
%test2 = icmp ne <2 x i16> %masked, zeroinitializer
%res = and <2 x i1> %test1, %test2
ret <2 x i1> %res
}
define i1 @fpclass_test_not_normal(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_not_normal(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NUM]], i32 759)
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp eq i32 %masked, 2139095040
%test2 = icmp eq i32 %masked, 0
%res = or i1 %test1, %test2
ret i1 %res
}
define <2 x i1> @fpclass_test_not_normal_vec(<2 x float> %num) {
; CHECK-LABEL: define <2 x i1> @fpclass_test_not_normal_vec(
; CHECK-SAME: <2 x float> [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f32(<2 x float> [[NUM]], i32 759)
; CHECK-NEXT: ret <2 x i1> [[RES]]
;
%cast = bitcast <2 x float> %num to <2 x i32>
%masked = and <2 x i32> %cast, splat(i32 2139095040)
%test1 = icmp eq <2 x i32> %masked, splat(i32 2139095040)
%test2 = icmp eq <2 x i32> %masked, zeroinitializer
%res = or <2 x i1> %test1, %test2
ret <2 x i1> %res
}
define i1 @fpclass_test_normal_commuted(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_commuted(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[RES:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NUM]], i32 264)
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp ne i32 %masked, 0
%res = and i1 %test2, %test1
ret i1 %res
}
; Negative tests
define i1 @fpclass_test_normal_fp128(ppc_fp128 %x) {
; CHECK-LABEL: define i1 @fpclass_test_normal_fp128(
; CHECK-SAME: ppc_fp128 [[X:%.*]]) {
; CHECK-NEXT: [[BITS:%.*]] = bitcast ppc_fp128 [[X]] to i128
; CHECK-NEXT: [[MASKED:%.*]] = and i128 [[BITS]], 170058106710732674489630815774616584192
; CHECK-NEXT: [[TEST1:%.*]] = icmp ne i128 [[MASKED]], 170058106710732674489630815774616584192
; CHECK-NEXT: [[TEST2:%.*]] = icmp ne i128 [[MASKED]], 0
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TEST2]], [[TEST1]]
; CHECK-NEXT: ret i1 [[RES]]
;
%bits = bitcast ppc_fp128 %x to i128
%masked = and i128 %bits, 170058106710732674489630815774616584192
%test1 = icmp ne i128 %masked, 170058106710732674489630815774616584192
%test2 = icmp ne i128 %masked, 0
%res = and i1 %test2, %test1
ret i1 %res
}
define i1 @fpclass_test_normal_mismatch_pred(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_mismatch_pred(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[TEST2:%.*]] = call i1 @llvm.is.fpclass.f32(float [[NUM]], i32 240)
; CHECK-NEXT: ret i1 [[TEST2]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp eq i32 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_no_implicit_fp(float %num) #0 {
; CHECK-LABEL: define i1 @fpclass_test_normal_no_implicit_fp(
; CHECK-SAME: float [[NUM:%.*]]) #[[ATTR1]] {
; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[NUM]] to i32
; CHECK-NEXT: [[MASKED:%.*]] = and i32 [[CAST]], 2139095040
; CHECK-NEXT: [[TEST1:%.*]] = icmp ne i32 [[MASKED]], 2139095040
; CHECK-NEXT: [[TEST2:%.*]] = icmp ne i32 [[MASKED]], 0
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TEST1]], [[TEST2]]
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp ne i32 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_invalid_constant1(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_invalid_constant1(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[NUM]] to i32
; CHECK-NEXT: [[MASKED:%.*]] = and i32 [[CAST]], 2139095039
; CHECK-NEXT: [[TEST1:%.*]] = icmp ne i32 [[MASKED]], 2139095039
; CHECK-NEXT: [[TEST2:%.*]] = icmp ne i32 [[MASKED]], 0
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TEST1]], [[TEST2]]
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095039
%test1 = icmp ne i32 %masked, 2139095039
%test2 = icmp ne i32 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_invalid_constant2(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_invalid_constant2(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[NUM]] to i32
; CHECK-NEXT: [[MASKED:%.*]] = and i32 [[CAST]], 2139095040
; CHECK-NEXT: [[TEST1:%.*]] = icmp ne i32 [[MASKED]], 2130706432
; CHECK-NEXT: [[TEST2:%.*]] = icmp ne i32 [[MASKED]], 0
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TEST1]], [[TEST2]]
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2130706432
%test2 = icmp ne i32 %masked, 0
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_invalid_constant3(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_invalid_constant3(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[NUM]] to i32
; CHECK-NEXT: [[TMP1:%.*]] = and i32 [[CAST]], 2130706432
; CHECK-NEXT: [[RES:%.*]] = icmp ne i32 [[TMP1]], 2130706432
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp ne i32 %masked, 2130706432
%res = and i1 %test1, %test2
ret i1 %res
}
define i1 @fpclass_test_normal_multiuse(float %num) {
; CHECK-LABEL: define i1 @fpclass_test_normal_multiuse(
; CHECK-SAME: float [[NUM:%.*]]) {
; CHECK-NEXT: [[CAST:%.*]] = bitcast float [[NUM]] to i32
; CHECK-NEXT: [[MASKED:%.*]] = and i32 [[CAST]], 2139095040
; CHECK-NEXT: [[TEST1:%.*]] = icmp ne i32 [[MASKED]], 2139095040
; CHECK-NEXT: [[TEST2:%.*]] = icmp ne i32 [[MASKED]], 0
; CHECK-NEXT: call void @usei1(i1 [[TEST1]])
; CHECK-NEXT: [[RES:%.*]] = and i1 [[TEST1]], [[TEST2]]
; CHECK-NEXT: ret i1 [[RES]]
;
%cast = bitcast float %num to i32
%masked = and i32 %cast, 2139095040
%test1 = icmp ne i32 %masked, 2139095040
%test2 = icmp ne i32 %masked, 0
call void @usei1(i1 %test1)
%res = and i1 %test1, %test2
ret i1 %res
}
declare void @usei32(i32)
declare void @usei1(i1)
attributes #0 = { noimplicitfloat }