aboutsummaryrefslogtreecommitdiff
path: root/llvm/lib/Analysis
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/lib/Analysis')
-rwxr-xr-xllvm/lib/Analysis/ConstantFolding.cpp9
-rw-r--r--llvm/lib/Analysis/HeatUtils.cpp62
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp182
-rw-r--r--llvm/lib/Analysis/Loads.cpp24
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp4
5 files changed, 193 insertions, 88 deletions
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index d52b073..b744537 100755
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -1482,6 +1482,15 @@ Constant *llvm::ConstantFoldFPInstOperands(unsigned Opcode, Constant *LHS,
Constant *llvm::ConstantFoldCastOperand(unsigned Opcode, Constant *C,
Type *DestTy, const DataLayout &DL) {
assert(Instruction::isCast(Opcode));
+
+ if (auto *CE = dyn_cast<ConstantExpr>(C))
+ if (CE->isCast())
+ if (unsigned NewOp = CastInst::isEliminableCastPair(
+ Instruction::CastOps(CE->getOpcode()),
+ Instruction::CastOps(Opcode), CE->getOperand(0)->getType(),
+ C->getType(), DestTy, &DL))
+ return ConstantFoldCastOperand(NewOp, CE->getOperand(0), DestTy, DL);
+
switch (Opcode) {
default:
llvm_unreachable("Missing case");
diff --git a/llvm/lib/Analysis/HeatUtils.cpp b/llvm/lib/Analysis/HeatUtils.cpp
index b6a0d58..a1cc707 100644
--- a/llvm/lib/Analysis/HeatUtils.cpp
+++ b/llvm/lib/Analysis/HeatUtils.cpp
@@ -17,10 +17,10 @@
#include <cmath>
-namespace llvm {
+using namespace llvm;
-static const unsigned heatSize = 100;
-static const char heatPalette[heatSize][8] = {
+static constexpr unsigned HeatSize = 100;
+static constexpr char HeatPalette[HeatSize][8] = {
"#3d50c3", "#4055c8", "#4358cb", "#465ecf", "#4961d2", "#4c66d6", "#4f69d9",
"#536edd", "#5572df", "#5977e3", "#5b7ae5", "#5f7fe8", "#6282ea", "#6687ed",
"#6a8bef", "#6c8ff1", "#7093f3", "#7396f5", "#779af7", "#7a9df8", "#7ea1fa",
@@ -37,43 +37,37 @@ static const char heatPalette[heatSize][8] = {
"#d24b40", "#d0473d", "#cc403a", "#ca3b37", "#c53334", "#c32e31", "#be242e",
"#bb1b2c", "#b70d28"};
-uint64_t
-getNumOfCalls(Function &callerFunction, Function &calledFunction) {
- uint64_t counter = 0;
- for (User *U : calledFunction.users()) {
- if (auto CI = dyn_cast<CallInst>(U)) {
- if (CI->getCaller() == (&callerFunction)) {
- counter += 1;
- }
- }
- }
- return counter;
+uint64_t llvm::getNumOfCalls(const Function &CallerFunction,
+ const Function &CalledFunction) {
+ uint64_t Counter = 0;
+ for (const User *U : CalledFunction.users())
+ if (auto CI = dyn_cast<CallInst>(U))
+ Counter += CI->getCaller() == &CallerFunction;
+ return Counter;
}
-uint64_t getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI) {
- uint64_t maxFreq = 0;
+uint64_t llvm::getMaxFreq(const Function &F, const BlockFrequencyInfo *BFI) {
+ uint64_t MaxFreq = 0;
for (const BasicBlock &BB : F) {
- uint64_t freqVal = BFI->getBlockFreq(&BB).getFrequency();
- if (freqVal >= maxFreq)
- maxFreq = freqVal;
+ uint64_t FreqVal = BFI->getBlockFreq(&BB).getFrequency();
+ if (FreqVal >= MaxFreq)
+ MaxFreq = FreqVal;
}
- return maxFreq;
+ return MaxFreq;
}
-std::string getHeatColor(uint64_t freq, uint64_t maxFreq) {
- if (freq > maxFreq)
- freq = maxFreq;
- double percent = (freq > 0) ? log2(double(freq)) / log2(maxFreq) : 0;
- return getHeatColor(percent);
+std::string llvm::getHeatColor(uint64_t Freq, uint64_t MaxFreq) {
+ if (Freq > MaxFreq)
+ Freq = MaxFreq;
+ double Percent = (Freq > 0) ? log2(double(Freq)) / log2(MaxFreq) : 0;
+ return getHeatColor(Percent);
}
-std::string getHeatColor(double percent) {
- if (percent > 1.0)
- percent = 1.0;
- if (percent < 0.0)
- percent = 0.0;
- unsigned colorId = unsigned(round(percent * (heatSize - 1.0)));
- return heatPalette[colorId];
+std::string llvm::getHeatColor(double Percent) {
+ if (Percent > 1.0)
+ Percent = 1.0;
+ if (Percent < 0.0)
+ Percent = 0.0;
+ unsigned ColorID = unsigned(round(Percent * (HeatSize - 1.0)));
+ return HeatPalette[ColorID];
}
-
-} // namespace llvm
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index 0d978d4..d1977f0 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -5425,15 +5425,8 @@ static Value *simplifyCastInst(unsigned CastOpc, Value *Op, Type *Ty,
if (Src->getType() == Ty) {
auto FirstOp = CI->getOpcode();
auto SecondOp = static_cast<Instruction::CastOps>(CastOpc);
- Type *SrcIntPtrTy =
- SrcTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(SrcTy) : nullptr;
- Type *MidIntPtrTy =
- MidTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(MidTy) : nullptr;
- Type *DstIntPtrTy =
- DstTy->isPtrOrPtrVectorTy() ? Q.DL.getIntPtrType(DstTy) : nullptr;
if (CastInst::isEliminableCastPair(FirstOp, SecondOp, SrcTy, MidTy, DstTy,
- SrcIntPtrTy, MidIntPtrTy,
- DstIntPtrTy) == Instruction::BitCast)
+ &Q.DL) == Instruction::BitCast)
return Src;
}
}
@@ -6473,7 +6466,8 @@ static Value *foldMinMaxSharedOp(Intrinsic::ID IID, Value *Op0, Value *Op1) {
static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
Value *Op1) {
assert((IID == Intrinsic::maxnum || IID == Intrinsic::minnum ||
- IID == Intrinsic::maximum || IID == Intrinsic::minimum) &&
+ IID == Intrinsic::maximum || IID == Intrinsic::minimum ||
+ IID == Intrinsic::maximumnum || IID == Intrinsic::minimumnum) &&
"Unsupported intrinsic");
auto *M0 = dyn_cast<IntrinsicInst>(Op0);
@@ -6512,6 +6506,82 @@ static Value *foldMinimumMaximumSharedOp(Intrinsic::ID IID, Value *Op0,
return nullptr;
}
+enum class MinMaxOptResult {
+ CannotOptimize = 0,
+ UseNewConstVal = 1,
+ UseOtherVal = 2,
+ // For undef/poison, we can choose to either propgate undef/poison or
+ // use the LHS value depending on what will allow more optimization.
+ UseEither = 3
+};
+// Get the optimized value for a min/max instruction with a single constant
+// input (either undef or scalar constantFP). The result may indicate to
+// use the non-const LHS value, use a new constant value instead (with NaNs
+// quieted), or to choose either option in the case of undef/poison.
+static MinMaxOptResult OptimizeConstMinMax(const Constant *RHSConst,
+ const Intrinsic::ID IID,
+ const CallBase *Call,
+ Constant **OutNewConstVal) {
+ assert(OutNewConstVal != nullptr);
+
+ bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
+ bool PropagateSNaN = IID == Intrinsic::minnum || IID == Intrinsic::maxnum;
+ bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum ||
+ IID == Intrinsic::minimumnum;
+
+ // min/max(x, poison) -> either x or poison
+ if (isa<UndefValue>(RHSConst)) {
+ *OutNewConstVal = const_cast<Constant *>(RHSConst);
+ return MinMaxOptResult::UseEither;
+ }
+
+ const ConstantFP *CFP = dyn_cast<ConstantFP>(RHSConst);
+ if (!CFP)
+ return MinMaxOptResult::CannotOptimize;
+ APFloat CAPF = CFP->getValueAPF();
+
+ // minnum(x, qnan) -> x
+ // maxnum(x, qnan) -> x
+ // minnum(x, snan) -> qnan
+ // maxnum(x, snan) -> qnan
+ // minimum(X, nan) -> qnan
+ // maximum(X, nan) -> qnan
+ // minimumnum(X, nan) -> x
+ // maximumnum(X, nan) -> x
+ if (CAPF.isNaN()) {
+ if (PropagateNaN || (PropagateSNaN && CAPF.isSignaling())) {
+ *OutNewConstVal = ConstantFP::get(CFP->getType(), CAPF.makeQuiet());
+ return MinMaxOptResult::UseNewConstVal;
+ }
+ return MinMaxOptResult::UseOtherVal;
+ }
+
+ if (CAPF.isInfinity() || (Call && Call->hasNoInfs() && CAPF.isLargest())) {
+ // minnum(X, -inf) -> -inf (ignoring sNaN -> qNaN propagation)
+ // maxnum(X, +inf) -> +inf (ignoring sNaN -> qNaN propagation)
+ // minimum(X, -inf) -> -inf if nnan
+ // maximum(X, +inf) -> +inf if nnan
+ // minimumnum(X, -inf) -> -inf
+ // maximumnum(X, +inf) -> +inf
+ if (CAPF.isNegative() == IsMin &&
+ (!PropagateNaN || (Call && Call->hasNoNaNs()))) {
+ *OutNewConstVal = const_cast<Constant *>(RHSConst);
+ return MinMaxOptResult::UseNewConstVal;
+ }
+
+ // minnum(X, +inf) -> X if nnan
+ // maxnum(X, -inf) -> X if nnan
+ // minimum(X, +inf) -> X (ignoring quieting of sNaNs)
+ // maximum(X, -inf) -> X (ignoring quieting of sNaNs)
+ // minimumnum(X, +inf) -> X if nnan
+ // maximumnum(X, -inf) -> X if nnan
+ if (CAPF.isNegative() != IsMin &&
+ (PropagateNaN || (Call && Call->hasNoNaNs())))
+ return MinMaxOptResult::UseOtherVal;
+ }
+ return MinMaxOptResult::CannotOptimize;
+}
+
Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
Value *Op0, Value *Op1,
const SimplifyQuery &Q,
@@ -6780,8 +6850,17 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
case Intrinsic::maxnum:
case Intrinsic::minnum:
case Intrinsic::maximum:
- case Intrinsic::minimum: {
- // If the arguments are the same, this is a no-op.
+ case Intrinsic::minimum:
+ case Intrinsic::maximumnum:
+ case Intrinsic::minimumnum: {
+ // In several cases here, we deviate from exact IEEE 754 semantics
+ // to enable optimizations (as allowed by the LLVM IR spec).
+ //
+ // For instance, we may return one of the arguments unmodified instead of
+ // inserting an llvm.canonicalize to transform input sNaNs into qNaNs,
+ // or may assume all NaN inputs are qNaNs.
+
+ // If the arguments are the same, this is a no-op (ignoring NaN quieting)
if (Op0 == Op1)
return Op0;
@@ -6789,40 +6868,55 @@ Value *llvm::simplifyBinaryIntrinsic(Intrinsic::ID IID, Type *ReturnType,
if (isa<Constant>(Op0))
std::swap(Op0, Op1);
- // If an argument is undef, return the other argument.
- if (Q.isUndefValue(Op1))
- return Op0;
+ if (Constant *C = dyn_cast<Constant>(Op1)) {
+ MinMaxOptResult OptResult = MinMaxOptResult::CannotOptimize;
+ Constant *NewConst = nullptr;
+
+ if (VectorType *VTy = dyn_cast<VectorType>(C->getType())) {
+ ElementCount ElemCount = VTy->getElementCount();
+
+ if (Constant *SplatVal = C->getSplatValue()) {
+ // Handle splat vectors (including scalable vectors)
+ OptResult = OptimizeConstMinMax(SplatVal, IID, Call, &NewConst);
+ if (OptResult == MinMaxOptResult::UseNewConstVal)
+ NewConst = ConstantVector::getSplat(ElemCount, NewConst);
+
+ } else if (ElemCount.isFixed()) {
+ // Storage to build up new const return value (with NaNs quieted)
+ SmallVector<Constant *, 16> NewC(ElemCount.getFixedValue());
+
+ // Check elementwise whether we can optimize to either a constant
+ // value or return the LHS value. We cannot mix and match LHS +
+ // constant elements, as this would require inserting a new
+ // VectorShuffle instruction, which is not allowed in simplifyBinOp.
+ OptResult = MinMaxOptResult::UseEither;
+ for (unsigned i = 0; i != ElemCount.getFixedValue(); ++i) {
+ auto ElemResult = OptimizeConstMinMax(C->getAggregateElement(i),
+ IID, Call, &NewConst);
+ if (ElemResult == MinMaxOptResult::CannotOptimize ||
+ (ElemResult != OptResult &&
+ OptResult != MinMaxOptResult::UseEither &&
+ ElemResult != MinMaxOptResult::UseEither)) {
+ OptResult = MinMaxOptResult::CannotOptimize;
+ break;
+ }
+ NewC[i] = NewConst;
+ if (ElemResult != MinMaxOptResult::UseEither)
+ OptResult = ElemResult;
+ }
+ if (OptResult == MinMaxOptResult::UseNewConstVal)
+ NewConst = ConstantVector::get(NewC);
+ }
+ } else {
+ // Handle scalar inputs
+ OptResult = OptimizeConstMinMax(C, IID, Call, &NewConst);
+ }
- bool PropagateNaN = IID == Intrinsic::minimum || IID == Intrinsic::maximum;
- bool IsMin = IID == Intrinsic::minimum || IID == Intrinsic::minnum;
-
- // minnum(X, nan) -> X
- // maxnum(X, nan) -> X
- // minimum(X, nan) -> nan
- // maximum(X, nan) -> nan
- if (match(Op1, m_NaN()))
- return PropagateNaN ? propagateNaN(cast<Constant>(Op1)) : Op0;
-
- // In the following folds, inf can be replaced with the largest finite
- // float, if the ninf flag is set.
- const APFloat *C;
- if (match(Op1, m_APFloat(C)) &&
- (C->isInfinity() || (Call && Call->hasNoInfs() && C->isLargest()))) {
- // minnum(X, -inf) -> -inf
- // maxnum(X, +inf) -> +inf
- // minimum(X, -inf) -> -inf if nnan
- // maximum(X, +inf) -> +inf if nnan
- if (C->isNegative() == IsMin &&
- (!PropagateNaN || (Call && Call->hasNoNaNs())))
- return ConstantFP::get(ReturnType, *C);
-
- // minnum(X, +inf) -> X if nnan
- // maxnum(X, -inf) -> X if nnan
- // minimum(X, +inf) -> X
- // maximum(X, -inf) -> X
- if (C->isNegative() != IsMin &&
- (PropagateNaN || (Call && Call->hasNoNaNs())))
- return Op0;
+ if (OptResult == MinMaxOptResult::UseOtherVal ||
+ OptResult == MinMaxOptResult::UseEither)
+ return Op0; // Return the other arg (ignoring NaN quieting)
+ else if (OptResult == MinMaxOptResult::UseNewConstVal)
+ return NewConst;
}
// Min/max of the same operation with common operand:
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 0c4e3a2..4c2e1fe 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -37,17 +37,13 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
function_ref<bool(const RetainedKnowledge &RK)> CheckSize,
const DataLayout &DL, const Instruction *CtxI, AssumptionCache *AC,
const DominatorTree *DT) {
- // Dereferenceable information from assumptions is only valid if the value
- // cannot be freed between the assumption and use. For now just use the
- // information for values that cannot be freed in the function.
- // TODO: More precisely check if the pointer can be freed between assumption
- // and use.
- if (!CtxI || Ptr->canBeFreed())
+ if (!CtxI)
return false;
/// Look through assumes to see if both dereferencability and alignment can
/// be proven by an assume if needed.
RetainedKnowledge AlignRK;
RetainedKnowledge DerefRK;
+ bool PtrCanBeFreed = Ptr->canBeFreed();
bool IsAligned = Ptr->getPointerAlignment(DL) >= Alignment;
return getKnowledgeForValue(
Ptr, {Attribute::Dereferenceable, Attribute::Alignment}, *AC,
@@ -56,7 +52,11 @@ static bool isDereferenceableAndAlignedPointerViaAssumption(
return false;
if (RK.AttrKind == Attribute::Alignment)
AlignRK = std::max(AlignRK, RK);
- if (RK.AttrKind == Attribute::Dereferenceable)
+
+ // Dereferenceable information from assumptions is only valid if the
+ // value cannot be freed between the assumption and use.
+ if ((!PtrCanBeFreed || willNotFreeBetween(Assume, CtxI)) &&
+ RK.AttrKind == Attribute::Dereferenceable)
DerefRK = std::max(DerefRK, RK);
IsAligned |= AlignRK && AlignRK.ArgValue >= Alignment.value();
if (IsAligned && DerefRK && CheckSize(DerefRK))
@@ -390,7 +390,11 @@ bool llvm::isDereferenceableAndAlignedInLoop(
} else
return false;
- Instruction *HeaderFirstNonPHI = &*L->getHeader()->getFirstNonPHIIt();
+ Instruction *CtxI = &*L->getHeader()->getFirstNonPHIIt();
+ if (BasicBlock *LoopPred = L->getLoopPredecessor()) {
+ if (isa<BranchInst>(LoopPred->getTerminator()))
+ CtxI = LoopPred->getTerminator();
+ }
return isDereferenceableAndAlignedPointerViaAssumption(
Base, Alignment,
[&SE, AccessSizeSCEV, &LoopGuards](const RetainedKnowledge &RK) {
@@ -399,9 +403,9 @@ bool llvm::isDereferenceableAndAlignedInLoop(
SE.applyLoopGuards(AccessSizeSCEV, *LoopGuards),
SE.applyLoopGuards(SE.getSCEV(RK.IRArgValue), *LoopGuards));
},
- DL, HeaderFirstNonPHI, AC, &DT) ||
+ DL, CtxI, AC, &DT) ||
isDereferenceableAndAlignedPointer(Base, Alignment, AccessSize, DL,
- HeaderFirstNonPHI, AC, &DT);
+ CtxI, AC, &DT);
}
static bool suppressSpeculativeLoadForSanitizers(const Instruction &CtxI) {
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index a42c061..9655c88 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -9095,6 +9095,10 @@ Intrinsic::ID llvm::getInverseMinMaxIntrinsic(Intrinsic::ID MinMaxID) {
case Intrinsic::minimum: return Intrinsic::maximum;
case Intrinsic::maxnum: return Intrinsic::minnum;
case Intrinsic::minnum: return Intrinsic::maxnum;
+ case Intrinsic::maximumnum:
+ return Intrinsic::minimumnum;
+ case Intrinsic::minimumnum:
+ return Intrinsic::maximumnum;
default: llvm_unreachable("Unexpected intrinsic");
}
}