Skip to content

Commit 887e270

Browse files
[NFCI][Globals]Add GlobalObjects::updateSectionPrefix and change setSectionPrefix to handle empty strings
1 parent bac9e46 commit 887e270

File tree

4 files changed

+105
-1
lines changed

4 files changed

+105
-1
lines changed

llvm/include/llvm/IR/GlobalObject.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,9 +121,14 @@ class GlobalObject : public GlobalValue {
121121
/// appropriate default object file section.
122122
LLVM_ABI void setSection(StringRef S);
123123

124-
/// Set the section prefix for this global object.
124+
/// Set the section prefix for this global object. If \p Prefix is empty,
125+
/// the section prefix metadata will be cleared if it exists.
125126
LLVM_ABI void setSectionPrefix(StringRef Prefix);
126127

128+
/// If \p Prefix is different from existing prefix, update section prefix.
129+
/// Returns true if an update happens and false otherwise.
130+
LLVM_ABI bool updateSectionPrefix(StringRef Prefix);
131+
127132
/// Get the section prefix for this global object.
128133
LLVM_ABI std::optional<StringRef> getSectionPrefix() const;
129134

llvm/lib/IR/Globals.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -289,11 +289,28 @@ void GlobalObject::setSection(StringRef S) {
289289
}
290290

291291
void GlobalObject::setSectionPrefix(StringRef Prefix) {
292+
if (Prefix.empty()) {
293+
setMetadata(LLVMContext::MD_section_prefix, nullptr);
294+
return;
295+
}
292296
MDBuilder MDB(getContext());
293297
setMetadata(LLVMContext::MD_section_prefix,
294298
MDB.createGlobalObjectSectionPrefix(Prefix));
295299
}
296300

301+
bool GlobalObject::updateSectionPrefix(StringRef Prefix) {
302+
auto MD = getMetadata(LLVMContext::MD_section_prefix);
303+
StringRef ExistingPrefix; // Empty by default.
304+
if (MD != nullptr)
305+
ExistingPrefix = cast<MDString>(MD->getOperand(1))->getString();
306+
307+
if (ExistingPrefix != Prefix) {
308+
setSectionPrefix(Prefix);
309+
return true;
310+
}
311+
return false;
312+
}
313+
297314
std::optional<StringRef> GlobalObject::getSectionPrefix() const {
298315
if (MDNode *MD = getMetadata(LLVMContext::MD_section_prefix)) {
299316
[[maybe_unused]] StringRef MDName =

llvm/unittests/IR/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ add_llvm_unittest(IRTests
2828
DominatorTreeBatchUpdatesTest.cpp
2929
DroppedVariableStatsIRTest.cpp
3030
FunctionTest.cpp
31+
GlobalObjectTest.cpp
3132
PassBuilderCallbacksTest.cpp
3233
IRBuilderTest.cpp
3334
InstructionsTest.cpp
Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
//===- GlobalObjectTest.cpp - Global object unit tests --------------------===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "llvm/IR/GlobalObject.h"
10+
#include "llvm-c/Core.h"
11+
#include "llvm/AsmParser/Parser.h"
12+
#include "llvm/IR/Module.h"
13+
#include "llvm/Support/SourceMgr.h"
14+
#include "gtest/gtest.h"
15+
#include "gmock/gmock.h"
16+
using namespace llvm;
17+
namespace {
18+
19+
using testing::Eq;
20+
using testing::Optional;
21+
using testing::StrEq;
22+
23+
static std::unique_ptr<Module> parseIR(LLVMContext &C, const char *IR) {
24+
SMDiagnostic Err;
25+
std::unique_ptr<Module> Mod = parseAssemblyString(IR, Err, C);
26+
if (!Mod)
27+
Err.print("GlobalObjectTests", errs());
28+
return Mod;
29+
}
30+
31+
static LLVMContext C;
32+
static std::unique_ptr<Module> M;
33+
34+
class GlobalObjectTest : public testing::Test {
35+
public:
36+
static void SetUpTestSuite() {
37+
38+
M = parseIR(C, R"(
39+
@foo = global i32 3, !section_prefix !0
40+
@bar = global i32 0
41+
42+
!0 = !{!"section_prefix", !"hot"}
43+
)");
44+
45+
}
46+
47+
};
48+
49+
TEST_F(GlobalObjectTest, SectionPrefix) {
50+
GlobalVariable* Foo = M->getGlobalVariable("foo");
51+
52+
// Initial section prefix is hot.
53+
ASSERT_NE(Foo, nullptr);
54+
ASSERT_THAT(Foo->getSectionPrefix(), Optional(StrEq("hot")));
55+
56+
// No actual update.
57+
EXPECT_FALSE(Foo->updateSectionPrefix("hot"));
58+
59+
// Update prefix from hot to unlikely.
60+
Foo->setSectionPrefix("unlikely");
61+
EXPECT_THAT(Foo->getSectionPrefix(), Optional(StrEq("unlikely")));
62+
63+
// Update prefix to empty is the same as clear.
64+
Foo->setSectionPrefix("");
65+
EXPECT_THAT(Foo->getSectionPrefix(), Eq(std::nullopt));
66+
67+
GlobalVariable* Bar = M->getGlobalVariable("bar");
68+
69+
// Initial section prefix is empty.
70+
ASSERT_NE(Bar, nullptr);
71+
ASSERT_THAT(Bar->getSectionPrefix(), Eq(std::nullopt));
72+
73+
// No actual update.
74+
EXPECT_FALSE(Bar->updateSectionPrefix(""));
75+
76+
// Update from empty to hot.
77+
EXPECT_TRUE(Bar->updateSectionPrefix("hot"));
78+
EXPECT_THAT(Bar->getSectionPrefix(), Optional(StrEq("hot")));
79+
}
80+
81+
} // namespace

0 commit comments

Comments
 (0)