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 @@ -346,6 +346,21 @@ const char *Argv0 = nullptr; ArrayRef CommandLineArgs; + /// The minimum hotness value a diagnostic needs in order to be included in + /// optimization diagnostics. + /// + /// The threshold is an Optional value, which maps to one of the 3 states: + /// 1. 0 => threshold disabled. All remarks will be printed. + /// 2. positive int => manual threshold by user. Remarks with hotness exceed + /// threshold will be printed. + /// 3. None => 'auto' threshold by user. The actual value is not + /// available at command line, but will be synced with + /// hotness threshold from profile summary during + /// compilation. + /// + /// If threshold option is not specified, it is disabled by default. + Optional DiagnosticsHotnessThreshold = 0; + 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 @@ -366,10 +366,6 @@ /// Whether to report the hotness of the code region for optimization remarks. CODEGENOPT(DiagnosticsWithHotness, 1, 0) -/// The minimum hotness value a diagnostic needs in order to be included in -/// optimization diagnostics. -VALUE_CODEGENOPT(DiagnosticsHotnessThreshold, 32, 0) - /// Whether copy relocations support is available when building as PIE. CODEGENOPT(PIECopyRelocations, 1, 0) 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 @@ -117,6 +117,8 @@ "unable to execute command: %0">; def err_drv_invalid_darwin_version : Error< "invalid Darwin version number: %0">; +def err_drv_invalid_diagnotics_hotness_threshold : Error< + "invalid argument in '%0', only integer or 'auto' is 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/Driver/Options.td b/clang/include/clang/Driver/Options.td --- a/clang/include/clang/Driver/Options.td +++ b/clang/include/clang/Driver/Options.td @@ -984,8 +984,9 @@ def fdiagnostics_show_hotness : Flag<["-"], "fdiagnostics-show-hotness">, Group, Flags<[CC1Option]>, HelpText<"Enable profile hotness information in diagnostic line">; def fdiagnostics_hotness_threshold_EQ : Joined<["-"], "fdiagnostics-hotness-threshold=">, - Group, Flags<[CC1Option]>, MetaVarName<"">, - HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count">; + Group, Flags<[CC1Option]>, MetaVarName<"">, + HelpText<"Prevent optimization remarks from being output if they do not have at least this profile count. " + "Use 'auto' to apply the threshold from profile summary">; def fdiagnostics_show_option : Flag<["-"], "fdiagnostics-show-option">, Group, HelpText<"Print option name with mappable diagnostics">; def fdiagnostics_show_note_include_stack : Flag<["-"], "fdiagnostics-show-note-include-stack">, 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 @@ -14,6 +14,7 @@ #include "clang/Basic/CommentOptions.h" #include "clang/Basic/DebugInfoOptions.h" #include "clang/Basic/Diagnostic.h" +#include "clang/Basic/DiagnosticDriver.h" #include "clang/Basic/DiagnosticOptions.h" #include "clang/Basic/FileSystemOptions.h" #include "clang/Basic/LLVM.h" @@ -66,6 +67,7 @@ #include "llvm/Option/OptTable.h" #include "llvm/Option/Option.h" #include "llvm/ProfileData/InstrProfReader.h" +#include "llvm/Remarks/HotnessThresholdParser.h" #include "llvm/Support/CodeGen.h" #include "llvm/Support/Compiler.h" #include "llvm/Support/Error.h" @@ -1501,11 +1503,24 @@ Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) << "-fdiagnostics-show-hotness"; - Opts.DiagnosticsHotnessThreshold = getLastArgUInt64Value( - Args, options::OPT_fdiagnostics_hotness_threshold_EQ, 0); - if (Opts.DiagnosticsHotnessThreshold > 0 && !UsingProfile) - Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) - << "-fdiagnostics-hotness-threshold="; + // Parse remarks hotness threshold. Valid value is either integer or 'auto'. + if (auto *arg = + Args.getLastArg(options::OPT_fdiagnostics_hotness_threshold_EQ)) { + auto ResultOrErr = + llvm::remarks::parseHotnessThresholdOption(arg->getValue()); + + if (!ResultOrErr) { + Diags.Report(diag::err_drv_invalid_diagnotics_hotness_threshold) + << "-fdiagnostics-hotness-threshold="; + } else { + Opts.DiagnosticsHotnessThreshold = *ResultOrErr; + if ((!Opts.DiagnosticsHotnessThreshold.hasValue() || + Opts.DiagnosticsHotnessThreshold.getValue() > 0) && + !UsingProfile) + Diags.Report(diag::warn_drv_diagnostics_hotness_requires_pgo) + << "-fdiagnostics-hotness-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 diff --git a/clang/test/Driver/opt-record.c b/clang/test/Driver/opt-record.c --- a/clang/test/Driver/opt-record.c +++ b/clang/test/Driver/opt-record.c @@ -51,6 +51,7 @@ // RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=gold -flto -fdiagnostics-hotness-threshold=100 -fsave-optimization-record -foptimization-record-passes=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS // RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -fsave-optimization-record=some-format -foptimization-record-file=FOO.txt %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-CUSTOM // RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=100 -Rpass=inline -Rpass-missed=inline -Rpass-analysis=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-RPASS +// RUN: %clang -target x86_64-linux -### -o FOO -fuse-ld=lld -flto=thin -fdiagnostics-hotness-threshold=auto -Rpass=inline -Rpass-missed=inline -Rpass-analysis=inline %s 2>&1 | FileCheck %s -check-prefix=CHECK-PASS-AUTO // CHECK-NOPASS-NOT: "--plugin-opt=opt-remarks-filename=" // CHECK-NOPASS-NOT: "--plugin-opt=opt-remarks-passes=inline" @@ -75,3 +76,5 @@ // CHECK-PASS-RPASS-SAME: "--plugin-opt=-pass-remarks-missed=inline" // CHECK-PASS-RPASS-SAME: "--plugin-opt=-pass-remarks-analysis=inline" // CHECK-PASS-RPASS-SAME: "--plugin-opt=opt-remarks-hotness-threshold=100" + +// CHECK-PASS-AUTO: "--plugin-opt=opt-remarks-hotness-threshold=auto" diff --git a/clang/test/Frontend/Inputs/remarks-hotness.prof b/clang/test/Frontend/Inputs/remarks-hotness.prof new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/Inputs/remarks-hotness.prof @@ -0,0 +1,8 @@ +_Z7callee1v:600:600 + 1: 600 +_Z7callee2v:1:1 + 1: 1 +_Z7caller1v:400:400 + 1: 400 +_Z7caller2v:1:1 + 1: 1 diff --git a/clang/test/Frontend/remarks-hotness.cpp b/clang/test/Frontend/remarks-hotness.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Frontend/remarks-hotness.cpp @@ -0,0 +1,34 @@ +// Without hotness threshold, print both hot and cold remarks. +// RUN: %clang_cc1 -triple x86_64-linux %s -emit-llvm-only -O3 \ +// RUN: -fprofile-sample-use=%S/Inputs/remarks-hotness.prof \ +// RUN: -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline \ +// RUN: -fexperimental-new-pass-manager -fdiagnostics-show-hotness 2>&1 \ +// RUN: | FileCheck -check-prefix=REMARKS %s + +// With auto hotness threshold, only print hot remarks. +// RUN: %clang_cc1 -triple x86_64-linux %s -emit-llvm-only -O3 \ +// RUN: -fprofile-sample-use=%S/Inputs/remarks-hotness.prof \ +// RUN: -Rpass=inline -Rpass-analysis=inline -Rpass-missed=inline \ +// RUN: -fexperimental-new-pass-manager -fdiagnostics-show-hotness \ +// RUN: -fdiagnostics-hotness-threshold=auto 2>&1 \ +// RUN: | FileCheck -check-prefix=HOT_CALL %s + +int callee1() { + return 1; +} + +__attribute__((noinline)) int callee2() { + return 2; +} + +// REMARKS: _Z7callee1v inlined into _Z7caller1v +// HOT_CALL: _Z7callee1v inlined into _Z7caller1v +int caller1() { + return callee1(); +} + +// REMARKS: _Z7callee2v not inlined into _Z7caller2v +// HOT_CALL-NOT: _Z7callee2v not inlined into _Z7caller2v +int caller2() { + return callee2(); +} diff --git a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h --- a/llvm/include/llvm/Analysis/ProfileSummaryInfo.h +++ b/llvm/include/llvm/Analysis/ProfileSummaryInfo.h @@ -38,7 +38,7 @@ // units. This would require making this depend on BFI. class ProfileSummaryInfo { private: - Module &M; + const Module &M; std::unique_ptr Summary; void computeThresholds(); // Count thresholds to answer isHotCount and isColdCount queries. @@ -58,7 +58,8 @@ mutable DenseMap ThresholdCache; public: - ProfileSummaryInfo(Module &M) : M(M) { refresh(); } + ProfileSummaryInfo(const Module &M) : M(M) { refresh(); } + ProfileSummaryInfo(ProfileSummaryInfo &&Arg) = default; /// If no summary is present, attempt to refresh. 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 @@ -237,6 +237,9 @@ /// included in optimization diagnostics. void setDiagnosticsHotnessThreshold(Optional Threshold); + /// Return if hotness threshold is requested from PSI. + bool isDiagnosticsHotnessThresholdSetFromPSI() const; + /// The "main remark streamer" used by all the specialized remark streamers. /// This streamer keeps generic remark metadata in memory throughout the life /// of the LLVMContext. This metadata may be emitted in a section in object diff --git a/llvm/include/llvm/IR/Module.h b/llvm/include/llvm/IR/Module.h --- a/llvm/include/llvm/IR/Module.h +++ b/llvm/include/llvm/IR/Module.h @@ -850,7 +850,7 @@ /// Returns profile summary metadata. When IsCS is true, use the context /// sensitive profile summary. - Metadata *getProfileSummary(bool IsCS); + Metadata *getProfileSummary(bool IsCS) const; /// @} /// Returns whether semantic interposition is to be respected. diff --git a/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp b/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp --- a/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp +++ b/llvm/lib/Analysis/OptimizationRemarkEmitter.cpp @@ -15,6 +15,7 @@ #include "llvm/Analysis/BranchProbabilityInfo.h" #include "llvm/Analysis/LazyBlockFrequencyInfo.h" #include "llvm/Analysis/LoopInfo.h" +#include "llvm/Analysis/ProfileSummaryInfo.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/Dominators.h" #include "llvm/IR/LLVMContext.h" @@ -96,9 +97,17 @@ bool OptimizationRemarkEmitterWrapperPass::runOnFunction(Function &Fn) { BlockFrequencyInfo *BFI; - if (Fn.getContext().getDiagnosticsHotnessRequested()) + auto &Context = Fn.getContext(); + if (Context.getDiagnosticsHotnessRequested()) { BFI = &getAnalysis().getBFI(); - else + // Get hotness threshold from PSI. This should only happen once. + if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) { + if (ProfileSummaryInfo *PSI = + &getAnalysis().getPSI()) + Context.setDiagnosticsHotnessThreshold( + PSI->getOrCompHotCountThreshold()); + } + } else BFI = nullptr; ORE = std::make_unique(&Fn, BFI); @@ -108,6 +117,7 @@ void OptimizationRemarkEmitterWrapperPass::getAnalysisUsage( AnalysisUsage &AU) const { LazyBlockFrequencyInfoPass::getLazyBFIAnalysisUsage(AU); + AU.addRequired(); AU.setPreservesAll(); } @@ -117,10 +127,19 @@ OptimizationRemarkEmitterAnalysis::run(Function &F, FunctionAnalysisManager &AM) { BlockFrequencyInfo *BFI; + auto &Context = F.getContext(); - if (F.getContext().getDiagnosticsHotnessRequested()) + if (Context.getDiagnosticsHotnessRequested()) { BFI = &AM.getResult(F); - else + // Get hotness threshold from PSI. This should only happen once. + if (Context.isDiagnosticsHotnessThresholdSetFromPSI()) { + auto &MAMProxy = AM.getResult(F); + if (ProfileSummaryInfo *PSI = + MAMProxy.getCachedResult(*F.getParent())) + Context.setDiagnosticsHotnessThreshold( + PSI->getOrCompHotCountThreshold()); + } + } else BFI = nullptr; return OptimizationRemarkEmitter(&F, BFI); @@ -133,5 +152,6 @@ INITIALIZE_PASS_BEGIN(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name, false, true) INITIALIZE_PASS_DEPENDENCY(LazyBFIPass) +INITIALIZE_PASS_DEPENDENCY(ProfileSummaryInfoWrapperPass) INITIALIZE_PASS_END(OptimizationRemarkEmitterWrapperPass, ORE_NAME, ore_name, false, true) 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 @@ -149,10 +149,15 @@ void LLVMContext::setDiagnosticsHotnessThreshold(Optional Threshold) { pImpl->DiagnosticsHotnessThreshold = Threshold; } + uint64_t LLVMContext::getDiagnosticsHotnessThreshold() const { return pImpl->DiagnosticsHotnessThreshold.getValueOr(UINT64_MAX); } +bool LLVMContext::isDiagnosticsHotnessThresholdSetFromPSI() const { + return !pImpl->DiagnosticsHotnessThreshold.hasValue(); +} + remarks::RemarkStreamer *LLVMContext::getMainRemarkStreamer() { return pImpl->MainRemarkStreamer.get(); } diff --git a/llvm/lib/IR/LLVMRemarkStreamer.cpp b/llvm/lib/IR/LLVMRemarkStreamer.cpp --- a/llvm/lib/IR/LLVMRemarkStreamer.cpp +++ b/llvm/lib/IR/LLVMRemarkStreamer.cpp @@ -96,8 +96,7 @@ if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); - if (RemarksHotnessThreshold) - Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); + Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); if (RemarksFilename.empty()) return nullptr; @@ -144,8 +143,7 @@ if (RemarksWithHotness) Context.setDiagnosticsHotnessRequested(true); - if (RemarksHotnessThreshold) - Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); + Context.setDiagnosticsHotnessThreshold(RemarksHotnessThreshold); Expected Format = remarks::parseFormat(RemarksFormat); if (Error E = Format.takeError()) diff --git a/llvm/lib/IR/Module.cpp b/llvm/lib/IR/Module.cpp --- a/llvm/lib/IR/Module.cpp +++ b/llvm/lib/IR/Module.cpp @@ -582,7 +582,7 @@ setModuleFlag(ModFlagBehavior::Error, "ProfileSummary", M); } -Metadata *Module::getProfileSummary(bool IsCS) { +Metadata *Module::getProfileSummary(bool IsCS) const { return (IsCS ? getModuleFlag("CSProfileSummary") : getModuleFlag("ProfileSummary")); } diff --git a/llvm/test/Other/optimization-remarks-auto.ll b/llvm/test/Other/optimization-remarks-auto.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Other/optimization-remarks-auto.ll @@ -0,0 +1,85 @@ +;; This test verifies 'auto' hotness threshold when profile summary is available. +;; +;; new PM +; RUN: rm -f %t.yaml %t.hot.yaml +; RUN: opt < %s --disable-output --enable-new-pm \ +; RUN: --passes='inline' \ +; RUN: --pass-remarks-output=%t.yaml --pass-remarks-filter='inline' \ +; RUN: --pass-remarks-with-hotness +; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.yaml +; RUN: FileCheck %s -check-prefix=YAML-MISS < %t.yaml + +;; test 'auto' threshold +; RUN: opt < %s --disable-output --enable-new-pm \ +; RUN: --passes='module(print-profile-summary,cgscc(inline))' \ +; RUN: --pass-remarks-output=%t.hot.yaml --pass-remarks-filter='inline' \ +; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto 2>&1 | FileCheck %s +; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.hot.yaml +; RUN: not FileCheck %s -check-prefix=YAML-MISS < %t.hot.yaml + +; RUN: opt < %s --disable-output --enable-new-pm \ +; RUN: --passes='module(print-profile-summary,cgscc(inline))' \ +; RUN: --pass-remarks=inline --pass-remarks-missed=inline --pass-remarks-analysis=inline \ +; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto 2>&1 | FileCheck %s -check-prefix=CHECK-RPASS + +; YAML-PASS: --- !Passed +; YAML-PASS-NEXT: Pass: inline +; YAML-PASS-NEXT: Name: Inlined +; YAML-PASS-NEXT: Function: caller1 +; YAML-PASS-NEXT: Hotness: 400 + +; YAML-MISS: --- !Missed +; YAML-MISS-NEXT: Pass: inline +; YAML-MISS-NEXT: Name: NeverInline +; YAML-MISS-NEXT: Function: caller2 +; YAML-MISS-NEXT: Hotness: 1 + +; CHECK-RPASS: callee1 inlined into caller1 with (cost=-30, threshold=4500) (hotness: 400) +; CHECK-RPASS-NOT: callee2 not inlined into caller2 because it should never be inlined (cost=never): noinline function attribute (hotness: 1) + +define void @callee1() !prof !20 { +; CHECK: callee1 :hot +entry: + ret void +} + +; Function Attrs: noinline +define void @callee2() noinline !prof !21 { +; CHECK: callee2 :cold +entry: + ret void +} + +define void @caller1() !prof !20 { +; CHECK: caller1 :hot +entry: + call void @callee1() + ret void +} + +define void @caller2() !prof !21 { +; CHECK: caller2 :cold +entry: + call void @callee2() + ret void +} + +!llvm.module.flags = !{!1} +!20 = !{!"function_entry_count", i64 400} +!21 = !{!"function_entry_count", i64 1} + +!1 = !{i32 1, !"ProfileSummary", !2} +!2 = !{!3, !4, !5, !6, !7, !8, !9, !10} +!3 = !{!"ProfileFormat", !"InstrProf"} +!4 = !{!"TotalCount", i64 10000} +!5 = !{!"MaxCount", i64 10} +!6 = !{!"MaxInternalCount", i64 1} +!7 = !{!"MaxFunctionCount", i64 1000} +!8 = !{!"NumCounts", i64 3} +!9 = !{!"NumFunctions", i64 3} +!10 = !{!"DetailedSummary", !11} +!11 = !{!12, !13, !14} +!12 = !{i32 10000, i64 100, i32 1} +!13 = !{i32 999000, i64 100, i32 1} +!14 = !{i32 999999, i64 1, i32 2} + diff --git a/llvm/test/Transforms/SampleProfile/Inputs/remarks-hotness.prof b/llvm/test/Transforms/SampleProfile/Inputs/remarks-hotness.prof new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SampleProfile/Inputs/remarks-hotness.prof @@ -0,0 +1,8 @@ +_Z7callee1v:600:600 + 1: 600 +_Z7callee2v:1:1 + 1: 1 +_Z7caller1v:400:400 + 1: 400 +_Z7caller2v:1:1 + 1: 1 diff --git a/llvm/test/Transforms/SampleProfile/remarks-hotness.ll b/llvm/test/Transforms/SampleProfile/remarks-hotness.ll new file mode 100644 --- /dev/null +++ b/llvm/test/Transforms/SampleProfile/remarks-hotness.ll @@ -0,0 +1,96 @@ +;; This test verifies 'auto' hotness threshold when profile file is provided. +;; +;; new PM +; RUN: rm -f %t.yaml %t.hot.yaml +; RUN: opt %s --enable-new-pm --passes='sample-profile,cgscc(inline)' \ +; RUN: --sample-profile-file=%S/Inputs/remarks-hotness.prof \ +; RUN: -S --pass-remarks-filter=inline --pass-remarks-output=%t.yaml \ +; RUN: -pass-remarks-with-hotness --disable-output +; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.yaml +; RUN: FileCheck %s -check-prefix=YAML-MISS < %t.yaml + +;; test 'auto' threshold +; RUN: opt %s --enable-new-pm --passes='sample-profile,cgscc(inline)' \ +; RUN: --sample-profile-file=%S/Inputs/remarks-hotness.prof \ +; RUN: -S --pass-remarks-filter=inline --pass-remarks-output=%t.hot.yaml \ +; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto --disable-output +; RUN: FileCheck %s -check-prefix=YAML-PASS < %t.hot.yaml +; RUN: not FileCheck %s -check-prefix=YAML-MISS < %t.hot.yaml + +; RUN: opt %s --enable-new-pm --passes='sample-profile,cgscc(inline)' \ +; RUN: --sample-profile-file=%S/Inputs/remarks-hotness.prof \ +; RUN: -S --pass-remarks=inline --pass-remarks-missed=inline --pass-remarks-analysis=inline \ +; RUN: --pass-remarks-with-hotness --pass-remarks-hotness-threshold=auto --disable-output 2>&1 | FileCheck %s -check-prefix=CHECK-RPASS + +; YAML-PASS: --- !Passed +; YAML-PASS-NEXT: Pass: inline +; YAML-PASS-NEXT: Name: Inlined +; YAML-PASS-NEXT: DebugLoc: { File: remarks-hotness.cpp, Line: 10, Column: 10 } +; YAML-PASS-NEXT: Function: _Z7caller1v +; YAML-PASS-NEXT: Hotness: 401 + +; YAML-MISS: --- !Missed +; YAML-MISS-NEXT: Pass: inline +; YAML-MISS-NEXT: Name: NeverInline +; YAML-MISS-NEXT: DebugLoc: { File: remarks-hotness.cpp, Line: 14, Column: 10 } +; YAML-MISS-NEXT: Function: _Z7caller2v +; YAML-MISS-NEXT: Hotness: 2 + +; CHECK-RPASS: _Z7callee1v inlined into _Z7caller1v with (cost=-30, threshold=4500) at callsite _Z7caller1v:1 (hotness: 401) +; CHECK-RPASS-NOT: _Z7callee2v not inlined into _Z7caller2v because it should never be inlined (cost=never): noinline function attribute (hotness: 2) + +; ModuleID = 'remarks-hotness.cpp' +source_filename = "remarks-hotness.cpp" +target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-f80:128-n8:16:32:64-S128" +target triple = "x86_64-unknown-linux-gnu" + +; Function Attrs: use-sample-profile +define dso_local i32 @_Z7callee1v() #0 !dbg !7 { + ret i32 1, !dbg !11 +} + +; Function Attrs: noinline nounwind uwtable use-sample-profile +define dso_local i32 @_Z7callee2v() #1 !dbg !12 { + ret i32 2, !dbg !13 +} + +; Function Attrs: use-sample-profile +define dso_local i32 @_Z7caller1v() #0 !dbg !14 { + %1 = call i32 @_Z7callee1v(), !dbg !15 + ret i32 %1, !dbg !16 +} + +; Function Attrs: use-sample-profile +define dso_local i32 @_Z7caller2v() #0 !dbg !17 { + %1 = call i32 @_Z7callee2v(), !dbg !18 + ret i32 %1, !dbg !19 +} + +attributes #0 = { "use-sample-profile" } +attributes #1 = { noinline nounwind uwtable "use-sample-profile" } + +!llvm.dbg.cu = !{!0} +!llvm.module.flags = !{!3, !4, !5} +!llvm.ident = !{!6} + +!0 = distinct !DICompileUnit(language: DW_LANG_C_plus_plus_14, file: !1, isOptimized: false, runtimeVersion: 0, emissionKind: FullDebug, enums: !2, splitDebugInlining: false, debugInfoForProfiling: true, nameTableKind: None) +!1 = !DIFile(filename: "remarks-hotness.cpp", directory: ".") +!2 = !{} +!3 = !{i32 7, !"Dwarf Version", i32 4} +!4 = !{i32 2, !"Debug Info Version", i32 3} +!5 = !{i32 1, !"wchar_size", i32 4} +!6 = !{!"clang version 11.0.0"} +!7 = distinct !DISubprogram(name: "callee1", linkageName: "_Z7callee1v", scope: !1, file: !1, line: 1, type: !8, scopeLine: 1, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!8 = !DISubroutineType(types: !9) +!9 = !{!10} +!10 = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed) +!11 = !DILocation(line: 2, column: 3, scope: !7) +!12 = distinct !DISubprogram(name: "callee2", linkageName: "_Z7callee2v", scope: !1, file: !1, line: 5, type: !8, scopeLine: 5, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!13 = !DILocation(line: 6, column: 3, scope: !12) +!14 = distinct !DISubprogram(name: "caller1", linkageName: "_Z7caller1v", scope: !1, file: !1, line: 9, type: !8, scopeLine: 9, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!15 = !DILocation(line: 10, column: 10, scope: !14) +!16 = !DILocation(line: 10, column: 3, scope: !14) +!17 = distinct !DISubprogram(name: "caller2", linkageName: "_Z7caller2v", scope: !1, file: !1, line: 13, type: !8, scopeLine: 13, flags: DIFlagPrototyped, spFlags: DISPFlagDefinition, unit: !0, retainedNodes: !2) +!18 = !DILocation(line: 14, column: 10, scope: !17) +!19 = !DILocation(line: 14, column: 3, scope: !17) +