Skip to content
Merged
Show file tree
Hide file tree
Changes from 14 commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
a05f76f
Add module flag
mingmingl-llvm Oct 7, 2025
f68b06f
[nfc][StaticDataLayout]Add helper functions to tell the eligibility s…
mingmingl-llvm Oct 7, 2025
331888b
save irrelevant change for the next PR to make this one focused
mingmingl-llvm Oct 7, 2025
c56b792
Get rid of section prefix validation in codegen.
mingmingl-llvm Oct 7, 2025
dcb9f00
resolve comments
mingmingl-llvm Oct 7, 2025
3565bc0
add test coverage
mingmingl-llvm Oct 8, 2025
905b80f
simplify test
mingmingl-llvm Oct 8, 2025
95292a6
test coverage for the subsequent patch https://github.com/llvm/llvm-p…
mingmingl-llvm Oct 8, 2025
64be09f
Revert "test coverage for the subsequent patch https://github.com/llv…
mingmingl-llvm Oct 8, 2025
4a90c77
add a minial test case for subsequent PRs to expand on
mingmingl-llvm Oct 8, 2025
3b2f494
Merge branch 'users/mingmingl-llvm/sdpi' into users/mingmingl-llvm/se…
mingmingl-llvm Oct 9, 2025
f9c6266
one liner fix in test
mingmingl-llvm Oct 9, 2025
58bb098
Merge branch 'users/mingmingl-llvm/sdpi' into users/mingmingl-llvm/se…
mingmingl-llvm Oct 9, 2025
90ac67d
test coverage
mingmingl-llvm Oct 9, 2025
34b47c9
simplify switch-break to if-continue
mingmingl-llvm Oct 10, 2025
3756370
Merge branch 'main' into users/mingmingl-llvm/module
mingmingl-llvm Oct 10, 2025
b880ee3
rebase on top of pre-commit test in https://github.com/llvm/llvm-proj…
mingmingl-llvm Oct 10, 2025
41f3d6a
rebase for pre-commit test case in https://github.com/llvm/llvm-proje…
mingmingl-llvm Oct 10, 2025
c6c5311
Merge branch 'main' into users/mingmingl-llvm/setsectionprefix
mingmingl-llvm Oct 13, 2025
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."))
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
15 changes: 2 additions & 13 deletions llvm/lib/CodeGen/StaticDataAnnotator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,22 +75,11 @@ bool StaticDataAnnotator::runOnModule(Module &M) {

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

// The implementation below assumes prior passes don't set section prefixes,
// and specifically do 'assign' rather than 'update'. So report error if a
// section prefix is already set.
if (auto maybeSectionPrefix = GV.getSectionPrefix();
maybeSectionPrefix && !maybeSectionPrefix->empty())
llvm::report_fatal_error("Global variable " + GV.getName() +
" already has a section prefix " +
*maybeSectionPrefix);

StringRef SectionPrefix = SDPI->getConstantSectionPrefix(&GV, PSI);
if (SectionPrefix.empty())
continue;

// setSectionPrefix returns true if the section prefix is updated.
Changed |= GV.setSectionPrefix(SectionPrefix);
}

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) {
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. Subsequent PRs will expand on this test case
;; (e.g., with more functions, variables and profiles) and test the hotness
;; reconcillation implementation.
; RUN: 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=IR

; IR: .section .bss.hot.,"aw"

@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