Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 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
6 changes: 0 additions & 6 deletions llvm/include/llvm/IR/Function.h
Original file line number Diff line number Diff line change
Expand Up @@ -346,12 +346,6 @@ class LLVM_ABI Function : public GlobalObject, public ilist_node<Function> {
/// sample PGO, to enable the same inlines as the profiled optimized binary.
DenseSet<GlobalValue::GUID> getImportGUIDs() const;

/// Set the section prefix for this function.
void setSectionPrefix(StringRef Prefix);

/// Get the section prefix for this function.
std::optional<StringRef> getSectionPrefix() const;

/// hasGC/getGC/setGC/clearGC - The name of the garbage collection algorithm
/// to use during code generation.
bool hasGC() const {
Expand Down
11 changes: 11 additions & 0 deletions llvm/include/llvm/IR/GlobalObject.h
Original file line number Diff line number Diff line change
Expand Up @@ -124,6 +124,17 @@ class GlobalObject : public GlobalValue {
/// appropriate default object file section.
void setSection(StringRef S);

/// Set the section prefix for this global object.
void setSectionPrefix(StringRef Prefix);

/// Update the section prefix, unless the existing prefix is the same as
/// `KeepPrefix`.
void updateSectionPrefix(StringRef Prefix,
std::optional<StringRef> KeepPrefix = std::nullopt);

/// Get the section prefix for this global object.
std::optional<StringRef> getSectionPrefix() const;

bool hasComdat() const { return getComdat() != nullptr; }
const Comdat *getComdat() const { return ObjComdat; }
Comdat *getComdat() { return ObjComdat; }
Expand Down
4 changes: 2 additions & 2 deletions llvm/include/llvm/IR/MDBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -89,8 +89,8 @@ class MDBuilder {
MDNode *createFunctionEntryCount(uint64_t Count, bool Synthetic,
const DenseSet<GlobalValue::GUID> *Imports);

/// Return metadata containing the section prefix for a function.
MDNode *createFunctionSectionPrefix(StringRef Prefix);
/// Return metadata containing the section prefix for a global object.
MDNode *createGlobalObjectSectionPrefix(StringRef Prefix);

/// Return metadata containing the pseudo probe descriptor for a function.
MDNode *createPseudoProbeDesc(uint64_t GUID, uint64_t Hash, StringRef FName);
Expand Down
5 changes: 5 additions & 0 deletions llvm/lib/CodeGen/TargetLoweringObjectFileImpl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -687,6 +687,11 @@ getELFSectionNameForGlobal(const GlobalObject *GO, SectionKind Kind,
raw_svector_ostream(Name) << '.' << *Prefix;
HasPrefix = true;
}
} else if (const auto *GV = dyn_cast<GlobalVariable>(GO)) {
if (std::optional<StringRef> Prefix = GV->getSectionPrefix()) {
raw_svector_ostream(Name) << '.' << *Prefix;
HasPrefix = true;
}
}

if (UniqueSectionName) {
Expand Down
16 changes: 0 additions & 16 deletions llvm/lib/IR/Function.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1164,22 +1164,6 @@ DenseSet<GlobalValue::GUID> Function::getImportGUIDs() const {
return R;
}

void Function::setSectionPrefix(StringRef Prefix) {
MDBuilder MDB(getContext());
setMetadata(LLVMContext::MD_section_prefix,
MDB.createFunctionSectionPrefix(Prefix));
}

std::optional<StringRef> Function::getSectionPrefix() const {
if (MDNode *MD = getMetadata(LLVMContext::MD_section_prefix)) {
assert(cast<MDString>(MD->getOperand(0))->getString() ==
"function_section_prefix" &&
"Metadata not match");
return cast<MDString>(MD->getOperand(1))->getString();
}
return std::nullopt;
}

bool Function::nullPointerIsDefined() const {
return hasFnAttribute(Attribute::NullPointerIsValid);
}
Expand Down
30 changes: 30 additions & 0 deletions llvm/lib/IR/Globals.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@
#include "llvm/IR/GlobalAlias.h"
#include "llvm/IR/GlobalValue.h"
#include "llvm/IR/GlobalVariable.h"
#include "llvm/IR/MDBuilder.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"
Expand Down Expand Up @@ -286,6 +287,35 @@ void GlobalObject::setSection(StringRef S) {
setGlobalObjectFlag(HasSectionHashEntryBit, !S.empty());
}

void GlobalObject::setSectionPrefix(StringRef Prefix) {
MDBuilder MDB(getContext());
setMetadata(LLVMContext::MD_section_prefix,
MDB.createGlobalObjectSectionPrefix(Prefix));
}

void GlobalObject::updateSectionPrefix(StringRef Prefix,

Choose a reason for hiding this comment

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

In the cases that I could find in #125756 we could use something like if (! getSectionPrefix == "hot") setSectionPrefix("unlikely"); instead of this helper. Do we really need a helper for this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Ideally the StaticDataSplitter should be ported to new pass manager to be a module pass, but I'm hoping to do that later.

By then, the data partitioning pass can call setSectionPrefix once per object after walking all functions. I removed this method along with unit tests, and will do the conditional update inside the pass for now.

std::optional<StringRef> KeepPrefix) {
auto SectionPrefix = getSectionPrefix();
if (SectionPrefix && (*SectionPrefix == Prefix ||
(KeepPrefix && *SectionPrefix == *KeepPrefix)))
return;

setSectionPrefix(Prefix);
return;
}

std::optional<StringRef> GlobalObject::getSectionPrefix() const {
if (MDNode *MD = getMetadata(LLVMContext::MD_section_prefix)) {
[[maybe_unused]] StringRef MDName =
cast<MDString>(MD->getOperand(0))->getString();
assert((MDName == "section_prefix" ||
(isa<Function>(this) && MDName == "function_section_prefix")) &&
"Metadata not match");
return cast<MDString>(MD->getOperand(1))->getString();
}
return std::nullopt;
}

bool GlobalValue::isNobuiltinFnDef() const {
const Function *F = dyn_cast<Function>(this);
if (!F || F->empty())
Expand Down
6 changes: 3 additions & 3 deletions llvm/lib/IR/MDBuilder.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -87,9 +87,9 @@ MDNode *MDBuilder::createFunctionEntryCount(
return MDNode::get(Context, Ops);
}

MDNode *MDBuilder::createFunctionSectionPrefix(StringRef Prefix) {
return MDNode::get(
Context, {createString("function_section_prefix"), createString(Prefix)});
MDNode *MDBuilder::createGlobalObjectSectionPrefix(StringRef Prefix) {
return MDNode::get(Context,
{createString("section_prefix"), createString(Prefix)});
}

MDNode *MDBuilder::createRange(const APInt &Lo, const APInt &Hi) {
Expand Down
27 changes: 27 additions & 0 deletions llvm/test/CodeGen/X86/data-section-prefix.ll
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
; RUN: llc -mtriple x86_64-linux-gnu -data-sections %s -o - | FileCheck %s --check-prefix=ELF
; RUN: llc -mtriple x86_64-linux-gnu -unique-section-names=0 -data-sections %s -o - | FileCheck %s --check-prefix=ELF-NOUNIQ

; RUN: llc -mtriple x86_64-windows-msvc -data-sections %s -o - | FileCheck %s --check-prefix=COFF-MSVC

; ELF: .section .data.hot.foo,
; ELF: .section .data.bar,
; ELF: .section .bss.unlikely.baz,
; ELF: .section .bss.quz,

; ELF-NOUNIQ: .section .data.hot.,"aw",@progbits,unique,1
; ELF-NOUNIQ: .section .data,"aw",@progbits,unique,2
; ELF-NOUNIQ: .section .bss.unlikely.,"aw",@nobits,unique,3
; ELF-NOUNIQ: .section .bss,"aw",@nobits,unique,4

; COFF-MSVC: .section .data,"dw",one_only,foo
; COFF-MSVC: .section .data,"dw",one_only,bar
; COFF-MSVC: .section .bss,"bw",one_only,baz
; COFF-MSVC: .section .bss,"bw",one_only,quz

@foo = global i32 1, !section_prefix !0
@bar = global i32 2
@baz = global i32 0, !section_prefix !1
@quz = global i32 0

!0 = !{!"section_prefix", !"hot"}
!1 = !{!"section_prefix", !"unlikely"}
4 changes: 2 additions & 2 deletions llvm/test/Transforms/CodeGenPrepare/X86/section-samplepgo.ll
Original file line number Diff line number Diff line change
Expand Up @@ -34,8 +34,8 @@ define void @cold_func() !prof !16 {
ret void
}

; CHECK: ![[HOT_ID]] = !{!"function_section_prefix", !"hot"}
; CHECK: ![[COLD_ID]] = !{!"function_section_prefix", !"unlikely"}
; CHECK: ![[HOT_ID]] = !{!"section_prefix", !"hot"}
; CHECK: ![[COLD_ID]] = !{!"section_prefix", !"unlikely"}
!llvm.module.flags = !{!1}
!1 = !{i32 1, !"ProfileSummary", !2}
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/CodeGenPrepare/X86/section.ll
Original file line number Diff line number Diff line change
Expand Up @@ -66,8 +66,8 @@ define void @cold_func3() !prof !16 {
ret void
}

; CHECK: ![[HOT_ID]] = !{!"function_section_prefix", !"hot"}
; CHECK: ![[COLD_ID]] = !{!"function_section_prefix", !"unlikely"}
; CHECK: ![[HOT_ID]] = !{!"section_prefix", !"hot"}
; CHECK: ![[COLD_ID]] = !{!"section_prefix", !"unlikely"}
!llvm.module.flags = !{!1}
!1 = !{i32 1, !"ProfileSummary", !2}
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
Expand Down
4 changes: 2 additions & 2 deletions llvm/test/Transforms/HotColdSplit/coldentrycount.ll
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ declare void @sink() cold
; CHECK: define {{.*}} @fun.cold.1{{.*}} ![[PROF:[0-9]+]] {{.*}}section_prefix ![[UNLIKELY:[0-9]+]]

; CHECK: ![[HOTPROF]] = !{!"function_entry_count", i64 100}
; CHECK: ![[LIKELY]] = !{!"function_section_prefix", !"hot"}
; CHECK: ![[LIKELY]] = !{!"section_prefix", !"hot"}
; CHECK: ![[PROF]] = !{!"function_entry_count", i64 0}
; CHECK: ![[UNLIKELY]] = !{!"function_section_prefix", !"unlikely"}
; CHECK: ![[UNLIKELY]] = !{!"section_prefix", !"unlikely"}

!llvm.module.flags = !{!0}
!0 = !{i32 1, !"ProfileSummary", !1}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -36,11 +36,11 @@ attributes #1 = { "use-sample-profile" }

; CHECK: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1}
; CHECK: ![[ZERO_ID]] = !{!"function_entry_count", i64 0}
; CHECK: ![[COLD_ID]] = !{!"function_section_prefix", !"unlikely"}
; CHECK: ![[COLD_ID]] = !{!"section_prefix", !"unlikely"}
; UNKNOWN: ![[NOPROFILE_ID]] = !{!"function_entry_count", i64 -1}
; UNKNOWN: ![[UNKNOWN_ID]] = !{!"function_section_prefix", !"unknown"}
; UNKNOWN: ![[UNKNOWN_ID]] = !{!"section_prefix", !"unknown"}
; ACCURATE: ![[ZERO_ID]] = !{!"function_entry_count", i64 0}
; ACCURATE: ![[COLD_ID]] = !{!"function_section_prefix", !"unlikely"}
; ACCURATE: ![[COLD_ID]] = !{!"section_prefix", !"unlikely"}
!llvm.module.flags = !{!1}
!1 = !{i32 1, !"ProfileSummary", !2}
!2 = !{!3, !4, !5, !6, !7, !8, !9, !10}
Expand Down
1 change: 1 addition & 0 deletions llvm/unittests/IR/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ add_llvm_unittest(IRTests
DominatorTreeBatchUpdatesTest.cpp
DroppedVariableStatsIRTest.cpp
FunctionTest.cpp
GlobalObjectTest.cpp
PassBuilderCallbacksTest.cpp
IRBuilderTest.cpp
InstructionsTest.cpp
Expand Down
56 changes: 56 additions & 0 deletions llvm/unittests/IR/GlobalObjectTest.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
//===- GlobalObjectTest.cpp - Global Object unit tests
//-----------------------------===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "llvm-c/Core.h"
#include "llvm/AsmParser/Parser.h"
#include "llvm/IR/Function.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/SourceMgr.h"
#include "gtest/gtest.h"
using namespace llvm;

namespace {

static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
SMDiagnostic Err;
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
if (!Mod)
Err.print("GlobalObjectTest", errs());
return Mod;
}

} // namespace

TEST(GlobalObjectTest, updateSectionPrefix) {
LLVMContext C;

std::unique_ptr<Module> M = parseIR(C, R"(
@foo = global i32 1, !section_prefix !0
@bar = global i32 2
@baz = global i32 0, !section_prefix !1

!0 = !{!"section_prefix", !"hot"}
!1 = !{!"section_prefix", !"unlikely"}
)");

GlobalVariable *Foo = M->getGlobalVariable("foo");
EXPECT_EQ(Foo->getSectionPrefix(), "hot");
Foo->updateSectionPrefix("unlikely", std::make_optional(StringRef("hot")));
EXPECT_EQ(Foo->getSectionPrefix(), "hot");

GlobalVariable *Bar = M->getGlobalVariable("bar");
EXPECT_EQ(Bar->getSectionPrefix(), std::nullopt);
Bar->setSectionPrefix("unlikely");
EXPECT_EQ(Bar->getSectionPrefix(), "unlikely");

GlobalVariable *Baz = M->getGlobalVariable("baz");
EXPECT_EQ(Baz->getSectionPrefix(), "unlikely");
Baz->updateSectionPrefix("hot");
EXPECT_EQ(Baz->getSectionPrefix(), "hot");
}