diff --git a/lib/Transforms/Scalar/InstructionCombining.cpp b/lib/Transforms/Scalar/InstructionCombining.cpp index 743d8bb15f7..60b907e0da9 100644 --- a/lib/Transforms/Scalar/InstructionCombining.cpp +++ b/lib/Transforms/Scalar/InstructionCombining.cpp @@ -5317,7 +5317,8 @@ Instruction *InstCombiner::FoldFCmp_IntToFP_Cst(FCmpInst &I, unsigned InputSize = LHSI->getOperand(0)->getType()->getPrimitiveSizeInBits(); // If this is a uitofp instruction, we need an extra bit to hold the sign. - if (isa(LHSI)) + bool LHSUnsigned = isa(LHSI); + if (LHSUnsigned) ++InputSize; // If the conversion would lose info, don't hack on this. @@ -5333,17 +5334,29 @@ Instruction *InstCombiner::FoldFCmp_IntToFP_Cst(FCmpInst &I, switch (I.getPredicate()) { default: assert(0 && "Unexpected predicate!"); case FCmpInst::FCMP_UEQ: - case FCmpInst::FCMP_OEQ: Pred = ICmpInst::ICMP_EQ; break; + case FCmpInst::FCMP_OEQ: + Pred = ICmpInst::ICMP_EQ; + break; case FCmpInst::FCMP_UGT: - case FCmpInst::FCMP_OGT: Pred = ICmpInst::ICMP_SGT; break; + case FCmpInst::FCMP_OGT: + Pred = LHSUnsigned ? ICmpInst::ICMP_UGT : ICmpInst::ICMP_SGT; + break; case FCmpInst::FCMP_UGE: - case FCmpInst::FCMP_OGE: Pred = ICmpInst::ICMP_SGE; break; + case FCmpInst::FCMP_OGE: + Pred = LHSUnsigned ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_SGE; + break; case FCmpInst::FCMP_ULT: - case FCmpInst::FCMP_OLT: Pred = ICmpInst::ICMP_SLT; break; + case FCmpInst::FCMP_OLT: + Pred = LHSUnsigned ? ICmpInst::ICMP_ULT : ICmpInst::ICMP_SLT; + break; case FCmpInst::FCMP_ULE: - case FCmpInst::FCMP_OLE: Pred = ICmpInst::ICMP_SLE; break; + case FCmpInst::FCMP_OLE: + Pred = LHSUnsigned ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_SLE; + break; case FCmpInst::FCMP_UNE: - case FCmpInst::FCMP_ONE: Pred = ICmpInst::ICMP_NE; break; + case FCmpInst::FCMP_ONE: + Pred = ICmpInst::ICMP_NE; + break; case FCmpInst::FCMP_ORD: return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); case FCmpInst::FCMP_UNO: @@ -5358,63 +5371,105 @@ Instruction *InstCombiner::FoldFCmp_IntToFP_Cst(FCmpInst &I, // comparing an i8 to 300.0. unsigned IntWidth = IntTy->getPrimitiveSizeInBits(); - // If the RHS value is > SignedMax, fold the comparison. This handles +INF - // and large values. - APFloat SMax(RHS.getSemantics(), APFloat::fcZero, false); - SMax.convertFromAPInt(APInt::getSignedMaxValue(IntWidth), true, - APFloat::rmNearestTiesToEven); - if (SMax.compare(RHS) == APFloat::cmpLessThan) { // smax < 13123.0 - if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SLT || - Pred == ICmpInst::ICMP_SLE) - return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); - return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + if (!LHSUnsigned) { + // If the RHS value is > SignedMax, fold the comparison. This handles +INF + // and large values. + APFloat SMax(RHS.getSemantics(), APFloat::fcZero, false); + SMax.convertFromAPInt(APInt::getSignedMaxValue(IntWidth), true, + APFloat::rmNearestTiesToEven); + if (SMax.compare(RHS) == APFloat::cmpLessThan) { // smax < 13123.0 + if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SLT || + Pred == ICmpInst::ICMP_SLE) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + } + } else { + // If the RHS value is > UnsignedMax, fold the comparison. This handles + // +INF and large values. + APFloat UMax(RHS.getSemantics(), APFloat::fcZero, false); + UMax.convertFromAPInt(APInt::getMaxValue(IntWidth), false, + APFloat::rmNearestTiesToEven); + if (UMax.compare(RHS) == APFloat::cmpLessThan) { // umax < 13123.0 + if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_ULT || + Pred == ICmpInst::ICMP_ULE) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + } } - // See if the RHS value is < SignedMin. - APFloat SMin(RHS.getSemantics(), APFloat::fcZero, false); - SMin.convertFromAPInt(APInt::getSignedMinValue(IntWidth), true, - APFloat::rmNearestTiesToEven); - if (SMin.compare(RHS) == APFloat::cmpGreaterThan) { // smin > 12312.0 - if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SGT || - Pred == ICmpInst::ICMP_SGE) - return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); - return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + if (!LHSUnsigned) { + // See if the RHS value is < SignedMin. + APFloat SMin(RHS.getSemantics(), APFloat::fcZero, false); + SMin.convertFromAPInt(APInt::getSignedMinValue(IntWidth), true, + APFloat::rmNearestTiesToEven); + if (SMin.compare(RHS) == APFloat::cmpGreaterThan) { // smin > 12312.0 + if (Pred == ICmpInst::ICMP_NE || Pred == ICmpInst::ICMP_SGT || + Pred == ICmpInst::ICMP_SGE) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + } } - // Okay, now we know that the FP constant fits in the range [SMIN, SMAX] but - // it may still be fractional. See if it is fractional by casting the FP - // value to the integer value and back, checking for equality. Don't do this - // for zero, because -0.0 is not fractional. + // Okay, now we know that the FP constant fits in the range [SMIN, SMAX] or + // [0, UMAX], but it may still be fractional. See if it is fractional by + // casting the FP value to the integer value and back, checking for equality. + // Don't do this for zero, because -0.0 is not fractional. Constant *RHSInt = ConstantExpr::getFPToSI(RHSC, IntTy); if (!RHS.isZero() && ConstantExpr::getSIToFP(RHSInt, RHSC->getType()) != RHSC) { - // If we had a comparison against a fractional value, we have to adjust - // the compare predicate and sometimes the value. RHSC is rounded towards - // zero at this point. + // If we had a comparison against a fractional value, we have to adjust the + // compare predicate and sometimes the value. RHSC is rounded towards zero + // at this point. switch (Pred) { default: assert(0 && "Unexpected integer comparison!"); case ICmpInst::ICMP_NE: // (float)int != 4.4 --> true return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); case ICmpInst::ICMP_EQ: // (float)int == 4.4 --> false return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + case ICmpInst::ICMP_ULE: + // (float)int <= 4.4 --> int <= 4 + // (float)int <= -4.4 --> false + if (RHS.isNegative()) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + break; case ICmpInst::ICMP_SLE: // (float)int <= 4.4 --> int <= 4 // (float)int <= -4.4 --> int < -4 if (RHS.isNegative()) Pred = ICmpInst::ICMP_SLT; break; + case ICmpInst::ICMP_ULT: + // (float)int < -4.4 --> false + // (float)int < 4.4 --> int <= 4 + if (RHS.isNegative()) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 0)); + Pred = ICmpInst::ICMP_ULE; + break; case ICmpInst::ICMP_SLT: // (float)int < -4.4 --> int < -4 // (float)int < 4.4 --> int <= 4 if (!RHS.isNegative()) Pred = ICmpInst::ICMP_SLE; break; + case ICmpInst::ICMP_UGT: + // (float)int > 4.4 --> int > 4 + // (float)int > -4.4 --> true + if (RHS.isNegative()) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); + break; case ICmpInst::ICMP_SGT: // (float)int > 4.4 --> int > 4 // (float)int > -4.4 --> int >= -4 if (RHS.isNegative()) Pred = ICmpInst::ICMP_SGE; break; + case ICmpInst::ICMP_UGE: + // (float)int >= -4.4 --> true + // (float)int >= 4.4 --> int > 4 + if (!RHS.isNegative()) + return ReplaceInstUsesWith(I, ConstantInt::get(Type::Int1Ty, 1)); + Pred = ICmpInst::ICMP_UGT; + break; case ICmpInst::ICMP_SGE: // (float)int >= -4.4 --> int >= -4 // (float)int >= 4.4 --> int > 4 diff --git a/test/Transforms/InstCombine/2008-11-08-FCmp.ll b/test/Transforms/InstCombine/2008-11-08-FCmp.ll new file mode 100644 index 00000000000..c088f3166fa --- /dev/null +++ b/test/Transforms/InstCombine/2008-11-08-FCmp.ll @@ -0,0 +1,46 @@ +; RUN: llvm-as < %s | opt -instcombine | llvm-dis > %t +; RUN: grep {icmp eq} %t +; RUN: grep {ret i1 false} %t | count 2 +; RUN: grep {ret i1 true} %t | count 2 +; RUN: grep {icmp ne} %t +; RUN: not grep {icmp slt} %t +; PR3021 + +; When inst combining an FCMP with the LHS coming from a uitofp instruction, we +; can't lower it to signed ICMP instructions. + +define i1 @test1(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp ole double %1, 0.000000e+00 + ret i1 %2 +} + +define i1 @test2(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp olt double %1, 0.000000e+00 + ret i1 %2 +} + +define i1 @test3(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp oge double %1, 0.000000e+00 + ret i1 %2 +} + +define i1 @test4(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp ogt double %1, 0.000000e+00 + ret i1 %2 +} + +define i1 @test5(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp ogt double %1, -4.400000e+00 + ret i1 %2 +} + +define i1 @test6(i32 %val) { + %1 = uitofp i32 %val to double + %2 = fcmp olt double %1, -4.400000e+00 + ret i1 %2 +}