Skip to content
Merged
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions llvm/include/llvm/Analysis/StaticDataProfileInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,24 @@

namespace llvm {

namespace memprof {
// Represents the eligibility status of a global variable for section prefix
// annotation. Other than AnnotationOk, each enum value indicates a specific
// reason for ineligibility.
enum class AnnotationKind : uint8_t {
AnnotationOK,
DeclForLinker,
ExplicitSection,
ReservedName,
};
/// Returns the annotation kind of the global variable \p GV.
AnnotationKind getAnnotationKind(const GlobalVariable &GV);

/// Returns true if the annotation kind of the global variable \p GV is
/// AnnotationOK.
bool IsAnnotationOK(const GlobalVariable &GV);
} // namespace memprof

/// A class that holds the constants that represent static data and their
/// profile information and provides methods to operate on them.
class StaticDataProfileInfo {
Expand Down
40 changes: 40 additions & 0 deletions llvm/lib/Analysis/StaticDataProfileInfo.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,46 @@
#include "llvm/ProfileData/InstrProf.h"

using namespace llvm;

namespace llvm {
namespace memprof {
// Returns true iff the global variable has custom section either by
// __attribute__((section("name")))
// (https://clang.llvm.org/docs/AttributeReference.html#section-declspec-allocate)
// or #pragma clang section directives
// (https://clang.llvm.org/docs/LanguageExtensions.html#specifying-section-names-for-global-objects-pragma-clang-section).
static bool hasExplicitSectionName(const GlobalVariable &GVar) {
if (GVar.hasSection())
return true;

auto Attrs = GVar.getAttributes();
if (Attrs.hasAttribute("bss-section") || Attrs.hasAttribute("data-section") ||
Attrs.hasAttribute("relro-section") ||
Attrs.hasAttribute("rodata-section"))
return true;
return false;
}

AnnotationKind getAnnotationKind(const GlobalVariable &GV) {
if (GV.isDeclarationForLinker())
return AnnotationKind::DeclForLinker;
// Skip 'llvm.'-prefixed global variables conservatively because they are
// often handled specially,
StringRef Name = GV.getName();
if (Name.starts_with("llvm."))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This check is new afaict - so is this NFC?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah sorry, you are correct.

This is from another similar call site [1] and this PR means to cover that one. Updated the PR.

[1]

// Skip 'llvm.'-prefixed global variables conservatively because they are
// often handled specially, and skip those not in static data
// sections.
if (!GV || GV->getName().starts_with("llvm.") ||
!inStaticDataSection(*GV, TM))

return AnnotationKind::ReservedName;
// Respect user-specified custom data sections.
if (hasExplicitSectionName(GV))
return AnnotationKind::ExplicitSection;
return AnnotationKind::AnnotationOK;
}

bool IsAnnotationOK(const GlobalVariable &GV) {
return getAnnotationKind(GV) == AnnotationKind::AnnotationOK;
}
} // namespace memprof
} // namespace llvm

void StaticDataProfileInfo::addConstantProfileCount(
const Constant *C, std::optional<uint64_t> Count) {
if (!Count) {
Expand Down
2 changes: 1 addition & 1 deletion llvm/lib/CodeGen/StaticDataAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ bool StaticDataAnnotator::runOnModule(Module &M) {

bool Changed = false;
for (auto &GV : M.globals()) {
if (GV.isDeclarationForLinker())
if (!llvm::memprof::IsAnnotationOK(GV))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This helper function includes more checks than just isDeclarationForLinker - so is this change really NFC?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah I agree.

I think this PR is more of 'NFCI' (non functional change intended) or no user-visible change intended. I removed the 'NFC' tag so (unfamiliar) readers won't get (unintentionally) fooled..

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But are the effects of this change and the other one I mentioned earlier not observable by tests?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

But are the effects of this change and the other one I mentioned earlier not observable by tests?

Yeah, the test coverage is limited to [1] before. Improved the test coverage now, PTAL, thanks!

[1]

; LOG: Global variable var3 has explicit section name. Skip annotating.
; LOG: Global variable var4 has explicit section name. Skip annotating.

continue;

// The implementation below assumes prior passes don't set section prefixes,
Expand Down
6 changes: 2 additions & 4 deletions llvm/lib/CodeGen/StaticDataSplitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -130,10 +130,8 @@ StaticDataSplitter::getConstant(const MachineOperand &Op,
if (Op.isGlobal()) {
// Find global variables with local linkage.
const GlobalVariable *GV = getLocalLinkageGlobalVariable(Op.getGlobal());
// Skip 'llvm.'-prefixed global variables conservatively because they are
// often handled specially, and skip those not in static data
// sections.
if (!GV || GV->getName().starts_with("llvm.") ||
// Skip those not eligible for annotation or not in static data sections.
if (!GV || !llvm::memprof::IsAnnotationOK(*GV) ||
!inStaticDataSection(*GV, TM))
return nullptr;
return GV;
Expand Down
58 changes: 33 additions & 25 deletions llvm/lib/Transforms/Instrumentation/MemProfUse.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include "llvm/ADT/StringRef.h"
#include "llvm/Analysis/MemoryProfileInfo.h"
#include "llvm/Analysis/OptimizationRemarkEmitter.h"
#include "llvm/Analysis/StaticDataProfileInfo.h"
#include "llvm/Analysis/TargetLibraryInfo.h"
#include "llvm/IR/DiagnosticInfo.h"
#include "llvm/IR/Function.h"
Expand Down Expand Up @@ -194,6 +195,30 @@ static bool isAllocationWithHotColdVariant(const Function *Callee,
}
}

static void HandleUnsupportedAnnotationKinds(GlobalVariable &GVar,
AnnotationKind Kind) {
assert(Kind != llvm::memprof::AnnotationKind::AnnotationOK &&
"Should not handle AnnotationOK here");
SmallString<32> Reason;
switch (Kind) {
case llvm::memprof::AnnotationKind::ExplicitSection:
++NumOfMemProfExplicitSectionGlobalVars;
Reason.append("explicit section name");
break;
case llvm::memprof::AnnotationKind::DeclForLinker:
Reason.append("linker declaration");
break;
case llvm::memprof::AnnotationKind::ReservedName:
Reason.append("name starts with `llvm.`");
break;
default:
llvm_unreachable("Unexpected annotation kind");
}
LLVM_DEBUG(dbgs() << "Skip annotation for " << GVar.getName() << " due to "
<< Reason << ".\n");
return;
}

struct AllocMatchInfo {
uint64_t TotalSize = 0;
AllocationType AllocType = AllocationType::None;
Expand Down Expand Up @@ -775,36 +800,21 @@ PreservedAnalyses MemProfUsePass::run(Module &M, ModuleAnalysisManager &AM) {
return PreservedAnalyses::none();
}

// Returns true iff the global variable has custom section either by
// __attribute__((section("name")))
// (https://clang.llvm.org/docs/AttributeReference.html#section-declspec-allocate)
// or #pragma clang section directives
// (https://clang.llvm.org/docs/LanguageExtensions.html#specifying-section-names-for-global-objects-pragma-clang-section).
static bool hasExplicitSectionName(const GlobalVariable &GVar) {
if (GVar.hasSection())
return true;

auto Attrs = GVar.getAttributes();
if (Attrs.hasAttribute("bss-section") || Attrs.hasAttribute("data-section") ||
Attrs.hasAttribute("relro-section") ||
Attrs.hasAttribute("rodata-section"))
return true;
return false;
}

bool MemProfUsePass::annotateGlobalVariables(
Module &M, const memprof::DataAccessProfData *DataAccessProf) {
if (!AnnotateStaticDataSectionPrefix || M.globals().empty())
return false;

if (!DataAccessProf) {
M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 0U);
M.getContext().diagnose(DiagnosticInfoPGOProfile(
MemoryProfileFileName.data(),
StringRef("Data access profiles not found in memprof. Ignore "
"-memprof-annotate-static-data-prefix."),
DS_Warning));
return false;
}
M.addModuleFlag(Module::Warning, "EnableDataAccessProf", 1U);

bool Changed = false;
// Iterate all global variables in the module and annotate them based on
Expand All @@ -815,13 +825,12 @@ bool MemProfUsePass::annotateGlobalVariables(
for (GlobalVariable &GVar : M.globals()) {
assert(!GVar.getSectionPrefix().has_value() &&
"GVar shouldn't have section prefix yet");
if (GVar.isDeclarationForLinker())
continue;

if (hasExplicitSectionName(GVar)) {
++NumOfMemProfExplicitSectionGlobalVars;
LLVM_DEBUG(dbgs() << "Global variable " << GVar.getName()
<< " has explicit section name. Skip annotating.\n");
auto Kind = llvm::memprof::getAnnotationKind(GVar);
switch (Kind) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Since the switch now only handles 2 cases, this would be clearer written as an if condition like:

if (Kind != llvm::memprof::AnnotationKind::AnnotationOK) {
   HandleUnsupportedAnnotationKinds(GVar, Kind);
   continue;
}

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll resolve this one shortly after.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in 34b47c9

case llvm::memprof::AnnotationKind::AnnotationOK:
break;
default:
HandleUnsupportedAnnotationKinds(GVar, Kind);
continue;
}

Expand All @@ -831,7 +840,6 @@ bool MemProfUsePass::annotateGlobalVariables(
// TODO: Track string content hash in the profiles and compute it inside the
// compiler to categeorize the hotness string literals.
if (Name.starts_with(".str")) {

LLVM_DEBUG(dbgs() << "Skip annotating string literal " << Name << "\n");
continue;
}
Expand Down
42 changes: 42 additions & 0 deletions llvm/test/CodeGen/X86/global-variable-partition-with-dap.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
target datalayout = "e-m:e-p270:32:32-p271:32:32-p272:64:64-i64:64-i128:128-f80:128-n8:16:32:64-S128"
target triple = "x86_64-unknown-linux-gnu"

;; A minimal test case. llc will crash if global variables already has a section
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the behavior of this test affected by this PR? If not, commit it separately as a standalone change.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done in #162938 to pre-commit the test case.

;; prefix. Subsequent PRs will expand on this test case to test the hotness
;; reconcillation implementation.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

s/reconcillation/reconciliation/

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

fixed in #162938 and will rebase the PR that depends on the test.

; RUN: not llc -mtriple=x86_64-unknown-linux-gnu -relocation-model=pic \
; RUN: -partition-static-data-sections=true \
; RUN: -data-sections=true -unique-section-names=false \
; RUN: %s -o - 2>&1 | FileCheck %s --check-prefix=ERR

; ERR: Global variable hot_bss already has a section prefix hot

@hot_bss = internal global i32 0, !section_prefix !17

define void @hot_func() !prof !14 {
%9 = load i32, ptr @hot_bss
%11 = call i32 (...) @func_taking_arbitrary_param(i32 %9)
ret void
}

declare i32 @func_taking_arbitrary_param(...)

!llvm.module.flags = !{!1}

!1 = !{i32 1, !"ProfileSummary", !2}
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
!3 = !{!"ProfileFormat", !"InstrProf"}
!4 = !{!"TotalCount", i64 1460183}
!5 = !{!"MaxCount", i64 849024}
!6 = !{!"MaxInternalCount", i64 32769}
!7 = !{!"MaxFunctionCount", i64 849024}
!8 = !{!"NumCounts", i64 23627}
!9 = !{!"NumFunctions", i64 3271}
!10 = !{!"DetailedSummary", !11}
!11 = !{!12, !13}
!12 = !{i32 990000, i64 166, i32 73}
!13 = !{i32 999999, i64 3, i32 1443}
!14 = !{!"function_entry_count", i64 100000}
!15 = !{!"function_entry_count", i64 1}
!16 = !{!"branch_weights", i32 1, i32 99999}
!17 = !{!"section_prefix", !"hot"}
18 changes: 14 additions & 4 deletions llvm/test/CodeGen/X86/global-variable-partition.ll
Original file line number Diff line number Diff line change
Expand Up @@ -106,23 +106,31 @@ target triple = "x86_64-unknown-linux-gnu"
; UNIQ-NEXT: .section .data.unlikely.,"aw",@progbits,unique,8
; AGG-NEXT: .section .data.unlikely.,"aw",@progbits

;; The `.section` directive is omitted for .data with -unique-section-names=false.
; See MCSectionELF::shouldOmitSectionDirective for the implementation details.

; For @data_with_unknown_hotness
; SYM: .type .Ldata_with_unknown_hotness,@object # @data_with_unknown_hotness
; SYM: .section .data..Ldata_with_unknown_hotness,"aw",@progbits
; UNIQ: .section .data,"aw",@progbits,unique,9
; The `.section` directive is omitted for .data with -unique-section-names=false.
; See MCSectionELF::shouldOmitSectionDirective for the implementation details.

; AGG: .data
; COMMON: .Ldata_with_unknown_hotness:

; For @hot_data_custom_bar_section
; It has an explicit section attribute 'var' and shouldn't have hot or unlikely suffix.
; For variables that are not eligible for section prefix annotation
; COMMON: .type hot_data_custom_bar_section,@object
; SYM-NEXT: .section bar,"aw",@progbits
; SYM: hot_data_custom_bar_section
; UNIQ: .section bar,"aw",@progbits
; AGG: .section bar,"aw",@progbits

; SYM: .section .data.llvm.fake_var,"aw"
; UNIQ: .section .data,"aw"
; AGG: .data

;; No section for linker declaration
; COMMON-NOT: qux

@.str = private unnamed_addr constant [5 x i8] c"hot\09\00", align 1
@.str.1 = private unnamed_addr constant [10 x i8] c"%d\09%d\09%d\0A\00", align 1
@hot_relro_array = internal constant [2 x ptr] [ptr @bss2, ptr @data3]
Expand All @@ -137,6 +145,8 @@ target triple = "x86_64-unknown-linux-gnu"
@data3 = internal global i32 3
@data_with_unknown_hotness = private global i32 5
@hot_data_custom_bar_section = internal global i32 101 #0
@llvm.fake_var = internal global i32 123
@qux = external global i64

define void @cold_func(i32 %0) !prof !15 {
%2 = load i32, ptr @cold_bss
Expand Down
Loading