diff --git a/llvm/include/llvm/Analysis/ValueLattice.h b/llvm/include/llvm/Analysis/ValueLattice.h --- a/llvm/include/llvm/Analysis/ValueLattice.h +++ b/llvm/include/llvm/Analysis/ValueLattice.h @@ -190,7 +190,8 @@ /// contains a single element. In that case, it can be replaced by a constant. bool isConstantRange(bool UndefAllowed = true) const { return Tag == constantrange || (Tag == constantrange_including_undef && - (UndefAllowed || Range.isSingleElement())); + (UndefAllowed || Range.isSingleElement() || + Range.isSingleElementFP())); } bool isOverdefined() const { return Tag == overdefined; } @@ -254,6 +255,8 @@ if (ConstantInt *CI = dyn_cast(V)) return markConstantRange(ConstantRange(CI->getValue()), MayIncludeUndef); + if (ConstantFP *CFP = dyn_cast(V)) + return markConstantRange(ConstantRange(CFP->getValueAPF()), MayIncludeUndef); assert(isUnknown() || isUndef()); Tag = constant; @@ -266,6 +269,8 @@ if (ConstantInt *CI = dyn_cast(V)) return markConstantRange( ConstantRange(CI->getValue() + 1, CI->getValue())); + if (ConstantFP *CFP = dyn_cast(V)) + return markConstantRange(ConstantRange(CFP->getValueAPF()).inverse()); if (isa(V)) return false; @@ -401,12 +406,23 @@ const auto &CR = getConstantRange(); const auto &OtherCR = Other.getConstantRange(); - if (ConstantRange::makeSatisfyingICmpRegion(Pred, OtherCR).contains(CR)) - return ConstantInt::getTrue(Ty); - if (ConstantRange::makeSatisfyingICmpRegion( - CmpInst::getInversePredicate(Pred), OtherCR) - .contains(CR)) - return ConstantInt::getFalse(Ty); + if (CR.getIsFloat()) { + assert(OtherCR.getIsFloat()); + if (ConstantRange::makeSatisfyingFCmpRegion(Pred, OtherCR).contains(CR)) + return ConstantInt::getTrue(Ty); + if (ConstantRange::makeSatisfyingFCmpRegion( + CmpInst::getInversePredicate(Pred), OtherCR) + .contains(CR)) + return ConstantInt::getFalse(Ty); + } else { + assert(!OtherCR.getIsFloat()); + if (ConstantRange::makeSatisfyingICmpRegion(Pred, OtherCR).contains(CR)) + return ConstantInt::getTrue(Ty); + if (ConstantRange::makeSatisfyingICmpRegion( + CmpInst::getInversePredicate(Pred), OtherCR) + .contains(CR)) + return ConstantInt::getFalse(Ty); + } return nullptr; } diff --git a/llvm/lib/Analysis/LazyValueInfo.cpp b/llvm/lib/Analysis/LazyValueInfo.cpp --- a/llvm/lib/Analysis/LazyValueInfo.cpp +++ b/llvm/lib/Analysis/LazyValueInfo.cpp @@ -69,8 +69,9 @@ /// reachable code. static bool hasSingleValue(const ValueLatticeElement &Val) { if (Val.isConstantRange() && - Val.getConstantRange().isSingleElement()) - // Integer constants are single element ranges + (Val.getConstantRange().isSingleElement() || + Val.getConstantRange().isSingleElementFP())) + // Integer and FP constants are single element ranges return true; if (Val.isConstant()) // Non integer constants @@ -640,13 +641,13 @@ Res = ValueLatticeElement::getNot(ConstantPointerNull::get(PT)); return true; } + if (BinaryOperator *BO = dyn_cast(BBI)) + return solveBlockValueBinaryOp(Res, BO, BB); + if (BBI->getType()->isIntegerTy()) { if (auto *CI = dyn_cast(BBI)) return solveBlockValueCast(Res, CI, BB); - if (BinaryOperator *BO = dyn_cast(BBI)) - return solveBlockValueBinaryOp(Res, BO, BB); - if (auto *EVI = dyn_cast(BBI)) return solveBlockValueExtractValue(Res, EVI, BB); @@ -1709,6 +1710,8 @@ const ConstantRange &CR = Result.getConstantRange(); if (const APInt *SingleVal = CR.getSingleElement()) return ConstantInt::get(V->getContext(), *SingleVal); + if (const APFloat *SingleVal = CR.getSingleElementFP()) + return ConstantFP::get(V->getContext(), *SingleVal); } return nullptr; } @@ -1747,6 +1750,8 @@ const ConstantRange &CR = Result.getConstantRange(); if (const APInt *SingleVal = CR.getSingleElement()) return ConstantInt::get(V->getContext(), *SingleVal); + if (const APFloat *SingleVal = CR.getSingleElementFP()) + return ConstantFP::get(V->getContext(), *SingleVal); } return nullptr; } @@ -1766,8 +1771,9 @@ return Result.getConstantRange(); // We represent ConstantInt constants as constant ranges but other kinds // of integer constants, i.e. ConstantExpr will be tagged as constants - assert(!(Result.isConstant() && isa(Result.getConstant())) && - "ConstantInt value must be represented as constantrange"); + assert(!(Result.isConstant() && isa(Result.getConstant()) && + isa(Result.getConstant()) ) && + "ConstantInt and ConstantFP values must be represented as constantrange"); return ConstantRange::getFull(Width); } @@ -1785,7 +1791,8 @@ if (Val.isConstantRange()) { ConstantInt *CI = dyn_cast(C); - if (!CI) return LazyValueInfo::Unknown; + ConstantFP *CFP = dyn_cast(C); + if (!CI && !CFP) return LazyValueInfo::Unknown; const ConstantRange &CR = Val.getConstantRange(); if (Pred == ICmpInst::ICMP_EQ) { @@ -1802,12 +1809,26 @@ return LazyValueInfo::False; } else { // Handle more complex predicates. - ConstantRange TrueValues = ConstantRange::makeExactICmpRegion( - (ICmpInst::Predicate)Pred, CI->getValue()); - if (TrueValues.contains(CR)) - return LazyValueInfo::True; - if (TrueValues.inverse().contains(CR)) - return LazyValueInfo::False; + if (CI) { + ConstantRange TrueValues = ConstantRange::makeExactICmpRegion( + (ICmpInst::Predicate)Pred, CI->getValue()); + if (TrueValues.contains(CR)) + return LazyValueInfo::True; + if (TrueValues.inverse().contains(CR)) + return LazyValueInfo::False; + } + // Handle floating point prdicates + if (CFP) { + ConstantRange TrueValues = ConstantRange::makeExactFCmpRegion( + (FCmpInst::Predicate)Pred, CFP->getValueAPF()); + if (TrueValues.contains(CR)) + return LazyValueInfo::True; + ConstantRange FalseValues = ConstantRange::makeExactFCmpRegion( + FCmpInst::getInversePredicate((FCmpInst::Predicate)Pred), + CFP->getValueAPF()); + if (FalseValues.contains(CR)) + return LazyValueInfo::False; + } } return LazyValueInfo::Unknown; } diff --git a/llvm/lib/Analysis/ValueLattice.cpp b/llvm/lib/Analysis/ValueLattice.cpp --- a/llvm/lib/Analysis/ValueLattice.cpp +++ b/llvm/lib/Analysis/ValueLattice.cpp @@ -20,14 +20,26 @@ if (Val.isNotConstant()) return OS << "notconstant<" << *Val.getNotConstant() << ">"; - if (Val.isConstantRangeIncludingUndef()) - return OS << "constantrange incl. undef <" - << Val.getConstantRange(true).getLower() << ", " - << Val.getConstantRange(true).getUpper() << ">"; + if (Val.isConstantRangeIncludingUndef()) { + const ConstantRange &CR = Val.getConstantRange(true); + if (CR.getIsFloat()) { + return OS << "constantrange-fp incl. undef <" << CR << ">"; + } else { + return OS << "constantrange incl. undef <" << CR.getLower() << ", " + << CR.getUpper() << ">"; + } + } + + if (Val.isConstantRange()) { + const ConstantRange &CR = Val.getConstantRange(true); + if (CR.getIsFloat()) { + return OS << "constantrange-fp<" << CR << ">"; + } else { + return OS << "constantrange<" << CR.getLower() << ", " + << CR.getUpper() << ">"; + } + } - if (Val.isConstantRange()) - return OS << "constantrange<" << Val.getConstantRange().getLower() << ", " - << Val.getConstantRange().getUpper() << ">"; return OS << "constant<" << *Val.getConstant() << ">"; } } // end namespace llvm diff --git a/llvm/lib/IR/ConstantRange.cpp b/llvm/lib/IR/ConstantRange.cpp --- a/llvm/lib/IR/ConstantRange.cpp +++ b/llvm/lib/IR/ConstantRange.cpp @@ -101,6 +101,7 @@ ConstantRange ConstantRange::makeAllowedFCmpRegion(CmpInst::Predicate Pred, const ConstantRange &CR) { +// dbgs() << "Make allowed FCmp region '" << CmpInst::getPredicateName(Pred) << "' " << CR << "\n"; assert(CR.isFloat); if (CR.isEmptySet()) return CR; @@ -1104,8 +1105,11 @@ case Instruction::Xor: return binaryXor(Other); case Instruction::FAdd: - if (isFloat) // We don't support vector types - return fadd(Other); + if (isFloat) { // We don't support vector types + auto ret = fadd(Other); +// dbgs() << "FADD: " << *this << " + " << Other << " = " << ret << "\n"; + return ret; + } // Fallthrough case Instruction::FSub: if (isFloat) // We don't support vector types diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp --- a/llvm/lib/Transforms/Scalar/SCCP.cpp +++ b/llvm/lib/Transforms/Scalar/SCCP.cpp @@ -81,7 +81,9 @@ // transition to ValueLatticeElement. bool isConstant(const ValueLatticeElement &LV) { return LV.isConstant() || - (LV.isConstantRange() && LV.getConstantRange().isSingleElement()); + (LV.isConstantRange() && + (LV.getConstantRange().isSingleElement() || + LV.getConstantRange().isSingleElementFP())); } // Helper to check if \p LV is either overdefined or a constant range with more @@ -90,7 +92,8 @@ // transition to ValueLatticeElement. bool isOverdefined(const ValueLatticeElement &LV) { return LV.isOverdefined() || - (LV.isConstantRange() && !LV.getConstantRange().isSingleElement()); + (LV.isConstantRange() && !LV.getConstantRange().isSingleElement() && + !LV.getConstantRange().isSingleElementFP()); } //===----------------------------------------------------------------------===// @@ -342,6 +345,8 @@ auto &CR = LV.getConstantRange(); if (CR.getSingleElement()) return ConstantInt::get(Ctx, *CR.getSingleElement()); + if (CR.getSingleElementFP()) + return ConstantFP::get(Ctx, *CR.getSingleElementFP()); } return nullptr; } @@ -814,6 +819,13 @@ ConstantRange Res = OpRange.castOp(I.getOpcode(), DL.getTypeSizeInBits(DestTy)); mergeInValue(LV, &I, ValueLatticeElement::getRange(Res)); + } else if (OpSt.isConstantRange() && I.getDestTy()->isFloatingPointTy()) { + auto &LV = getValueState(&I); + ConstantRange OpRange = OpSt.getConstantRange(); + Type *DestTy = I.getDestTy(); + ConstantRange Res = + OpRange.castOp(I.getOpcode(), DestTy->getFltSemantics()); + mergeInValue(LV, &I, ValueLatticeElement::getRange(Res)); } else if (!OpSt.isUnknownOrUndef()) markOverdefined(&I); } @@ -979,13 +991,16 @@ } } - // Only use ranges for binary operators on integers. - if (!I.getType()->isIntegerTy()) + auto IType = I.getType(); + // Only use ranges for binary operators on integers and floating point + if (!IType->isIntegerTy() && !IType->isFloatingPointTy()) return markOverdefined(&I); // Try to simplify to a constant range. - ConstantRange A = ConstantRange::getFull(I.getType()->getScalarSizeInBits()); - ConstantRange B = ConstantRange::getFull(I.getType()->getScalarSizeInBits()); + ConstantRange A = IType->isFloatingPointTy() ? + ConstantRange::getFull(IType->getFltSemantics()): + ConstantRange::getFull(IType->getScalarSizeInBits()); + ConstantRange B = A; if (V1State.isConstantRange()) A = V1State.getConstantRange(); if (V2State.isConstantRange()) @@ -1244,7 +1259,10 @@ } // Everything below relies on the condition being a comparison. - auto *Cmp = dyn_cast(PBranch->Condition); + // FIXME: This is restricted to integer comparisons. + // FP comaprisons introduce a rather large range first, + // ehich then doesn't get reduced. + auto *Cmp = dyn_cast(PBranch->Condition); if (!Cmp) { mergeInValue(ValueState[I], I, getValueState(CopyOf)); return; @@ -1276,20 +1294,24 @@ ValueLatticeElement &IV = ValueState[I]; ValueLatticeElement OriginalVal = getValueState(CopyOf); if (CondVal.isConstantRange() || OriginalVal.isConstantRange()) { - auto NewCR = - ConstantRange::getFull(DL.getTypeSizeInBits(CopyOf->getType())); + auto CoType = CopyOf->getType(); + auto NewCR = CoType->isFloatingPointTy() ? + ConstantRange::getFull(CoType->getFltSemantics()): + ConstantRange::getFull(DL.getTypeSizeInBits(CoType)); + + auto OriginalCR = OriginalVal.isConstantRange() + ? OriginalVal.getConstantRange() : NewCR; // Get the range imposed by the condition. - if (CondVal.isConstantRange()) - NewCR = ConstantRange::makeAllowedICmpRegion( - Pred, CondVal.getConstantRange()); + if (CondVal.isConstantRange()) { + ConstantRange CR = CondVal.getConstantRange(); + NewCR = CR.getIsFloat() ? + ConstantRange::makeAllowedFCmpRegion(Pred, CR): + ConstantRange::makeAllowedICmpRegion(Pred, CR); + } // Combine range info for the original value with the new range from the // condition. - auto OriginalCR = OriginalVal.isConstantRange() - ? OriginalVal.getConstantRange() - : ConstantRange::getFull( - DL.getTypeSizeInBits(CopyOf->getType())); NewCR = NewCR.intersectWith(OriginalCR); addAdditionalUser(CmpOp1, I); diff --git a/llvm/test/Transforms/CorrelatedValuePropagation/select.ll b/llvm/test/Transforms/CorrelatedValuePropagation/select.ll --- a/llvm/test/Transforms/CorrelatedValuePropagation/select.ll +++ b/llvm/test/Transforms/CorrelatedValuePropagation/select.ll @@ -206,7 +206,7 @@ ; CHECK-NEXT: [[MIN:%.*]] = select i1 [[UNKNOWN:%.*]], double 1.000000e+00, double 0.000000e+00 ; CHECK-NEXT: br label [[NEXT2:%.*]] ; CHECK: next2: -; CHECK-NEXT: [[RES:%.*]] = fcmp oeq double [[MIN]], 3.000000e+02 +; CHECK-NEXT: [[RES:%.*]] = fcmp oeq double [[MIN]], 5.000000e-01 ; CHECK-NEXT: ret i1 [[RES]] ; CHECK: exit: ; CHECK-NEXT: ret i1 true @@ -220,7 +220,7 @@ ;; TODO: This pointless branch shouldn't be neccessary br label %next2 next2: - %res = fcmp oeq double %min, 300.0 + %res = fcmp oeq double %min, 0.5 ret i1 %res exit: diff --git a/llvm/test/Transforms/SCCP/apint-load.ll b/llvm/test/Transforms/SCCP/apint-load.ll --- a/llvm/test/Transforms/SCCP/apint-load.ll +++ b/llvm/test/Transforms/SCCP/apint-load.ll @@ -4,7 +4,7 @@ ; RUN: opt < %s -ipsccp -S | not grep fdiv @X = constant i212 42 -@Y = constant [2 x { i212, float }] [ { i212, float } { i212 12, float 1.0 }, +@Y = constant [2 x { i212, float }] [ { i212, float } { i212 16, float 1.0 }, { i212, float } { i212 37, float 0x3FF3B2FEC0000000 } ] define i212 @test1() { %B = load i212, i212* @X @@ -27,7 +27,7 @@ { %A = call float @test2() %B = call i212 @test3() - %C = mul i212 %B, -1234567 + %C = mul i212 %B, -16 %D = sitofp i212 %C to float %E = fdiv float %A, %D ret float %E diff --git a/llvm/test/Transforms/SCCP/float-nan-simplification.ll b/llvm/test/Transforms/SCCP/float-nan-simplification.ll --- a/llvm/test/Transforms/SCCP/float-nan-simplification.ll +++ b/llvm/test/Transforms/SCCP/float-nan-simplification.ll @@ -2,10 +2,12 @@ ; RUN: opt -sccp -S %s | FileCheck %s ; When marking the edge from bb2 -> exit as executable first, %p will be NaN -; first and %v.1 will simplify to NaN. But when marking bb1 -> exit executable, -; %p will we overdefined and %v.1 will be simplified to 0.0. Make sure we go to -; overdefined, instead of crashing. -; TODO: Can we do better, i.e. choose the 'conservative' 0.0 initially? +; first and %v.1 will simplify to NaN. Note that this will be a positive NaN. +; Operations with two NaNs return the first one, so the returned value is +; positive NaN. But when marking bb1 -> exit executable, %p will we +; overdefined (full set) and %v.1 will be simplified to 0.0 or NaN. +; This will be combined with neg NaN, which is the returend. +; TODO: Can we do better, i.e. track pos and neg NaN separately? define float @test1(float %a, i1 %bc) { ; CHECK-LABEL: @test1( ; CHECK-NEXT: entry: @@ -17,8 +19,7 @@ ; CHECK: exit: ; CHECK-NEXT: [[P:%.*]] = phi float [ [[A:%.*]], [[BB1]] ], [ 0x7FF8000000000000, [[BB2]] ] ; CHECK-NEXT: [[V_1:%.*]] = fmul float [[P]], 0.000000e+00 -; CHECK-NEXT: [[V_2:%.*]] = fadd float [[V_1]], 0xFFF8000000000000 -; CHECK-NEXT: ret float [[V_2]] +; CHECK-NEXT: ret float 0x7FF8000000000000 ; entry: br i1 %bc, label %bb1, label %bb2 diff --git a/llvm/unittests/Analysis/ValueLatticeTest.cpp b/llvm/unittests/Analysis/ValueLatticeTest.cpp --- a/llvm/unittests/Analysis/ValueLatticeTest.cpp +++ b/llvm/unittests/Analysis/ValueLatticeTest.cpp @@ -30,14 +30,17 @@ auto *C1 = ConstantInt::get(I32Ty, 1); EXPECT_TRUE(ValueLatticeElement::get(C1).isConstantRange()); + EXPECT_TRUE(ValueLatticeElement::getNot(C1).isConstantRange()); EXPECT_TRUE( ValueLatticeElement::getRange({C1->getValue()}).isConstantRange()); EXPECT_TRUE(ValueLatticeElement::getOverdefined().isOverdefined()); auto FloatTy = Type::getFloatTy(Context); - auto *C2 = ConstantFP::get(FloatTy, 1.1); - EXPECT_TRUE(ValueLatticeElement::get(C2).isConstant()); - EXPECT_TRUE(ValueLatticeElement::getNot(C2).isNotConstant()); + auto *C2 = dyn_cast(ConstantFP::get(FloatTy, 1.1)); + EXPECT_TRUE(ValueLatticeElement::get(C2).isConstantRange()); + EXPECT_TRUE(ValueLatticeElement::getNot(C2).isConstantRange()); + EXPECT_TRUE( + ValueLatticeElement::getRange({C2->getValueAPF()}).isConstantRange()); } TEST_F(ValueLatticeTest, MarkConstantRange) { @@ -162,10 +165,12 @@ EXPECT_TRUE( LV1.mergeIn(ValueLatticeElement::get(ConstantFP::get(FloatTy, 2.2)))); EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_OEQ, I1Ty, LV2), nullptr); - EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_OGE, I1Ty, LV2), nullptr); + // [1.0, 2.2] is always >= 1.0 + EXPECT_TRUE(LV1.getCompare(CmpInst::FCMP_OGE, I1Ty, LV2)->isOneValue()); EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_OLE, I1Ty, LV2), nullptr); EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_ONE, I1Ty, LV2), nullptr); - EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_OLT, I1Ty, LV2), nullptr); + // [1.0, 2.2] is never < 1.0 + EXPECT_TRUE(LV1.getCompare(CmpInst::FCMP_OLT, I1Ty, LV2)->isZeroValue()); EXPECT_EQ(LV1.getCompare(CmpInst::FCMP_OGT, I1Ty, LV2), nullptr); }