Index: llvm/include/llvm/Analysis/ValueTracking.h =================================================================== --- llvm/include/llvm/Analysis/ValueTracking.h +++ llvm/include/llvm/Analysis/ValueTracking.h @@ -346,10 +346,14 @@ SignBit = false; } + /// Return true if the sign bit must be 0, ignoring the sign of nans. + bool signBitIsZeroOrNaN() const { + return isKnownNever(fcNegative); + } + /// Assume the sign bit is zero. - void signBitIsZero() { - KnownFPClasses = (KnownFPClasses & fcPositive) | - (KnownFPClasses & fcNan); + void signBitMustBeZero() { + KnownFPClasses &= (fcPositive | fcNan); SignBit = false; } Index: llvm/lib/Analysis/ValueTracking.cpp =================================================================== --- llvm/lib/Analysis/ValueTracking.cpp +++ llvm/lib/Analysis/ValueTracking.cpp @@ -4474,7 +4474,7 @@ Known.knownNot(fcSubnormal); if (IID == Intrinsic::experimental_constrained_uitofp) - Known.signBitIsZero(); + Known.signBitMustBeZero(); // TODO: Copy inf handling from instructions break; @@ -4567,8 +4567,17 @@ break; } case Instruction::FDiv: { + // X / X is always exactly 1.0 or a NaN. + if (Op->getOperand(0) == Op->getOperand(1)) { + // TODO: Could filter out snan if we inspect the operand + Known.KnownFPClasses = fcNan | fcPosNormal; + break; + } + const bool WantNan = (InterestedClasses & fcNan) != fcNone; - if (!WantNan) + const bool WantNegative = + (InterestedClasses & KnownFPClass::OrderedLessThanZeroMask) != fcNone; + if (!WantNan && !WantNegative) break; // TODO: FRem @@ -4578,19 +4587,20 @@ fcNan | fcInf | fcZero | fcSubnormal, KnownRHS, Depth + 1, Q, TLI); - bool KnowSomethingUseful = KnownRHS.isKnownNeverNaN() || - KnownRHS.isKnownNeverInfinity() || - KnownRHS.isKnownNeverZero(); + bool KnowSomethingUseful = + KnownRHS.isKnownNeverNaN() || KnownRHS.isKnownNeverInfinity() || + KnownRHS.isKnownNeverZero() || KnownRHS.signBitIsZeroOrNaN(); if (KnowSomethingUseful) { computeKnownFPClass(Op->getOperand(0), DemandedElts, - fcNan | fcInf | fcZero, KnownLHS, Depth + 1, Q, TLI); + fcNan | fcInf | fcZero | + KnownFPClass::OrderedLessThanZeroMask, + KnownLHS, Depth + 1, Q, TLI); } const Function *F = cast(Op)->getFunction(); // Only 0/0, Inf/Inf, Inf REM x and x REM 0 produce NaN. - // TODO: Track sign bit. if (KnownLHS.isKnownNeverNaN() && KnownRHS.isKnownNeverNaN() && (KnownLHS.isKnownNeverInfinity() || KnownRHS.isKnownNeverInfinity()) && (KnownLHS.isKnownNeverLogicalZero(*F, Op->getType()) || @@ -4598,6 +4608,10 @@ Known.knownNot(fcNan); } + // X / -0.0 is -Inf (or NaN). + if (KnownLHS.isKnownNever(fcNegative) && KnownRHS.isKnownNever(fcNegative)) + Known.knownNot(fcNegative); + break; } case Instruction::FPExt: { @@ -4635,7 +4649,7 @@ // sitofp and uitofp turn into +0.0 for zero. Known.knownNot(fcNegZero); if (Op->getOpcode() == Instruction::UIToFP) - Known.signBitIsZero(); + Known.signBitMustBeZero(); if (InterestedClasses & fcInf) { // Get width of largest magnitude integer (remove a bit if signed). Index: llvm/test/Transforms/Attributor/nofpclass-fdiv.ll =================================================================== --- llvm/test/Transforms/Attributor/nofpclass-fdiv.ll +++ llvm/test/Transforms/Attributor/nofpclass-fdiv.ll @@ -356,7 +356,7 @@ } define float @ret_fdiv_same_operands(float %arg) #0 { -; CHECK-LABEL: define float @ret_fdiv_same_operands +; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands ; CHECK-SAME: (float [[ARG:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]] ; CHECK-NEXT: ret float [[FDIV]] @@ -366,7 +366,7 @@ } define float @ret_fdiv_same_operands_nosnan(float nofpclass(snan) %arg) #0 { -; CHECK-LABEL: define float @ret_fdiv_same_operands_nosnan +; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nosnan ; CHECK-SAME: (float nofpclass(snan) [[ARG:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]] ; CHECK-NEXT: ret float [[FDIV]] @@ -376,7 +376,7 @@ } define float @ret_fdiv_same_operands_noqnan(float nofpclass(qnan) %arg) #0 { -; CHECK-LABEL: define float @ret_fdiv_same_operands_noqnan +; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_noqnan ; CHECK-SAME: (float nofpclass(qnan) [[ARG:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]] ; CHECK-NEXT: ret float [[FDIV]] @@ -386,7 +386,7 @@ } define float @ret_fdiv_same_operands_nonan(float nofpclass(nan) %arg) #0 { -; CHECK-LABEL: define float @ret_fdiv_same_operands_nonan +; CHECK-LABEL: define nofpclass(inf zero sub nnorm) float @ret_fdiv_same_operands_nonan ; CHECK-SAME: (float nofpclass(nan) [[ARG:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG]], [[ARG]] ; CHECK-NEXT: ret float [[FDIV]] @@ -436,7 +436,7 @@ } define float @ret_fdiv_no_neg_nzero(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm nzero) %arg1) #0 { -; CHECK-LABEL: define float @ret_fdiv_no_neg_nzero +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fdiv_no_neg_nzero ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf nzero nsub nnorm) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FDIV]] @@ -456,7 +456,7 @@ } define float @ret_fdiv_no_neg_no_zero_rhs(float nofpclass(ninf nsub nnorm nzero) %arg0, float nofpclass(ninf nsub nnorm zero) %arg1) #0 { -; CHECK-LABEL: define float @ret_fdiv_no_neg_no_zero_rhs +; CHECK-LABEL: define nofpclass(ninf nzero nsub nnorm) float @ret_fdiv_no_neg_no_zero_rhs ; CHECK-SAME: (float nofpclass(ninf nzero nsub nnorm) [[ARG0:%.*]], float nofpclass(ninf zero nsub nnorm) [[ARG1:%.*]]) #[[ATTR0]] { ; CHECK-NEXT: [[FDIV:%.*]] = fdiv float [[ARG0]], [[ARG1]] ; CHECK-NEXT: ret float [[FDIV]]