Skip to content

Commit e4980c6

Browse files
authored
[InstCombine] Handle isSubnormalOrZero idiom (llvm#125501)
Alive2: https://alive2.llvm.org/ce/z/9nYE3J
1 parent 3a2b552 commit e4980c6

File tree

2 files changed

+145
-3
lines changed

2 files changed

+145
-3
lines changed

llvm/lib/Transforms/InstCombine/InstCombineCompares.cpp

Lines changed: 9 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1884,17 +1884,23 @@ Instruction *InstCombinerImpl::foldICmpAndConstConst(ICmpInst &Cmp,
18841884
// llvm.is.fpclass(X, fcInf|fcNan)
18851885
// (icmp ne (and (bitcast X to int), ExponentMask), ExponentMask) -->
18861886
// llvm.is.fpclass(X, ~(fcInf|fcNan))
1887+
// (icmp eq (and (bitcast X to int), ExponentMask), 0) -->
1888+
// llvm.is.fpclass(X, fcSubnormal|fcZero)
1889+
// (icmp ne (and (bitcast X to int), ExponentMask), 0) -->
1890+
// llvm.is.fpclass(X, ~(fcSubnormal|fcZero))
18871891
Value *V;
18881892
if (!Cmp.getParent()->getParent()->hasFnAttribute(
18891893
Attribute::NoImplicitFloat) &&
18901894
Cmp.isEquality() &&
18911895
match(X, m_OneUse(m_ElementWiseBitCast(m_Value(V))))) {
18921896
Type *FPType = V->getType()->getScalarType();
1893-
if (FPType->isIEEELikeFPTy() && C1 == *C2) {
1897+
if (FPType->isIEEELikeFPTy() && (C1.isZero() || C1 == *C2)) {
18941898
APInt ExponentMask =
18951899
APFloat::getInf(FPType->getFltSemantics()).bitcastToAPInt();
1896-
if (C1 == ExponentMask) {
1897-
unsigned Mask = FPClassTest::fcNan | FPClassTest::fcInf;
1900+
if (*C2 == ExponentMask) {
1901+
unsigned Mask = C1.isZero()
1902+
? FPClassTest::fcZero | FPClassTest::fcSubnormal
1903+
: FPClassTest::fcNan | FPClassTest::fcInf;
18981904
if (isICMP_NE)
18991905
Mask = ~Mask & fcAllFlags;
19001906
return replaceInstUsesWith(Cmp, Builder.createIsFPClass(V, Mask));

llvm/test/Transforms/InstCombine/fpclass-check-idioms.ll

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -566,6 +566,142 @@ define i1 @f32_fcnan_fcinf_noimplicitfloat_strictfp(float %a) strictfp #0 {
566566
ret i1 %cmp
567567
}
568568

569+
define i1 @f32_fcsubnormal_fczero(float %a) {
570+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero(
571+
; CHECK-SAME: float [[A:%.*]]) {
572+
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 240)
573+
; CHECK-NEXT: ret i1 [[CMP]]
574+
;
575+
%i32 = bitcast float %a to i32
576+
%and = and i32 %i32, 2139095040
577+
%cmp = icmp eq i32 %and, 0
578+
ret i1 %cmp
579+
}
580+
581+
define i1 @f32_not_fcsubnormal_fczero(float %a) {
582+
; CHECK-LABEL: define i1 @f32_not_fcsubnormal_fczero(
583+
; CHECK-SAME: float [[A:%.*]]) {
584+
; CHECK-NEXT: [[CMP:%.*]] = call i1 @llvm.is.fpclass.f32(float [[A]], i32 783)
585+
; CHECK-NEXT: ret i1 [[CMP]]
586+
;
587+
%i32 = bitcast float %a to i32
588+
%and = and i32 %i32, 2139095040
589+
%cmp = icmp ne i32 %and, 0
590+
ret i1 %cmp
591+
}
592+
593+
define <2 x i1> @f64_fcsubnormal_fczero_vec(<2 x double> %a) {
594+
; CHECK-LABEL: define <2 x i1> @f64_fcsubnormal_fczero_vec(
595+
; CHECK-SAME: <2 x double> [[A:%.*]]) {
596+
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f64(<2 x double> [[A]], i32 240)
597+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
598+
;
599+
%i64 = bitcast <2 x double> %a to <2 x i64>
600+
%and = and <2 x i64> %i64, splat(i64 9218868437227405312)
601+
%cmp = icmp eq <2 x i64> %and, zeroinitializer
602+
ret <2 x i1> %cmp
603+
}
604+
605+
define <2 x i1> @f64_no_fcsubnormal_fczero_vec(<2 x double> %a) {
606+
; CHECK-LABEL: define <2 x i1> @f64_no_fcsubnormal_fczero_vec(
607+
; CHECK-SAME: <2 x double> [[A:%.*]]) {
608+
; CHECK-NEXT: [[CMP:%.*]] = call <2 x i1> @llvm.is.fpclass.v2f64(<2 x double> [[A]], i32 783)
609+
; CHECK-NEXT: ret <2 x i1> [[CMP]]
610+
;
611+
%i64 = bitcast <2 x double> %a to <2 x i64>
612+
%and = and <2 x i64> %i64, splat(i64 9218868437227405312)
613+
%cmp = icmp ne <2 x i64> %and, zeroinitializer
614+
ret <2 x i1> %cmp
615+
}
616+
617+
define i1 @f32_fcsubnormal_fczero_no_implicit_fp(float %a) #0 {
618+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_no_implicit_fp(
619+
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1]] {
620+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
621+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
622+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
623+
; CHECK-NEXT: ret i1 [[CMP]]
624+
;
625+
%i32 = bitcast float %a to i32
626+
%and = and i32 %i32, 2139095040
627+
%cmp = icmp eq i32 %and, 0
628+
ret i1 %cmp
629+
}
630+
631+
define i1 @f32_fcsubnormal_fczero_invalid_constant1(float %a) {
632+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_invalid_constant1(
633+
; CHECK-SAME: float [[A:%.*]]) {
634+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
635+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095039
636+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
637+
; CHECK-NEXT: ret i1 [[CMP]]
638+
;
639+
%i32 = bitcast float %a to i32
640+
%and = and i32 %i32, 2139095039
641+
%cmp = icmp eq i32 %and, 0
642+
ret i1 %cmp
643+
}
644+
645+
define i1 @f32_fcsubnormal_fczero_invalid_constant2(float %a) {
646+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_invalid_constant2(
647+
; CHECK-SAME: float [[A:%.*]]) {
648+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
649+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
650+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 2130706432
651+
; CHECK-NEXT: ret i1 [[CMP]]
652+
;
653+
%i32 = bitcast float %a to i32
654+
%and = and i32 %i32, 2139095040
655+
%cmp = icmp eq i32 %and, 2130706432
656+
ret i1 %cmp
657+
}
658+
659+
define i1 @ppc128_fcsubnormal_fczero(ppc_fp128 %a) {
660+
; CHECK-LABEL: define i1 @ppc128_fcsubnormal_fczero(
661+
; CHECK-SAME: ppc_fp128 [[A:%.*]]) {
662+
; CHECK-NEXT: [[I128:%.*]] = bitcast ppc_fp128 [[A]] to i128
663+
; CHECK-NEXT: [[AND:%.*]] = and i128 [[I128]], 170058106710732674489630815774616584192
664+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i128 [[AND]], 0
665+
; CHECK-NEXT: ret i1 [[CMP]]
666+
;
667+
%i128 = bitcast ppc_fp128 %a to i128
668+
%and = and i128 %i128, 170058106710732674489630815774616584192
669+
%cmp = icmp eq i128 %and, 0
670+
ret i1 %cmp
671+
}
672+
673+
define i1 @f32_fcsubnormal_fczero_multiuse1(float %a) {
674+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_multiuse1(
675+
; CHECK-SAME: float [[A:%.*]]) {
676+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
677+
; CHECK-NEXT: call void @usei32(i32 [[I32]])
678+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
679+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
680+
; CHECK-NEXT: ret i1 [[CMP]]
681+
;
682+
%i32 = bitcast float %a to i32
683+
call void @usei32(i32 %i32)
684+
%and = and i32 %i32, 2139095040
685+
%cmp = icmp eq i32 %and, 0
686+
ret i1 %cmp
687+
}
688+
689+
define i1 @f32_fcsubnormal_fczero_multiuse2(float %a) {
690+
; CHECK-LABEL: define i1 @f32_fcsubnormal_fczero_multiuse2(
691+
; CHECK-SAME: float [[A:%.*]]) {
692+
; CHECK-NEXT: [[I32:%.*]] = bitcast float [[A]] to i32
693+
; CHECK-NEXT: [[AND:%.*]] = and i32 [[I32]], 2139095040
694+
; CHECK-NEXT: call void @usei32(i32 [[AND]])
695+
; CHECK-NEXT: [[CMP:%.*]] = icmp eq i32 [[AND]], 0
696+
; CHECK-NEXT: ret i1 [[CMP]]
697+
;
698+
%i32 = bitcast float %a to i32
699+
%and = and i32 %i32, 2139095040
700+
call void @usei32(i32 %and)
701+
%cmp = icmp eq i32 %and, 0
702+
ret i1 %cmp
703+
}
704+
569705
define i1 @f32_fcposinf_noimplicitfloat(float %a) #0 {
570706
; CHECK-LABEL: define i1 @f32_fcposinf_noimplicitfloat(
571707
; CHECK-SAME: float [[A:%.*]]) #[[ATTR1]] {

0 commit comments

Comments
 (0)