diff options
Diffstat (limited to 'llvm/lib')
-rw-r--r-- | llvm/lib/IR/DiagnosticInfo.cpp | 11 | ||||
-rw-r--r-- | llvm/lib/IR/LLVMContext.cpp | 14 | ||||
-rw-r--r-- | llvm/lib/IR/LLVMContextImpl.h | 5 | ||||
-rw-r--r-- | llvm/lib/Transforms/IPO/SampleProfile.cpp | 4 | ||||
-rw-r--r-- | llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp | 3 | ||||
-rw-r--r-- | llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp | 10 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/CMakeLists.txt | 1 | ||||
-rw-r--r-- | llvm/lib/Transforms/Utils/MisExpect.cpp | 234 |
8 files changed, 2 insertions, 280 deletions
diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp index 50fe682..f46f0fd 100644 --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -393,17 +393,6 @@ std::string DiagnosticInfoOptimizationBase::getMsg() const { return OS.str(); } -DiagnosticInfoMisExpect::DiagnosticInfoMisExpect(const Instruction *Inst, - Twine &Msg) - : DiagnosticInfoWithLocationBase(DK_MisExpect, DS_Warning, - *Inst->getParent()->getParent(), - Inst->getDebugLoc()), - Msg(Msg) {} - -void DiagnosticInfoMisExpect::print(DiagnosticPrinter &DP) const { - DP << getLocationStr() << ": " << getMsg(); -} - void OptimizationRemarkAnalysisFPCommute::anchor() {} void OptimizationRemarkAnalysisAliasing::anchor() {} diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp index df4a007..f4e917c 100644 --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -138,22 +138,10 @@ bool LLVMContext::getDiagnosticsHotnessRequested() const { void LLVMContext::setDiagnosticsHotnessThreshold(Optional<uint64_t> Threshold) { pImpl->DiagnosticsHotnessThreshold = Threshold; } -void LLVMContext::setMisExpectWarningRequested(bool Requested) { - pImpl->MisExpectWarningRequested = Requested; -} -bool LLVMContext::getMisExpectWarningRequested() const { - return pImpl->MisExpectWarningRequested; -} + uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const { return pImpl->DiagnosticsHotnessThreshold.getValueOr(UINT64_MAX); } -void LLVMContext::setDiagnosticsMisExpectTolerance( - Optional<uint64_t> Tolerance) { - pImpl->DiagnosticsMisExpectTolerance = Tolerance; -} -uint64_t LLVMContext::getDiagnosticsMisExpectTolerance() const { - return pImpl->DiagnosticsMisExpectTolerance.getValueOr(0); -} bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { return !pImpl->DiagnosticsHotnessThreshold.hasValue(); diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h index 0b39029..b87d285 100644 --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1380,11 +1380,6 @@ public: /// If threshold option is not specified, it is disabled (0) by default. Optional<uint64_t> DiagnosticsHotnessThreshold = 0; - /// The percentage of difference between profiling branch weights and - // llvm.expect branch weights to tolerate when emiting MisExpect diagnostics - Optional<uint64_t> DiagnosticsMisExpectTolerance = 0; - bool MisExpectWarningRequested = false; - /// The specialized remark streamer used by LLVM's OptimizationRemarkEmitter. std::unique_ptr<LLVMRemarkStreamer> LLVMRS; diff --git a/llvm/lib/Transforms/IPO/SampleProfile.cpp b/llvm/lib/Transforms/IPO/SampleProfile.cpp index 4bd7900..8232406 100644 --- a/llvm/lib/Transforms/IPO/SampleProfile.cpp +++ b/llvm/lib/Transforms/IPO/SampleProfile.cpp @@ -74,8 +74,6 @@ #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/CallPromotionUtils.h" #include "llvm/Transforms/Utils/Cloning.h" -#include "llvm/Transforms/Utils/MisExpect.h" -#include "llvm/Transforms/Utils/SampleProfileInference.h" #include "llvm/Transforms/Utils/SampleProfileLoaderBaseImpl.h" #include "llvm/Transforms/Utils/SampleProfileLoaderBaseUtil.h" #include <algorithm> @@ -1741,8 +1739,6 @@ void SampleProfileLoader::generateMDProfMetadata(Function &F) { } } - misexpect::checkExpectAnnotations(*TI, Weights, /*IsFrontend=*/false); - uint64_t TempWeight; // Only set weights if there is at least one non-zero weight. // In any other case, let the analyzer set weights. diff --git a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp index 35ea646..d421894 100644 --- a/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp +++ b/llvm/lib/Transforms/Instrumentation/PGOInstrumentation.cpp @@ -110,7 +110,6 @@ #include "llvm/Support/raw_ostream.h" #include "llvm/Transforms/Instrumentation.h" #include "llvm/Transforms/Utils/BasicBlockUtils.h" -#include "llvm/Transforms/Utils/MisExpect.h" #include "llvm/Transforms/Utils/ModuleUtils.h" #include <algorithm> #include <cassert> @@ -2118,8 +2117,6 @@ void llvm::setProfMetadata(Module *M, Instruction *TI, dbgs() << W << " "; } dbgs() << "\n";); - misexpect::checkExpectAnnotations(*TI, Weights, /*IsFrontend=*/false); - TI->setMetadata(LLVMContext::MD_prof, MDB.createBranchWeights(Weights)); if (EmitBranchProbability) { std::string BrCondStr = getBranchCondString(TI); diff --git a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp index 88fad98..97c8f33 100644 --- a/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp +++ b/llvm/lib/Transforms/Scalar/LowerExpectIntrinsic.cpp @@ -25,7 +25,6 @@ #include "llvm/Pass.h" #include "llvm/Support/CommandLine.h" #include "llvm/Transforms/Scalar.h" -#include "llvm/Transforms/Utils/MisExpect.h" using namespace llvm; @@ -100,8 +99,6 @@ static bool handleSwitchExpect(SwitchInst &SI) { uint64_t Index = (Case == *SI.case_default()) ? 0 : Case.getCaseIndex() + 1; Weights[Index] = LikelyBranchWeightVal; - misexpect::checkExpectAnnotations(SI, Weights, /*IsFrontend=*/true); - SI.setCondition(ArgValue); SI.setMetadata(LLVMContext::MD_prof, @@ -316,16 +313,13 @@ template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) { std::tie(LikelyBranchWeightVal, UnlikelyBranchWeightVal) = getBranchWeight(Fn->getIntrinsicID(), CI, 2); - SmallVector<uint32_t, 4> ExpectedWeights; if ((ExpectedValue->getZExtValue() == ValueComparedTo) == (Predicate == CmpInst::ICMP_EQ)) { Node = MDB.createBranchWeights(LikelyBranchWeightVal, UnlikelyBranchWeightVal); - ExpectedWeights = {LikelyBranchWeightVal, UnlikelyBranchWeightVal}; } else { Node = MDB.createBranchWeights(UnlikelyBranchWeightVal, LikelyBranchWeightVal); - ExpectedWeights = {UnlikelyBranchWeightVal, LikelyBranchWeightVal}; } if (CmpI) @@ -333,8 +327,6 @@ template <class BrSelInst> static bool handleBrSelExpect(BrSelInst &BSI) { else BSI.setCondition(ArgValue); - misexpect::checkFrontendInstrumentation(BSI, ExpectedWeights); - BSI.setMetadata(LLVMContext::MD_prof, Node); return true; @@ -415,7 +407,7 @@ public: bool runOnFunction(Function &F) override { return lowerExpectIntrinsic(F); } }; -} // namespace +} char LowerExpectIntrinsic::ID = 0; INITIALIZE_PASS(LowerExpectIntrinsic, "lower-expect", diff --git a/llvm/lib/Transforms/Utils/CMakeLists.txt b/llvm/lib/Transforms/Utils/CMakeLists.txt index 3462f89..58eddb7 100644 --- a/llvm/lib/Transforms/Utils/CMakeLists.txt +++ b/llvm/lib/Transforms/Utils/CMakeLists.txt @@ -53,7 +53,6 @@ add_llvm_component_library(LLVMTransformUtils MemoryTaggingSupport.cpp Mem2Reg.cpp MetaRenamer.cpp - MisExpect.cpp ModuleUtils.cpp NameAnonGlobals.cpp PredicateInfo.cpp diff --git a/llvm/lib/Transforms/Utils/MisExpect.cpp b/llvm/lib/Transforms/Utils/MisExpect.cpp deleted file mode 100644 index 044a2ca..0000000 --- a/llvm/lib/Transforms/Utils/MisExpect.cpp +++ /dev/null @@ -1,234 +0,0 @@ -//===--- MisExpect.cpp - Check the use of llvm.expect with PGO data -------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// -// -// This contains code to emit warnings for potentially incorrect usage of the -// llvm.expect intrinsic. This utility extracts the threshold values from -// metadata associated with the instrumented Branch or Switch instruction. The -// threshold values are then used to determine if a warning should be emmited. -// -// MisExpect's implementation relies on two assumptions about how branch weights -// are managed in LLVM. -// -// 1) Frontend profiling weights are always in place before llvm.expect is -// lowered in LowerExpectIntrinsic.cpp. Frontend based instrumentation therefore -// needs to extract the branch weights and then compare them to the weights -// being added by the llvm.expect intrinsic lowering. -// -// 2) Sampling and IR based profiles will *only* have branch weight metadata -// before profiling data is consulted if they are from a lowered llvm.expect -// intrinsic. These profiles thus always extract the expected weights and then -// compare them to the weights collected during profiling to determine if a -// diagnostic message is warranted. -// -//===----------------------------------------------------------------------===// - -#include "llvm/Transforms/Utils/MisExpect.h" -#include "llvm/ADT/Twine.h" -#include "llvm/Analysis/OptimizationRemarkEmitter.h" -#include "llvm/IR/Constants.h" -#include "llvm/IR/DiagnosticInfo.h" -#include "llvm/IR/Instruction.h" -#include "llvm/IR/Instructions.h" -#include "llvm/IR/LLVMContext.h" -#include "llvm/Support/BranchProbability.h" -#include "llvm/Support/CommandLine.h" -#include "llvm/Support/Debug.h" -#include "llvm/Support/FormatVariadic.h" -#include <cstdint> -#include <functional> -#include <numeric> - -#define DEBUG_TYPE "misexpect" - -using namespace llvm; -using namespace misexpect; - -namespace llvm { - -// Command line option to enable/disable the warning when profile data suggests -// a mismatch with the use of the llvm.expect intrinsic -static cl::opt<bool> PGOWarnMisExpect( - "pgo-warn-misexpect", cl::init(false), cl::Hidden, - cl::desc("Use this option to turn on/off " - "warnings about incorrect usage of llvm.expect intrinsics.")); - -static cl::opt<unsigned> MisExpectTolerance( - "misexpect-tolerance", cl::init(0), - cl::desc("Prevents emiting diagnostics when profile counts are " - "within N% of the threshold..")); - -} // namespace llvm - -namespace { - -bool isMisExpectDiagEnabled(LLVMContext &Ctx) { - return PGOWarnMisExpect || Ctx.getMisExpectWarningRequested(); -} - -uint64_t getMisExpectTolerance(LLVMContext &Ctx) { - return std::max(static_cast<uint64_t>(MisExpectTolerance), - Ctx.getDiagnosticsMisExpectTolerance()); -} - -Instruction *getInstCondition(Instruction *I) { - assert(I != nullptr && "MisExpect target Instruction cannot be nullptr"); - Instruction *Ret = nullptr; - if (auto *B = dyn_cast<BranchInst>(I)) { - Ret = dyn_cast<Instruction>(B->getCondition()); - } - // TODO: Find a way to resolve condition location for switches - // Using the condition of the switch seems to often resolve to an earlier - // point in the program, i.e. the calculation of the switch condition, rather - // than the switch's location in the source code. Thus, we should use the - // instruction to get source code locations rather than the condition to - // improve diagnostic output, such as the caret. If the same problem exists - // for branch instructions, then we should remove this function and directly - // use the instruction - // - else if (auto *S = dyn_cast<SwitchInst>(I)) { - Ret = dyn_cast<Instruction>(S->getCondition()); - } - return Ret ? Ret : I; -} - -void emitMisexpectDiagnostic(Instruction *I, LLVMContext &Ctx, - uint64_t ProfCount, uint64_t TotalCount) { - double PercentageCorrect = (double)ProfCount / TotalCount; - auto PerString = - formatv("{0:P} ({1} / {2})", PercentageCorrect, ProfCount, TotalCount); - auto RemStr = formatv( - "Potential performance regression from use of the llvm.expect intrinsic: " - "Annotation was correct on {0} of profiled executions.", - PerString); - Twine Msg(PerString); - Instruction *Cond = getInstCondition(I); - if (isMisExpectDiagEnabled(Ctx)) - Ctx.diagnose(DiagnosticInfoMisExpect(Cond, Msg)); - OptimizationRemarkEmitter ORE(I->getParent()->getParent()); - ORE.emit(OptimizationRemark(DEBUG_TYPE, "misexpect", Cond) << RemStr.str()); -} - -} // namespace - -namespace llvm { -namespace misexpect { - -// Helper function to extract branch weights into a vector -Optional<SmallVector<uint32_t, 4>> extractWeights(Instruction *I, - LLVMContext &Ctx) { - assert(I && "MisExpect::extractWeights given invalid pointer"); - - auto *ProfileData = I->getMetadata(LLVMContext::MD_prof); - if (!ProfileData) - return None; - - unsigned NOps = ProfileData->getNumOperands(); - if (NOps < 3) - return None; - - auto *ProfDataName = dyn_cast<MDString>(ProfileData->getOperand(0)); - if (!ProfDataName || !ProfDataName->getString().equals("branch_weights")) - return None; - - SmallVector<uint32_t, 4> Weights(NOps - 1); - for (unsigned Idx = 1; Idx < NOps; Idx++) { - ConstantInt *Value = - mdconst::dyn_extract<ConstantInt>(ProfileData->getOperand(Idx)); - uint32_t V = Value->getZExtValue(); - Weights[Idx - 1] = V; - } - - return Weights; -} - -void verifyMisExpect(Instruction &I, ArrayRef<uint32_t> RealWeights, - ArrayRef<uint32_t> ExpectedWeights) { - // To determine if we emit a diagnostic, we need to compare the branch weights - // from the profile to those added by the llvm.expect intrinsic. - // So first, we extract the "likely" and "unlikely" weights from - // ExpectedWeights And determine the correct weight in the profile to compare - // against. - uint64_t LikelyBranchWeight = 0, - UnlikelyBranchWeight = std::numeric_limits<uint32_t>::max(); - size_t MaxIndex = 0; - for (size_t Idx = 0, End = ExpectedWeights.size(); Idx < End; Idx++) { - uint32_t V = ExpectedWeights[Idx]; - if (LikelyBranchWeight < V) { - LikelyBranchWeight = V; - MaxIndex = Idx; - } - if (UnlikelyBranchWeight > V) { - UnlikelyBranchWeight = V; - } - } - - const uint64_t ProfiledWeight = RealWeights[MaxIndex]; - const uint64_t RealWeightsTotal = - std::accumulate(RealWeights.begin(), RealWeights.end(), (uint64_t)0, - std::plus<uint64_t>()); - const uint64_t NumUnlikelyTargets = RealWeights.size() - 1; - - const uint64_t TotalBranchWeight = - LikelyBranchWeight + (UnlikelyBranchWeight * NumUnlikelyTargets); - - // To determine our threshold value we need to obtain the branch probability - // for the weights added by llvm.expect and use that proportion to calculate - // our threshold based on the collected profile data. - const llvm::BranchProbability LikelyProbablilty(LikelyBranchWeight, - TotalBranchWeight); - uint64_t ScaledThreshold = LikelyProbablilty.scale(RealWeightsTotal); - - // clamp tolerance range to [0, 100) - auto Tolerance = getMisExpectTolerance(I.getContext()); - if (Tolerance < 0) - Tolerance = 0; - else if (MisExpectTolerance > 99) - Tolerance = 99; - - // Allow users to relax checking by N% i.e., if they use a 5% tolerance, - // then we check against 0.95*ScaledThreshold - if (Tolerance > 0) - ScaledThreshold *= (1.0 - Tolerance / 100.0); - - // When the profile weight is below the threshold, we emit the diagnostic - if (ProfiledWeight < ScaledThreshold) - emitMisexpectDiagnostic(&I, I.getContext(), ProfiledWeight, - RealWeightsTotal); -} - -void checkBackendInstrumentation(Instruction &I, - const ArrayRef<uint32_t> RealWeights) { - auto ExpectedWeightsOpt = extractWeights(&I, I.getContext()); - if (!ExpectedWeightsOpt.hasValue()) - return; - auto ExpectedWeights = ExpectedWeightsOpt.getValue(); - verifyMisExpect(I, RealWeights, ExpectedWeights); -} - -void checkFrontendInstrumentation(Instruction &I, - const ArrayRef<uint32_t> ExpectedWeights) { - auto RealWeightsOpt = extractWeights(&I, I.getContext()); - if (!RealWeightsOpt.hasValue()) - return; - auto RealWeights = RealWeightsOpt.getValue(); - verifyMisExpect(I, RealWeights, ExpectedWeights); -} - -void checkExpectAnnotations(Instruction &I, - const ArrayRef<uint32_t> ExistingWeights, - bool IsFrontendInstr) { - if (IsFrontendInstr) { - checkFrontendInstrumentation(I, ExistingWeights); - } else { - checkBackendInstrumentation(I, ExistingWeights); - } -} - -} // namespace misexpect -} // namespace llvm -#undef DEBUG_TYPE |