Index: include/llvm/Analysis/ProfileSummaryInfo.h =================================================================== --- include/llvm/Analysis/ProfileSummaryInfo.h +++ include/llvm/Analysis/ProfileSummaryInfo.h @@ -102,8 +102,11 @@ bool isFunctionHotInCallGraph(const Function *F, BlockFrequencyInfo &BFI); /// Returns true if \p F has cold function entry. bool isFunctionEntryCold(const Function *F); - /// Returns true if \p F contains only cold code. - bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI); + /// Returns true if \p F contains only cold code. If returns false, + /// IsUnknown will tell whether the function is not cold for sure or + /// just unknown. + bool isFunctionColdInCallGraph(const Function *F, BlockFrequencyInfo &BFI, + bool &IsUnknown); /// Returns true if count \p C is considered hot. bool isHotCount(uint64_t C); /// Returns true if count \p C is considered cold. Index: lib/Analysis/ProfileSummaryInfo.cpp =================================================================== --- lib/Analysis/ProfileSummaryInfo.cpp +++ lib/Analysis/ProfileSummaryInfo.cpp @@ -164,12 +164,16 @@ /// If it returns false, it either means it is not cold or it is unknown /// (for example, no profile data is available). bool ProfileSummaryInfo::isFunctionColdInCallGraph(const Function *F, - BlockFrequencyInfo &BFI) { + BlockFrequencyInfo &BFI, + bool &IsUnknown) { if (!F || !computeSummary()) return false; - if (auto FunctionCount = F->getEntryCount()) + IsUnknown = true; + if (auto FunctionCount = F->getEntryCount()) { + IsUnknown = false; if (!isColdCount(FunctionCount.getCount())) return false; + } if (hasSampleProfile()) { uint64_t TotalCallCount = 0; Index: lib/CodeGen/CodeGenPrepare.cpp =================================================================== --- lib/CodeGen/CodeGenPrepare.cpp +++ lib/CodeGen/CodeGenPrepare.cpp @@ -173,6 +173,17 @@ "profile-guided-section-prefix", cl::Hidden, cl::init(true), cl::ZeroOrMore, cl::desc("Use profile info to add section prefix for hot/cold functions")); +static cl::opt ProfileUnknownInSpecialSection( + "profile-unknown-in-special-section", cl::Hidden, cl::init(false), + cl::ZeroOrMore, + cl::desc("When profile info is used to add section prefix for hot/cold " + "functions. In sample profile, we cannot tell a function is " + "cold for sure if we don't have profile unless " + "option profile-sample-accurate is used, because it is possible " + "that the function lacking profile is newly created. With the " + "option, the function with its hot/cold being unknown will be " + "put in a special section instead of '.text' section. ")); + static cl::opt FreqRatioToSkipMerge( "cgp-freq-ratio-to-skip-merge", cl::Hidden, cl::init(2), cl::desc("Skip merging empty blocks if (frequency of empty block) / " @@ -432,10 +443,13 @@ ProfileSummaryInfo *PSI = &getAnalysis().getPSI(); if (ProfileGuidedSectionPrefix) { + bool IsUnknown = false; if (PSI->isFunctionHotInCallGraph(&F, *BFI)) F.setSectionPrefix(".hot"); - else if (PSI->isFunctionColdInCallGraph(&F, *BFI)) + else if (PSI->isFunctionColdInCallGraph(&F, *BFI, IsUnknown)) F.setSectionPrefix(".unlikely"); + else if (ProfileUnknownInSpecialSection && IsUnknown) + F.setSectionPrefix(".unknown"); } /// This optimization identifies DIV instructions that can be Index: lib/Transforms/Utils/SizeOpts.cpp =================================================================== --- lib/Transforms/Utils/SizeOpts.cpp +++ lib/Transforms/Utils/SizeOpts.cpp @@ -25,7 +25,9 @@ assert(F); if (!PSI || !BFI || !PSI->hasProfileSummary()) return false; - return ProfileGuidedSizeOpt && PSI->isFunctionColdInCallGraph(F, *BFI); + bool IsUnknown; + return ProfileGuidedSizeOpt && + PSI->isFunctionColdInCallGraph(F, *BFI, IsUnknown); } bool llvm::shouldOptimizeForSize(BasicBlock *BB, ProfileSummaryInfo *PSI, Index: test/Transforms/SampleProfile/section-accurate-samplepgo.ll =================================================================== --- test/Transforms/SampleProfile/section-accurate-samplepgo.ll +++ test/Transforms/SampleProfile/section-accurate-samplepgo.ll @@ -1,4 +1,5 @@ ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -S | FileCheck %s +; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -profile-unknown-in-special-section -S | FileCheck %s --check-prefix UNKNOWN ; RUN: opt < %s -sample-profile -sample-profile-file=%S/Inputs/inline.prof -codegenprepare -profile-sample-accurate -S | FileCheck %s --check-prefix ACCURATE target triple = "x86_64-pc-linux-gnu" @@ -10,7 +11,8 @@ declare void @hot_func() ; CHECK-NOT: foo_not_in_profile{{.*}}!section_prefix -; CHECK: foo_not_in_profile{{.*}}!prof ![[UNKNOWN_ID:[0-9]+]] +; CHECK: foo_not_in_profile{{.*}}!prof ![[NOPROFILE_ID:[0-9]+]] +; UNKNOWN: foo_not_in_profile{{.*}}!prof ![[NOPROFILE_ID:[0-9]+]] !section_prefix ![[UNKNOWN_ID:[0-9]+]] ; ACCURATE: foo_not_in_profile{{.*}}!prof ![[ZERO_ID:[0-9]+]] !section_prefix ![[COLD_ID:[0-9]+]] ; The function not appearing in profile is cold when -profile-sample-accurate ; is on. @@ -30,9 +32,11 @@ attributes #0 = { "profile-sample-accurate" } -; CHECK: ![[UNKNOWN_ID]] = !{!"function_entry_count", i64 -1} +; CHECK: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1} ; CHECK: ![[ZERO_ID]] = !{!"function_entry_count", i64 0} ; CHECK: ![[COLD_ID]] = !{!"function_section_prefix", !".unlikely"} +; UNKNOWN: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1} +; UNKNOWN: ![[UNKNOWN_ID]] = !{!"function_section_prefix", !".unknown"} ; ACCURATE: ![[ZERO_ID]] = !{!"function_entry_count", i64 0} ; ACCURATE: ![[COLD_ID]] = !{!"function_section_prefix", !".unlikely"} !llvm.module.flags = !{!1}