diff --git a/lib/Transforms/InstCombine/InstCombineCompares.cpp b/lib/Transforms/InstCombine/InstCombineCompares.cpp index b3366bb9888..f1a66816c4c 100644 --- a/lib/Transforms/InstCombine/InstCombineCompares.cpp +++ b/lib/Transforms/InstCombine/InstCombineCompares.cpp @@ -3734,15 +3734,7 @@ Instruction *InstCombiner::FoldFCmp_IntToFP_Cst(FCmpInst &I, 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(); @@ -3769,13 +3761,30 @@ Instruction *InstCombiner::FoldFCmp_IntToFP_Cst(FCmpInst &I, // 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 diff --git a/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll b/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll index 551d0efce5e..2e87a7d7802 100644 --- a/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll +++ b/test/Transforms/InstCombine/cast-int-fcmp-eq-0.ll @@ -10,8 +10,8 @@ define i1 @i32_cast_cmp_oeq_int_0_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_oeq_int_0_sitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_one_int_0_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_one_int_0_sitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_ueq_int_0_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_ueq_int_0_sitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_une_int_0_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_une_int_0_sitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_ogt_int_0_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_ogt_int_0_sitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_oeq_int_0_uitofp_ppcf128(i32 %i) { 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 @@ define i1 @i32_cast_cmp_oeq_int_i24max_uitofp(i32 %i) { } ; 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 @@ define i1 @i32_cast_cmp_oeq_int_i32umax_uitofp(i32 %i) { 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 @@ define i1 @i32_cast_cmp_oeq_int_negi32umax_uitofp(i32 %i) { 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 @@ define i1 @i32_cast_cmp_une_half_sitofp(i32 %i) { %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 +}