diff --git a/clang/include/clang/Basic/CodeGenOptions.h b/clang/include/clang/Basic/CodeGenOptions.h --- a/clang/include/clang/Basic/CodeGenOptions.h +++ b/clang/include/clang/Basic/CodeGenOptions.h @@ -426,6 +426,10 @@ /// values in order to be included in misexpect diagnostics. Optional DiagnosticsMisExpectTolerance = 0; + /// The minimum function hotness percentile after which we emit + /// a warning to be included in misnoinline diagnostics. + Optional DiagnosticsNoInlinePercentileThreshold = 990000; + public: // Define accessors/mutators for code generation options of enumeration type. #define CODEGENOPT(Name, Bits, Default) diff --git a/clang/include/clang/Basic/CodeGenOptions.def b/clang/include/clang/Basic/CodeGenOptions.def --- a/clang/include/clang/Basic/CodeGenOptions.def +++ b/clang/include/clang/Basic/CodeGenOptions.def @@ -182,6 +182,7 @@ ///< enabled. CODEGENOPT(NoWarn , 1, 0) ///< Set when -Wa,--no-warn is enabled. CODEGENOPT(MisExpect , 1, 0) ///< Set when -Wmisexpect is enabled +CODEGENOPT(MisNoInline , 1, 0) ///< Set when -Wmisnoinline is enabled CODEGENOPT(EnableSegmentedStacks , 1, 0) ///< Set when -fsplit-stack is enabled. CODEGENOPT(NoInlineLineTables, 1, 0) ///< Whether debug info should contain ///< inline line tables. diff --git a/clang/include/clang/Basic/DiagnosticDriverKinds.td b/clang/include/clang/Basic/DiagnosticDriverKinds.td --- a/clang/include/clang/Basic/DiagnosticDriverKinds.td +++ b/clang/include/clang/Basic/DiagnosticDriverKinds.td @@ -148,6 +148,8 @@ "invalid argument in '%0', only integer or 'auto' is supported">; def err_drv_invalid_diagnotics_misexpect_tolerance : Error< "invalid argument in '%0', only integers are supported">; +def err_drv_invalid_diagnotics_misnoinline_threshold : Error< + "invalid argument in '%0' only integers are supported">; def err_drv_missing_argument : Error< "argument to '%0' is missing (expected %1 value%s1)">; def err_drv_invalid_Xarch_argument_with_args : Error< diff --git a/clang/include/clang/Basic/DiagnosticFrontendKinds.td b/clang/include/clang/Basic/DiagnosticFrontendKinds.td --- a/clang/include/clang/Basic/DiagnosticFrontendKinds.td +++ b/clang/include/clang/Basic/DiagnosticFrontendKinds.td @@ -320,6 +320,10 @@ "Annotation was correct on %0 of profiled executions.">, BackendInfo, InGroup; +def warn_profile_data_misnoinline : Warning< + "noinline attribute marking for %0:%1 may hurt performance.">, + BackendInfo, + InGroup; } // end of instrumentation issue category } diff --git a/clang/include/clang/Basic/DiagnosticGroups.td b/clang/include/clang/Basic/DiagnosticGroups.td --- a/clang/include/clang/Basic/DiagnosticGroups.td +++ b/clang/include/clang/Basic/DiagnosticGroups.td @@ -1272,6 +1272,7 @@ def ProfileInstrOutOfDate : DiagGroup<"profile-instr-out-of-date">; def ProfileInstrUnprofiled : DiagGroup<"profile-instr-unprofiled">; def MisExpect : DiagGroup<"misexpect">; +def MisNoInline : DiagGroup<"misnoinline">; // AddressSanitizer frontend instrumentation remarks. def SanitizeAddressRemarks : DiagGroup<"sanitize-address">; diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -1483,6 +1483,9 @@ def fdiagnostics_misexpect_tolerance_EQ : Joined<["-"], "fdiagnostics-misexpect-tolerance=">, Group, Flags<[CC1Option]>, MetaVarName<"">, HelpText<"Prevent misexpect diagnostics from being output if the profile counts are within N% of the expected. ">; +def fdiagnostics_misnoinline_percentile_EQ : Joined<["-"], "fdiagnostics-misnoinline-percentile-threshold=">, + Group, Flags<[CC1Option]>, MetaVarName<"">, + HelpText<"Prevent misnoinline diagnostics from being output if the function is colder than N% of total entry counts. ">; defm diagnostics_show_option : BoolFOption<"diagnostics-show-option", DiagnosticOpts<"ShowOptionNames">, DefaultTrue, NegFlag, PosFlag>; diff --git a/clang/lib/CodeGen/BackendUtil.cpp b/clang/lib/CodeGen/BackendUtil.cpp --- a/clang/lib/CodeGen/BackendUtil.cpp +++ b/clang/lib/CodeGen/BackendUtil.cpp @@ -479,7 +479,7 @@ Options.MCOptions.Argv0 = CodeGenOpts.Argv0; Options.MCOptions.CommandLineArgs = CodeGenOpts.CommandLineArgs; Options.MisExpect = CodeGenOpts.MisExpect; - + Options.MisNoInline = CodeGenOpts.MisNoInline; return true; } diff --git a/clang/lib/CodeGen/CodeGenAction.cpp b/clang/lib/CodeGen/CodeGenAction.cpp --- a/clang/lib/CodeGen/CodeGenAction.cpp +++ b/clang/lib/CodeGen/CodeGenAction.cpp @@ -351,6 +351,13 @@ CodeGenOpts.DiagnosticsMisExpectTolerance); } + if (CodeGenOpts.MisNoInline) + Ctx.setMisNoInlineWarningRequested(true); + + if (CodeGenOpts.DiagnosticsNoInlinePercentileThreshold) + Ctx.setDiagnosticsMisNoInlinePercentileThreshold( + CodeGenOpts.DiagnosticsNoInlinePercentileThreshold); + // Link each LinkModule into our module. if (LinkInModules()) return; @@ -451,9 +458,10 @@ void OptimizationFailureHandler( const llvm::DiagnosticInfoOptimizationFailure &D); void DontCallDiagHandler(const DiagnosticInfoDontCall &D); - /// Specialized handler for misexpect warnings. - /// Note that misexpect remarks are emitted through ORE + /// Specialized handler for misexpect and misnoinline warnings. + /// Note that misexpect/misnoinline remarks are emitted through ORE void MisExpectDiagHandler(const llvm::DiagnosticInfoMisExpect &D); + void MisNoInlineDiagHandler(const llvm::DiagnosticInfoMisNoInline &D); }; void BackendConsumer::anchor() {} @@ -854,6 +862,25 @@ << Filename << Line << Column; } +void BackendConsumer::MisNoInlineDiagHandler( + const llvm::DiagnosticInfoMisNoInline &D) { + StringRef Filename; + unsigned Line, Column; + bool BadDebugInfo = false; + FullSourceLoc Loc = + getBestLocationFromDebugLoc(D, BadDebugInfo, Filename, Line, Column); + Diags.Report(Loc, diag::warn_profile_data_misnoinline) + << D.getFunction().getParent()->getName() + << llvm::demangle(D.getFunction().getName().str()); + if (BadDebugInfo) + // If we were not able to translate the file:line:col information + // back to a SourceLocation, at least emit a note stating that + // we could not translate this location. This can happen in the + // case of #line directives. + Diags.Report(Loc, diag::note_fe_backend_invalid_loc) + << Filename << Line << Column; +} + /// This function is invoked when the backend needs /// to report something to the user. void BackendConsumer::DiagnosticHandlerImpl(const DiagnosticInfo &DI) { @@ -931,6 +958,9 @@ case llvm::DK_MisExpect: MisExpectDiagHandler(cast(DI)); return; + case llvm::DK_MisNoInline: + MisNoInlineDiagHandler(cast(DI)); + return; default: // Plugin IDs are not bound to any value as they are set dynamically. ComputeDiagRemarkID(Severity, backend_plugin, DiagID); diff --git a/clang/lib/Frontend/CompilerInvocation.cpp b/clang/lib/Frontend/CompilerInvocation.cpp --- a/clang/lib/Frontend/CompilerInvocation.cpp +++ b/clang/lib/Frontend/CompilerInvocation.cpp @@ -120,6 +120,14 @@ "Not an integer: %s", Arg.data()); return Val; } +// Parse misnoinline count value. +// Valid option values are integers in the range [0, infinity) +inline Optional parseCountOption(StringRef Arg) { + int64_t Val; + if (Arg.getAsInteger(10, Val)) + return Optional(); + return Val; +} //===----------------------------------------------------------------------===// // Initialization. @@ -1553,6 +1561,9 @@ GenerateArg(Args, OPT_fdiagnostics_misexpect_tolerance_EQ, Twine(*Opts.DiagnosticsMisExpectTolerance), SA); + GenerateArg(Args, OPT_fdiagnostics_misnoinline_percentile_EQ, + Twine(*Opts.DiagnosticsNoInlinePercentileThreshold), SA); + for (StringRef Sanitizer : serializeSanitizerKinds(Opts.SanitizeRecover)) GenerateArg(Args, OPT_fsanitize_recover_EQ, Sanitizer, SA); @@ -2010,6 +2021,24 @@ } } + if (auto *arg = Args.getLastArg( + options::OPT_fdiagnostics_misnoinline_percentile_EQ)) { + auto ResultOrErr = parseCountOption(arg->getValue()); + + if (!ResultOrErr) { + Diags.Report(diag::err_drv_invalid_diagnotics_misnoinline_threshold) + << "-fdiagnostics-misnoinline-percentile-threshold="; + } else { + Opts.DiagnosticsNoInlinePercentileThreshold = *ResultOrErr; + if ((!Opts.DiagnosticsNoInlinePercentileThreshold || + Opts.MisNoInline == 1) && + !UsingProfile) { + Diags.Report(diag::warn_drv_diagnostics_misexpect_requires_pgo) + << "-fdiagnostics-misnoinline-percentile-threshold="; + } + } + } + // If the user requested to use a sample profile for PGO, then the // backend will need to track source location information so the profile // can be incorporated into the IR. @@ -4482,6 +4511,11 @@ !Diags.isIgnored(diag::warn_profile_data_misexpect, SourceLocation())) { Res.getCodeGenOpts().MisExpect = true; } + if (Warning == "misnoinline" && + !Diags.isIgnored(diag::warn_profile_data_misnoinline, + SourceLocation())) { + Res.getCodeGenOpts().MisNoInline = true; + } } if (LangOpts.CUDA) { diff --git a/llvm/include/llvm/Analysis/InlineCost.h b/llvm/include/llvm/Analysis/InlineCost.h --- a/llvm/include/llvm/Analysis/InlineCost.h +++ b/llvm/include/llvm/Analysis/InlineCost.h @@ -101,6 +101,8 @@ /// The cost-benefit pair computed by cost-benefit analysis. Optional CostBenefit = None; + bool IsNoInline = false; + // Trivial constructor, interesting logic in the factory functions below. InlineCost(int Cost, int Threshold, const char *Reason = nullptr, Optional CostBenefit = None) @@ -159,12 +161,17 @@ /// Only valid if the cost is of the variable kind. Returns a negative /// value if the cost is too high to inline. int getCostDelta() const { return Threshold - getCost(); } + + // Set cost is due to function being marked noinline + void setIsNoInline() { IsNoInline = true; } + bool isNoInline() const { return IsNoInline; } }; /// InlineResult is basically true or false. For false results the message /// describes a reason. class InlineResult { const char *Message = nullptr; + bool IsNoInline = false; InlineResult(const char *Message = nullptr) : Message(Message) {} public: @@ -178,6 +185,8 @@ "getFailureReason should only be called in failure cases"); return Message; } + bool isNoInline() const { return IsNoInline; } + void setIsNoInline() { IsNoInline = true; } }; /// Thresholds to tune inline cost analysis. The inline cost analysis decides @@ -292,6 +301,16 @@ CallBase &Call, Function *Callee, TargetTransformInfo &CalleeTTI, function_ref GetTLI); +// Check if a no inline function would have been inlined based on cost decision +InlineCost isInlineViableFromCostAnalysis( + CallBase &Call, Function *Callee, const InlineParams &Params, + TargetTransformInfo &CalleeTTI, + function_ref GetAssumptionCache, + function_ref GetTLI, + function_ref GetBFI = nullptr, + ProfileSummaryInfo *PSI = nullptr, + OptimizationRemarkEmitter *ORE = nullptr); + /// Get the cost estimate ignoring thresholds. This is similar to getInlineCost /// when passed InlineParams::ComputeFullInlineCost, or a non-null ORE. It /// uses default InlineParams otherwise. diff --git a/llvm/include/llvm/IR/DiagnosticInfo.h b/llvm/include/llvm/IR/DiagnosticInfo.h --- a/llvm/include/llvm/IR/DiagnosticInfo.h +++ b/llvm/include/llvm/IR/DiagnosticInfo.h @@ -86,6 +86,7 @@ DK_SrcMgr, DK_DontCall, DK_MisExpect, + DK_MisNoInline, DK_FirstPluginKind // Must be last value to work with // getNextAvailablePluginDiagnosticKind }; @@ -397,7 +398,7 @@ /// Return the absolute path tot the file. std::string getAbsolutePath() const; - + const Function &getFunction() const { return Fn; } DiagnosticLocation getLocation() const { return Loc; } @@ -1052,6 +1053,28 @@ const Twine &Msg; }; +/// Diagnostic information for MisNoInline analysis. +/// Diagnostic information for ISel fallback path. +class DiagnosticInfoMisNoInline : public DiagnosticInfoWithLocationBase { + /// The function that is concerned by this diagnostic. + /// const Twine &Msg; +private: + const Function &Fn; + const Twine &Msg; + +public: + DiagnosticInfoMisNoInline(const Instruction *Inst, const Function &Fn, + Twine &Msg); + const Function &getFunction() const { return Fn; } + + void print(DiagnosticPrinter &DP) const override; + + static bool classof(const DiagnosticInfo *DI) { + return DI->getKind() == DK_MisNoInline; + } + const Twine &getMsg() const { return Msg; } +}; + static DiagnosticSeverity getDiagnosticSeverity(SourceMgr::DiagKind DK) { switch (DK) { case llvm::SourceMgr::DK_Error: diff --git a/llvm/include/llvm/IR/LLVMContext.h b/llvm/include/llvm/IR/LLVMContext.h --- a/llvm/include/llvm/IR/LLVMContext.h +++ b/llvm/include/llvm/IR/LLVMContext.h @@ -207,6 +207,14 @@ void setDiagnosticsMisExpectTolerance(Optional Tolerance); uint32_t getDiagnosticsMisExpectTolerance() const; + /// Return if a code noinline diagnostic needs to be emitted + bool getMisNoInlineWarningRequested() const; + /// Set noinline diagnostic + void setMisNoInlineWarningRequested(bool Requested); + // Get/set for NoInline count threshold + void + setDiagnosticsMisNoInlinePercentileThreshold(Optional Threshold); + uint64_t getDiagnosticsMisNoInlinePercentileThreshold() const; /// Return the minimum hotness value a diagnostic would need in order /// to be included in optimization diagnostics. /// diff --git a/llvm/include/llvm/Target/TargetOptions.h b/llvm/include/llvm/Target/TargetOptions.h --- a/llvm/include/llvm/Target/TargetOptions.h +++ b/llvm/include/llvm/Target/TargetOptions.h @@ -144,7 +144,7 @@ ValueTrackingVariableLocations(false), ForceDwarfFrameSection(false), XRayOmitFunctionIndex(false), DebugStrictDwarf(false), Hotpatch(false), PPCGenScalarMASSEntries(false), JMCInstrument(false), - EnableCFIFixup(false), MisExpect(false), + EnableCFIFixup(false), MisExpect(false), MisNoInline(false), FPDenormalMode(DenormalMode::IEEE, DenormalMode::IEEE) {} /// DisableFramePointerElim - This returns true if frame pointer elimination @@ -364,6 +364,10 @@ /// By default, it is set to false unsigned MisExpect : 1; + /// When set to true, enable MisNoInline Diagnostics + /// By default, it is set to false + unsigned MisNoInline : 1; + /// Name of the stack usage file (i.e., .su file) if user passes /// -fstack-usage. If empty, it can be implied that -fstack-usage is not /// passed on the command line. diff --git a/llvm/lib/Analysis/InlineAdvisor.cpp b/llvm/lib/Analysis/InlineAdvisor.cpp --- a/llvm/lib/Analysis/InlineAdvisor.cpp +++ b/llvm/lib/Analysis/InlineAdvisor.cpp @@ -28,6 +28,7 @@ using namespace llvm; #define DEBUG_TYPE "inline" +#define DEBUG_TYPE_WARN "misnoinline" #ifdef LLVM_HAVE_TF_AOT_INLINERSIZEMODEL #define LLVM_HAVE_TF_AOT #endif @@ -61,6 +62,20 @@ cl::desc("If true, annotate inline advisor remarks " "with LTO and pass information.")); +// Command line option to enable/disable the warning when profile data suggests +// a mismatch with the use of the noinline attribute +static cl::opt PGOWarnMisNoInline( + "pgo-warn-misnoinline", cl::init(false), cl::Hidden, + cl::desc("Use this option to turn on/off " + "warnings about usage of noinline function attribute " + "which may hurt performance.")); + +// Command line opt option to noinline count threshold +static cl::opt MisNoInlinePercent( + "misnoinline-percent", + cl::desc("Prevents emiting diagnostics when function is colder" + "that N percentile of total entry counts.")); + extern cl::opt InlinerFunctionImportStats; namespace { @@ -128,6 +143,64 @@ Advisor->getAnnotatedInlinePassName()); } +static bool canEmitNoInlineWarning(CallBase *CB, InlineCost &IC, + FunctionAnalysisManager &FAM) { + Function &Callee = *CB->getCalledFunction(); + LLVMContext &Ctx = Callee.getContext(); + const char *reason = IC.getReason(); + + // Check if pass remarks, Wmisnoinline or pgo-warn-misnoinline said anything + // about warning + if (!OptimizationRemark(DEBUG_TYPE_WARN, "misnoinline", CB).isEnabled() && + !PGOWarnMisNoInline && !Ctx.getMisNoInlineWarningRequested()) + return false; + // If Callee has no profile data bail out + if (!Callee.hasProfileData()) + return false; + // Failiure reason is due to noinline callee/call site attribute + if (reason == nullptr) + return false; + if (!IC.isNoInline()) + return false; + uint64_t Percent_Threshold; + if (MisNoInlinePercent) + Percent_Threshold = MisNoInlinePercent; + else + Percent_Threshold = Ctx.getDiagnosticsMisNoInlinePercentileThreshold(); + ProfileSummaryInfo *PSI = + FAM.getResult(Callee) + .getCachedResult(*Callee.getParent()); + if (!PSI) + return false; + BlockFrequencyInfo &CalleeBFI = FAM.getResult(Callee); + if (!PSI->isFunctionHotInCallGraphNthPercentile(Percent_Threshold, &Callee, + CalleeBFI)) + return false; + // we have checked all conditions we are safe to + // check for cost and emit warning + return true; +} + +// Emit a noinline diagnostic if: +// 1. Function entry is hotter than the supplied thrshold in terms of total +// entry count +// 2. The noinline function could have been inlined by cost metric. This part is +// checked when normal inlining fails due to noinline attribute +static void emitNoInlineWarning(Function *Callee, Function *Caller, + CallBase *CB) { + llvm::LLVMContext &Ctx = Caller->getContext(); + auto RemStr = + formatv("Marking {0} noinline while calling in {1} " + "may hurt performance as per inline cost/hotness analysis", + Callee->getName(), Caller->getName()); + Twine Msg(RemStr); + if (PGOWarnMisNoInline || Ctx.getMisNoInlineWarningRequested()) + Ctx.diagnose(DiagnosticInfoMisNoInline(CB, *Callee, Msg)); + OptimizationRemarkEmitter ORE(CB->getParent()->getParent()); + ORE.emit(OptimizationRemark(DEBUG_TYPE_WARN, "misnoinline", CB) + << RemStr.str()); +} + llvm::Optional static getDefaultInlineAdvice( CallBase &CB, FunctionAnalysisManager &FAM, const InlineParams &Params) { Function &Caller = *CB.getCaller(); @@ -153,9 +226,23 @@ bool RemarksEnabled = Callee.getContext().getDiagHandlerPtr()->isMissedOptRemarkEnabled( DEBUG_TYPE); - return getInlineCost(CB, Params, CalleeTTI, GetAssumptionCache, GetTLI, - GetBFI, PSI, RemarksEnabled ? &ORE : nullptr); + InlineCost IC = + getInlineCost(CB, Params, CalleeTTI, GetAssumptionCache, GetTLI, GetBFI, + PSI, RemarksEnabled ? &ORE : nullptr); + // Check if we should emit a warning for noinline function + if (LLVM_UNLIKELY(canEmitNoInlineWarning(&CB, IC, FAM))) { + Function &Callee = *CB.getCalledFunction(); + auto &CalleeTTI = FAM.getResult(Callee); + auto TempIC = llvm::isInlineViableFromCostAnalysis( + CB, &Callee, Params, CalleeTTI, GetAssumptionCache, GetTLI, GetBFI, + PSI); + + if (TempIC.isAlways() || TempIC) + emitNoInlineWarning(&Callee, &Caller, &CB); + } + return IC; }; + return llvm::shouldInline( CB, GetInlineCost, ORE, Params.EnableDeferral.value_or(EnableInlineDeferral)); diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp --- a/llvm/lib/Analysis/InlineCost.cpp +++ b/llvm/lib/Analysis/InlineCost.cpp @@ -2919,33 +2919,29 @@ return InlineResult::failure("interposable"); // Don't inline functions marked noinline. - if (Callee->hasFnAttribute(Attribute::NoInline)) - return InlineResult::failure("noinline function attribute"); + if (Callee->hasFnAttribute(Attribute::NoInline)) { + auto IR = InlineResult::failure("noinline function attribute"); + IR.setIsNoInline(); + return IR; + } // Don't inline call sites marked noinline. - if (Call.isNoInline()) - return InlineResult::failure("noinline call site attribute"); + if (Call.isNoInline()) { + auto IR = InlineResult::failure("noinline call site attribute"); + IR.setIsNoInline(); + return IR; + } return None; } -InlineCost llvm::getInlineCost( +InlineCost llvm::isInlineViableFromCostAnalysis( CallBase &Call, Function *Callee, const InlineParams &Params, TargetTransformInfo &CalleeTTI, function_ref GetAssumptionCache, function_ref GetTLI, function_ref GetBFI, ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { - - auto UserDecision = - llvm::getAttributeBasedInliningDecision(Call, Callee, CalleeTTI, GetTLI); - - if (UserDecision) { - if (UserDecision->isSuccess()) - return llvm::InlineCost::getAlways("always inline attribute"); - return llvm::InlineCost::getNever(UserDecision->getFailureReason()); - } - LLVM_DEBUG(llvm::dbgs() << " Analyzing call of " << Callee->getName() << "... (caller:" << Call.getCaller()->getName() << ")\n"); @@ -2976,6 +2972,29 @@ : InlineCost::getNever(ShouldInline.getFailureReason()); } +InlineCost llvm::getInlineCost( + CallBase &Call, Function *Callee, const InlineParams &Params, + TargetTransformInfo &CalleeTTI, + function_ref GetAssumptionCache, + function_ref GetTLI, + function_ref GetBFI, + ProfileSummaryInfo *PSI, OptimizationRemarkEmitter *ORE) { + + auto UserDecision = + llvm::getAttributeBasedInliningDecision(Call, Callee, CalleeTTI, GetTLI); + if (UserDecision) { + if (UserDecision->isSuccess()) + return llvm::InlineCost::getAlways("always inline attribute"); + auto IC = llvm::InlineCost::getNever(UserDecision->getFailureReason()); + if (UserDecision->isNoInline()) + IC.setIsNoInline(); + return IC; + } + return llvm::isInlineViableFromCostAnalysis(Call, Callee, Params, CalleeTTI, + GetAssumptionCache, GetTLI, + GetBFI, PSI, ORE); +} + InlineResult llvm::isInlineViable(Function &F) { bool ReturnsTwice = F.hasFnAttribute(Attribute::ReturnsTwice); for (BasicBlock &BB : F) { diff --git a/llvm/lib/IR/DiagnosticInfo.cpp b/llvm/lib/IR/DiagnosticInfo.cpp --- a/llvm/lib/IR/DiagnosticInfo.cpp +++ b/llvm/lib/IR/DiagnosticInfo.cpp @@ -404,6 +404,19 @@ DP << getLocationStr() << ": " << getMsg(); } +DiagnosticInfoMisNoInline::DiagnosticInfoMisNoInline(const Instruction *Inst, + const Function &Fn, + Twine &Msg) + : DiagnosticInfoWithLocationBase(DK_MisNoInline, DS_Warning, + *Inst->getParent()->getParent(), + Inst->getDebugLoc()), + Fn(Fn), Msg(Msg) {} + +void DiagnosticInfoMisNoInline::print(DiagnosticPrinter &DP) const { + DP << "Module" + << ": " << getFunction().getParent()->getName() << " " << getMsg(); +} + void OptimizationRemarkAnalysisFPCommute::anchor() {} void OptimizationRemarkAnalysisAliasing::anchor() {} diff --git a/llvm/lib/IR/LLVMContext.cpp b/llvm/lib/IR/LLVMContext.cpp --- a/llvm/lib/IR/LLVMContext.cpp +++ b/llvm/lib/IR/LLVMContext.cpp @@ -155,6 +155,19 @@ return pImpl->DiagnosticsMisExpectTolerance.value_or(0); } +void LLVMContext::setMisNoInlineWarningRequested(bool Requested) { + pImpl->MisNoInlineWarningRequested = Requested; +} +bool LLVMContext::getMisNoInlineWarningRequested() const { + return pImpl->MisNoInlineWarningRequested; +} +void LLVMContext::setDiagnosticsMisNoInlinePercentileThreshold( + Optional Count) { + pImpl->DiagnosticsMisNoInlinePercentile = Count; +} +uint64_t LLVMContext::getDiagnosticsMisNoInlinePercentileThreshold() const { + return pImpl->DiagnosticsMisNoInlinePercentile.value_or(0); +} bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { return !pImpl->DiagnosticsHotnessThreshold.has_value(); } diff --git a/llvm/lib/IR/LLVMContextImpl.h b/llvm/lib/IR/LLVMContextImpl.h --- a/llvm/lib/IR/LLVMContextImpl.h +++ b/llvm/lib/IR/LLVMContextImpl.h @@ -1391,6 +1391,11 @@ Optional DiagnosticsMisExpectTolerance = 0; bool MisExpectWarningRequested = false; + /// The percentile of hotness of a function + // when emiting MisNoInline diagnostics + Optional DiagnosticsMisNoInlinePercentile = 990000; + bool MisNoInlineWarningRequested = false; + /// The specialized remark streamer used by LLVM's OptimizationRemarkEmitter. std::unique_ptr LLVMRS;