-
Notifications
You must be signed in to change notification settings - Fork 10.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Avoid BlockFrequency overflow problems #66280
Conversation
@llvm/pr-subscribers-llvm-analysis ChangesMultiplying raw block frequency with an integer carries a high risk of overflow.
5 Files Affected:
diff --git a/llvm/include/llvm/Support/BlockFrequency.h b/llvm/include/llvm/Support/BlockFrequency.h index 6c624d7dad7d801..1711fb592485b4c 100644 --- a/llvm/include/llvm/Support/BlockFrequency.h +++ b/llvm/include/llvm/Support/BlockFrequency.h @@ -16,6 +16,8 @@ #include <cassert> #include <cstdint> +#include "llvm/Support/Compiler.h" + namespace llvm { class BranchProbability; @@ -76,6 +78,12 @@ class BlockFrequency { return NewFreq; } + /// Multiplies frequency with `Factor` and stores the result into `Result`. + /// Returns `true` if an overflow occured. Overflows are common and should be + /// checked by all callers. + bool mul(uint64_t Factor, + BlockFrequency *Result) const LLVM_WARN_UNUSED_RESULT; + /// Shift block frequency to the right by count digits saturating to 1. BlockFrequency &operator>>=(const unsigned count) { // Frequency can never be 0 by design. diff --git a/llvm/include/llvm/Support/Compiler.h b/llvm/include/llvm/Support/Compiler.h index 12afe90f8facd47..9527e377317ac33 100644 --- a/llvm/include/llvm/Support/Compiler.h +++ b/llvm/include/llvm/Support/Compiler.h @@ -269,6 +269,14 @@ #define LLVM_ATTRIBUTE_RETURNS_NOALIAS #endif +/// Mark a function whose return value should not be ignored. Doing so without +/// a `[[maybe_unused]]` produces a warning if supported by the compiler. +#if __has_attribute(warn_unused_result) +#define LLVM_WARN_UNUSED_RESULT __attribute__((warn_unused_result)) +#else +#define LLVM_WARN_UNUSED_RESULT +#endif + /// LLVM_FALLTHROUGH - Mark fallthrough cases in switch statements. #if defined(__cplusplus) && __cplusplus > 201402L && LLVM_HAS_CPP_ATTRIBUTE(fallthrough) #define LLVM_FALLTHROUGH [[fallthrough]] diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp index a9de1dde7c7f717..d921047d6466f52 100644 --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -118,7 +118,7 @@ static cl::opt<int> ColdCallSiteRelFreq( "entry frequency, for a callsite to be cold in the absence of " "profile information.")); -static cl::opt<int> HotCallSiteRelFreq( +static cl::opt<uint64_t> HotCallSiteRelFreq( "hot-callsite-rel-freq", cl::Hidden, cl::init(60), cl::desc("Minimum block frequency, expressed as a multiple of caller's " "entry frequency, for a callsite to be hot in the absence of " @@ -1820,10 +1820,11 @@ InlineCostCallAnalyzer::getHotCallSiteThreshold(CallBase &Call, // potentially cache the computation of scaled entry frequency, but the added // complexity is not worth it unless this scaling shows up high in the // profiles. - auto CallSiteBB = Call.getParent(); - auto CallSiteFreq = CallerBFI->getBlockFreq(CallSiteBB).getFrequency(); - auto CallerEntryFreq = CallerBFI->getEntryFreq(); - if (CallSiteFreq >= CallerEntryFreq * HotCallSiteRelFreq) + const BasicBlock *CallSiteBB = Call.getParent(); + BlockFrequency CallSiteFreq = CallerBFI->getBlockFreq(CallSiteBB); + BlockFrequency CallerEntryFreq = CallerBFI->getEntryFreq(); + BlockFrequency Limit; + if (!CallerEntryFreq.mul(HotCallSiteRelFreq, &Limit) && CallSiteFreq >= Limit) return Params.LocallyHotCallSiteThreshold; // Otherwise treat it normally. diff --git a/llvm/lib/CodeGen/CodeGenPrepare.cpp b/llvm/lib/CodeGen/CodeGenPrepare.cpp index f07fc4fc52bffba..e24361c1f93970d 100644 --- a/llvm/lib/CodeGen/CodeGenPrepare.cpp +++ b/llvm/lib/CodeGen/CodeGenPrepare.cpp @@ -198,7 +198,7 @@ static cl::opt<bool> BBSectionsGuidedSectionPrefix( "impacted, i.e., their prefixes will be decided by FDO/sampleFDO " "profiles.")); -static cl::opt<unsigned> FreqRatioToSkipMerge( +static cl::opt<uint64_t> FreqRatioToSkipMerge( "cgp-freq-ratio-to-skip-merge", cl::Hidden, cl::init(2), cl::desc("Skip merging empty blocks if (frequency of empty block) / " "(frequency of destination block) is greater than this ratio")); @@ -978,16 +978,16 @@ bool CodeGenPrepare::isMergingEmptyBlockProfitable(BasicBlock *BB, if (SameIncomingValueBBs.count(Pred)) return true; - BlockFrequency PredFreq = BFI->getBlockFreq(Pred); - BlockFrequency BBFreq = BFI->getBlockFreq(BB); + BlockFrequency PredFreq = BFI->getBlockFreq(Pred).getFrequency(); + BlockFrequency BBFreq = BFI->getBlockFreq(BB).getFrequency(); for (auto *SameValueBB : SameIncomingValueBBs) if (SameValueBB->getUniquePredecessor() == Pred && DestBB == findDestBlockOfMergeableEmptyBlock(SameValueBB)) BBFreq += BFI->getBlockFreq(SameValueBB); - return PredFreq.getFrequency() <= - BBFreq.getFrequency() * FreqRatioToSkipMerge; + BlockFrequency Limit; + return !BBFreq.mul(FreqRatioToSkipMerge, &Limit) && PredFreq <= Limit; } /// Return true if we can merge BB into DestBB if there is a single diff --git a/llvm/lib/Support/BlockFrequency.cpp b/llvm/lib/Support/BlockFrequency.cpp index a4a1e477d9403f7..08fe3ef6061ecae 100644 --- a/llvm/lib/Support/BlockFrequency.cpp +++ b/llvm/lib/Support/BlockFrequency.cpp @@ -12,6 +12,7 @@ #include "llvm/Support/BlockFrequency.h" #include "llvm/Support/BranchProbability.h" +#include "llvm/Support/MathExtras.h" using namespace llvm; @@ -36,3 +37,10 @@ BlockFrequency BlockFrequency::operator/(BranchProbability Prob) const { Freq /= Prob; return Freq; } + +bool BlockFrequency::mul(uint64_t Factor, BlockFrequency *Result) const { + bool Overflow; + uint64_t ResultFrequency = SaturatingMultiply(Frequency, Factor, &Overflow); + *Result = BlockFrequency(ResultFrequency); + return Overflow; +} |
Error: Command failed due to missing milestone. |
An alternative fix for this would be to perform the arithemtic on |
8ede6e6
to
0bd06f1
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Thank you for updating the patch! (And even bigger thank you for paying attention to the block frequencies in the first place!)
Please be sure to update the commit message also as we no longer use __attribute__((warn_unused_result))
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM.
Multiplying raw block frequency with an integer carries a high risk of overflow. - Add `BlockFrequency::mul` return an std::optional with the product or `nullopt` to indicate an overflow. - Fix two instances where overflow was likely.
0bd06f1
to
c612ed5
Compare
Multiplying raw block frequency with an integer carries a high risk of overflow. - Add `BlockFrequency::mul` return an std::optional with the product or `nullopt` to indicate an overflow. - Fix two instances where overflow was likely.
Multiplying raw block frequency with an integer carries a high risk of overflow.
BlockFrequency::mul
function returning abool
indicating overflow.__attribute__((warn_unused_result))
to avoid users accidentally ignoring the indicator.