Index: lib/Transforms/InstCombine/InstCombineCompares.cpp =================================================================== --- lib/Transforms/InstCombine/InstCombineCompares.cpp +++ lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3726,15 +3726,7 @@ IntegerType *IntTy = cast(LHSI->getOperand(0)->getType()); - // Check to see that the input is converted from an integer type that is small - // enough that preserves all bits. TODO: check here for "known" sign bits. - // This would allow us to handle (fptosi (x >>s 62) to float) if x is i64 f.e. - unsigned InputSize = IntTy->getScalarSizeInBits(); - - // If this is a uitofp instruction, we need an extra bit to hold the sign. bool LHSUnsigned = isa(LHSI); - if (LHSUnsigned) - ++InputSize; if (I.isEquality()) { FCmpInst::Predicate P = I.getPredicate(); @@ -3761,13 +3753,30 @@ // equality compares as integer? } - // Comparisons with zero are a special case where we know we won't lose - // information. - bool IsCmpZero = RHS.isPosZero(); + // Check to see that the input is converted from an integer type that is small + // enough that preserves all bits. TODO: check here for "known" sign bits. + // This would allow us to handle (fptosi (x >>s 62) to float) if x is i64 f.e. + unsigned InputSize = IntTy->getScalarSizeInBits(); - // If the conversion would lose info, don't hack on this. - if ((int)InputSize > MantissaWidth && !IsCmpZero) - return nullptr; + // Following test does NOT adjust InputSize downwards for signed inputs, + // because the most negative value still requires all the mantissa bits + // to distinguish it from one less than that value. + if ((int)InputSize > MantissaWidth) { + // Conversion would lose accuracy. Check if loss can impact comparison. + int Exp = ilogb(RHS); + if (Exp == APFloat::IEK_Inf) { + int MaxExponent = ilogb(APFloat::getLargest(RHS.getSemantics())); + if (MaxExponent < (int)InputSize - !LHSUnsigned) + // Conversion could create infinity. + return nullptr; + } else { + // Note that if RHS is zero or NaN, then Exp is negative + // and first condition is trivially false. + if (MantissaWidth <= Exp && Exp <= (int)InputSize - !LHSUnsigned) + // Conversion could affect comparison. + return nullptr; + } + } // Otherwise, we can potentially simplify the comparison. We know that it // will always come through as an integer value and we know the constant is Index: test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll =================================================================== --- test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll +++ test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll @@ -10,8 +10,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_oeq_int_n0_uitofp( -; CHECK: uitofp -; CHECK: fcmp oeq +; CHECK-NEXT: icmp eq i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_oeq_int_n0_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp oeq float %f, -0.0 @@ -28,8 +28,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_oeq_int_n0_sitofp( -; CHECK: sitofp -; CHECK: fcmp oeq +; CHECK-NEXT: icmp eq i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_oeq_int_n0_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp oeq float %f, -0.0 @@ -46,8 +46,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_one_int_n0_uitofp( -; CHECK: uitofp -; CHECK: fcmp one +; CHECK-NEXT: icmp ne i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_one_int_n0_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp one float %f, -0.0 @@ -64,8 +64,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_one_int_n0_sitofp( -; CHECK: sitofp -; CHECK: fcmp one +; CHECK-NEXT: icmp ne i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_one_int_n0_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp one float %f, -0.0 @@ -82,8 +82,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_ueq_int_n0_uitofp( -; CHECK: uitofp -; CHECK: fcmp ueq +; CHECK-NEXT: icmp eq i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_ueq_int_n0_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp ueq float %f, -0.0 @@ -100,8 +100,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_ueq_int_n0_sitofp( -; CHECK: sitofp -; CHECK: fcmp ueq +; CHECK-NEXT: icmp eq i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_ueq_int_n0_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp ueq float %f, -0.0 @@ -118,8 +118,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_une_int_n0_uitofp( -; CHECK: uitofp -; CHECK: fcmp une +; CHECK-NEXT: icmp ne i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_une_int_n0_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp une float %f, -0.0 @@ -136,8 +136,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_une_int_n0_sitofp( -; CHECK: sitofp -; CHECK: fcmp une +; CHECK-NEXT: icmp ne i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_une_int_n0_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp une float %f, -0.0 @@ -154,8 +154,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_ogt_int_n0_uitofp( -; CHECK: uitofp -; CHECK: fcmp ogt +; CHECK: icmp ne i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_ogt_int_n0_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp ogt float %f, -0.0 @@ -172,8 +172,8 @@ } ; CHECK-LABEL: @i32_cast_cmp_ogt_int_n0_sitofp( -; CHECK: sitofp -; CHECK: fcmp ogt +; CHECK: icmp sgt i32 %i, 0 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_ogt_int_n0_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp ogt float %f, -0.0 @@ -261,12 +261,13 @@ ret i1 %cmp } -; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24max_uitofp( -; CHECK: uitofp -; CHECK: fcmp oeq +; Since 0xFFFFFF fits in a float, and one less and +; one more than it also fits without rounding, the +; test can be optimized to an integer compare. -; XCHECK: icmp eq i32 %i, 16777215 -; XCHECK-NEXT: ret +; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24max_uitofp( +; CHECK: icmp eq i32 %i, 16777215 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_oeq_int_i24max_uitofp(i32 %i) { %f = uitofp i32 %i to float %cmp = fcmp oeq float %f, 0x416FFFFFE0000000 @@ -274,17 +275,18 @@ } ; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24max_sitofp( -; CHECK: sitofp -; CHECK: fcmp oeq - -; XCHECK: icmp eq i32 %i, 16777215 -; XCHECK-NEXT: ret +; CHECK: icmp eq i32 %i, 16777215 +; CHECK-NEXT: ret define i1 @i32_cast_cmp_oeq_int_i24max_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp oeq float %f, 0x416FFFFFE0000000 ret i1 %cmp } +; Though 0x1000000 fits in a float, one more than it +; would round to it too, hence a single integer comparison +; does not suffice. + ; CHECK-LABEL: @i32_cast_cmp_oeq_int_i24maxp1_uitofp( ; CHECK: uitofp ; CHECK: fcmp oeq @@ -319,10 +321,18 @@ ret i1 %cmp } +; 32-bit unsigned integer cannot possibly round up to 1<<33 +; CHECK-LABEL: @i32_cast_cmp_oeq_int_big_uitofp( +; CHECK-NEXT: ret i1 false +define i1 @i32_cast_cmp_oeq_int_big_uitofp(i32 %i) { + %f = uitofp i32 %i to float + %cmp = fcmp oeq float %f, 0x4200000000000000 + ret i1 %cmp +} + +; 32-bit signed integer cannot possibly round up to 1<<32 ; CHECK-LABEL: @i32_cast_cmp_oeq_int_i32umax_sitofp( -; CHECK: sitofp -; CHECK: fcmp oeq -; CHECK-NEXT: ret +; CHECK-NEXT: ret i1 false define i1 @i32_cast_cmp_oeq_int_i32umax_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp oeq float %f, 0x41F0000000000000 @@ -379,10 +389,9 @@ ret i1 %cmp } +; 32-bit signed integer cannot possibly round to -1<<32 ; CHECK-LABEL: @i32_cast_cmp_oeq_int_negi32umax_sitofp( -; CHECK: sitofp -; CHECK: fcmp oeq -; CHECK-NEXT: ret +; CHECK-NEXT: ret i1 false define i1 @i32_cast_cmp_oeq_int_negi32umax_sitofp(i32 %i) { %f = sitofp i32 %i to float %cmp = fcmp oeq float %f, 0xC1F0000000000000 @@ -452,3 +461,30 @@ %cmp = fcmp une float %f, 0.5 ret i1 %cmp } + +; CHECK-LABEL: @i32_cast_cmp_oeq_int_inf_uitofp( +; CHECK-NEXT: ret i1 false +define i1 @i32_cast_cmp_oeq_int_inf_uitofp(i32 %i) { + %f = uitofp i32 %i to float + %cmp = fcmp oeq float %f, 0x7FF0000000000000 + ret i1 %cmp +} + +; CHECK-LABEL: @i32_cast_cmp_oeq_int_inf_sitofp( +; CHECK-NEXT: ret i1 false +define i1 @i32_cast_cmp_oeq_int_inf_sitofp(i32 %i) { + %f = sitofp i32 %i to float + %cmp = fcmp oeq float %f, 0x7FF0000000000000 + ret i1 %cmp +} + +; An i128 could round to an IEEE single-precision infinity. +; CHECK-LABEL: @i128_cast_cmp_oeq_int_inf_uitofp( +; CHECK: uitofp +; CHECK: fcmp oeq +; CHECK-NEXT: ret +define i1 @i128_cast_cmp_oeq_int_inf_uitofp(i128 %i) { + %f = uitofp i128 %i to float + %cmp = fcmp oeq float %f, 0x7FF0000000000000 + ret i1 %cmp +}