[llvm] [BOLT] Fix code section ordering comparator (PR #216725)
Alexander Wilson via llvm-commits
llvm-commits at lists.llvm.org
Mon Aug 17 06:14:45 PDT 2026
https://github.com/rdtscp created https://github.com/llvm/llvm-project/pull/216725
RewriteInstance::getCodeSections() used a comparator that did not form a strict weak ordering. Distinct sections with identical special names could compare less than each other, while cold and other sections had a non-transitive equivalence relation.
Assign explicit ranks to BOLT code section kinds. For --hot-functions-at-end, also place injected functions before ordinary cold functions in the output function list so emission order remains synchronized with physical section order.
Add direct getCodeSections() and ordering-property unit tests, plus an end-to-end hugify and split-functions layout regression.
Assisted-by: Codex
>From b5bb18dbf64ae31e3efae50aa0b3570aaf311361 Mon Sep 17 00:00:00 2001
From: Alexander Wilson <rdtscp at meta.com>
Date: Fri, 14 Aug 2026 10:48:36 -0700
Subject: [PATCH] [BOLT] Fix code section ordering comparator
RewriteInstance::getCodeSections() used a comparator that did not form a
strict weak ordering. Distinct sections with identical special names
could compare less than each other, while cold and other sections had a
non-transitive equivalence relation.
Assign explicit ranks to BOLT code section kinds. For
--hot-functions-at-end, also place injected functions before ordinary
cold functions in the output function list so emission order remains
synchronized with physical section order.
Add direct getCodeSections() and ordering-property unit tests, plus an
end-to-end hugify and split-functions layout regression.
Assisted-by: Codex
---
bolt/include/bolt/Rewrite/RewriteInstance.h | 33 +++
bolt/lib/Passes/BinaryPasses.cpp | 15 +-
bolt/lib/Rewrite/RewriteInstance.cpp | 117 +++++----
bolt/test/X86/code-section-order-injected.s | 43 ++++
bolt/unittests/Core/CMakeLists.txt | 1 +
bolt/unittests/Core/RewriteInstance.cpp | 252 ++++++++++++++++++++
6 files changed, 412 insertions(+), 49 deletions(-)
create mode 100644 bolt/test/X86/code-section-order-injected.s
create mode 100644 bolt/unittests/Core/RewriteInstance.cpp
diff --git a/bolt/include/bolt/Rewrite/RewriteInstance.h b/bolt/include/bolt/Rewrite/RewriteInstance.h
index a624c056ada14..5250b5c2ee4da 100644
--- a/bolt/include/bolt/Rewrite/RewriteInstance.h
+++ b/bolt/include/bolt/Rewrite/RewriteInstance.h
@@ -36,6 +36,38 @@ class BoltAddressTranslation;
class CFIReaderWriter;
class DWARFRewriter;
class ProfileReaderBase;
+class RewriteInstanceTest;
+
+namespace detail {
+
+/// Defines the strict weak ordering for BOLT-produced code sections.
+class CodeSectionOrder {
+public:
+ CodeSectionOrder(StringRef ColdSectionName, StringRef HotTextMoverSectionName,
+ StringRef MainSectionName, StringRef WarmSectionName,
+ bool HotText, bool HotFunctionsAtEnd)
+ : ColdSectionName(ColdSectionName),
+ HotTextMoverSectionName(HotTextMoverSectionName),
+ MainSectionName(MainSectionName), WarmSectionName(WarmSectionName),
+ HotText(HotText), HotFunctionsAtEnd(HotFunctionsAtEnd) {}
+
+ bool operator()(StringRef AName, StringRef BName) const;
+
+private:
+ enum class SectionKind { Mover, Main, Warm, Cold, Other };
+
+ SectionKind getKind(StringRef Name) const;
+ unsigned getRank(SectionKind Kind) const;
+
+ StringRef ColdSectionName;
+ StringRef HotTextMoverSectionName;
+ StringRef MainSectionName;
+ StringRef WarmSectionName;
+ bool HotText;
+ bool HotFunctionsAtEnd;
+};
+
+} // namespace detail
/// This class encapsulates all data necessary to carry on binary reading,
/// disassembly, CFG building, BB reordering (among other binary-level
@@ -618,6 +650,7 @@ class RewriteInstance {
const Regex FunctionFragmentTemplate{"(.*)\\.(cold|warm)(\\.[0-9]+)?"};
friend class RewriteInstanceDiff;
+ friend class RewriteInstanceTest;
};
#undef ELF_FUNCTION
diff --git a/bolt/lib/Passes/BinaryPasses.cpp b/bolt/lib/Passes/BinaryPasses.cpp
index d24295e5c2c32..d2c042571e8b3 100644
--- a/bolt/lib/Passes/BinaryPasses.cpp
+++ b/bolt/lib/Passes/BinaryPasses.cpp
@@ -603,17 +603,22 @@ Error PopulateOutputFunctions::runOnFunctions(BinaryContext &BC) {
llvm::copy(BC.getInjectedBinaryFunctions(),
std::back_inserter(OutputFunctions));
- // Place hot text movers in front.
- if (opts::HotText) {
+ if (opts::HotFunctionsAtEnd) {
+ // Injected functions have no profile and precede other cold functions in
+ // the reverse layout.
std::stable_partition(
OutputFunctions.begin(), OutputFunctions.end(),
- [](const BinaryFunction *A) { return opts::isHotTextMover(*A); });
+ [](const BinaryFunction *A) { return A->isInjected(); });
+ std::stable_partition(
+ OutputFunctions.begin(), OutputFunctions.end(),
+ [](const BinaryFunction *A) { return !A->hasValidIndex(); });
}
- if (opts::HotFunctionsAtEnd) {
+ // Place hot text movers in front.
+ if (opts::HotText) {
std::stable_partition(
OutputFunctions.begin(), OutputFunctions.end(),
- [](const BinaryFunction *A) { return !A->hasValidIndex(); });
+ [](const BinaryFunction *A) { return opts::isHotTextMover(*A); });
}
return Error::success();
diff --git a/bolt/lib/Rewrite/RewriteInstance.cpp b/bolt/lib/Rewrite/RewriteInstance.cpp
index a5de2b5733355..0918e0ca1720f 100644
--- a/bolt/lib/Rewrite/RewriteInstance.cpp
+++ b/bolt/lib/Rewrite/RewriteInstance.cpp
@@ -4361,58 +4361,87 @@ void RewriteInstance::mapFileSections(BOLTLinker::SectionMapper MapSection) {
}
}
+llvm::bolt::detail::CodeSectionOrder::SectionKind
+llvm::bolt::detail::CodeSectionOrder::getKind(StringRef Name) const {
+ if (HotText && Name == HotTextMoverSectionName)
+ return SectionKind::Mover;
+ if (Name == MainSectionName)
+ return SectionKind::Main;
+ if (Name == WarmSectionName)
+ return SectionKind::Warm;
+ if (Name.starts_with(ColdSectionName))
+ return SectionKind::Cold;
+ return SectionKind::Other;
+}
+
+unsigned llvm::bolt::detail::CodeSectionOrder::getRank(SectionKind Kind) const {
+ if (Kind == SectionKind::Mover)
+ return 0;
+ if (HotFunctionsAtEnd) {
+ switch (Kind) {
+ case SectionKind::Other:
+ return 1;
+ case SectionKind::Cold:
+ return 2;
+ case SectionKind::Warm:
+ return 3;
+ case SectionKind::Main:
+ return 4;
+ case SectionKind::Mover:
+ llvm_unreachable("handled above");
+ }
+ }
+ switch (Kind) {
+ case SectionKind::Main:
+ return 1;
+ case SectionKind::Warm:
+ return 2;
+ case SectionKind::Cold:
+ return 3;
+ case SectionKind::Other:
+ return 4;
+ case SectionKind::Mover:
+ llvm_unreachable("handled above");
+ }
+ llvm_unreachable("unknown section kind");
+}
+
+bool llvm::bolt::detail::CodeSectionOrder::operator()(StringRef AName,
+ StringRef BName) const {
+ const SectionKind AKind = getKind(AName);
+ const SectionKind BKind = getKind(BName);
+ const unsigned ARank = getRank(AKind);
+ const unsigned BRank = getRank(BKind);
+ if (ARank != BRank)
+ return ARank < BRank;
+
+ if (AKind == SectionKind::Cold) {
+ if (AName.size() != BName.size())
+ return HotFunctionsAtEnd ? AName.size() > BName.size()
+ : AName.size() < BName.size();
+ if (AName != BName)
+ return HotFunctionsAtEnd ? AName > BName : AName < BName;
+ }
+
+ return false;
+}
+
std::vector<BinarySection *> RewriteInstance::getCodeSections() {
std::vector<BinarySection *> CodeSections;
for (BinarySection &Section : BC->textSections())
if (Section.hasValidSectionID())
CodeSections.emplace_back(&Section);
- auto compareSections = [&](const BinarySection *A, const BinarySection *B) {
- if (A == B)
- return false;
-
- // If both A and B have names starting with ".text.cold", then
- // - if opts::HotFunctionsAtEnd is true, we want order
- // ".text.cold.T", ".text.cold.T-1", ... ".text.cold.1", ".text.cold"
- // - if opts::HotFunctionsAtEnd is false, we want order
- // ".text.cold", ".text.cold.1", ... ".text.cold.T-1", ".text.cold.T"
- if (A->getName().starts_with(BC->getColdCodeSectionName()) &&
- B->getName().starts_with(BC->getColdCodeSectionName())) {
- if (A->getName().size() != B->getName().size())
- return (opts::HotFunctionsAtEnd)
- ? (A->getName().size() > B->getName().size())
- : (A->getName().size() < B->getName().size());
- return (opts::HotFunctionsAtEnd) ? (A->getName() > B->getName())
- : (A->getName() < B->getName());
- }
-
- // Place hot text movers before anything else.
- if (opts::HotText) {
- if (A->getName() == BC->getHotTextMoverSectionName())
- return true;
- if (B->getName() == BC->getHotTextMoverSectionName())
- return false;
- }
-
- // Depending on opts::HotFunctionsAtEnd, place main and warm sections in
- // order.
- if (opts::HotFunctionsAtEnd) {
- if (B->getName() == BC->getMainCodeSectionName())
- return true;
- if (A->getName() == BC->getMainCodeSectionName())
- return false;
- return (B->getName() == BC->getWarmCodeSectionName());
- } else {
- if (A->getName() == BC->getMainCodeSectionName())
- return true;
- if (B->getName() == BC->getMainCodeSectionName())
- return false;
- return (A->getName() == BC->getWarmCodeSectionName());
- }
- };
+ const llvm::bolt::detail::CodeSectionOrder CompareSections(
+ BC->getColdCodeSectionName(), BC->getHotTextMoverSectionName(),
+ BC->getMainCodeSectionName(), BC->getWarmCodeSectionName(), opts::HotText,
+ opts::HotFunctionsAtEnd);
// Determine the order of sections.
- llvm::stable_sort(CodeSections, compareSections);
+ llvm::stable_sort(CodeSections,
+ [&](const BinarySection *A, const BinarySection *B) {
+ return CompareSections(A->getName(), B->getName());
+ });
#ifndef NDEBUG
// Verify that the order of sections and functions is consistent.
diff --git a/bolt/test/X86/code-section-order-injected.s b/bolt/test/X86/code-section-order-injected.s
new file mode 100644
index 0000000000000..ab8c8e7051cec
--- /dev/null
+++ b/bolt/test/X86/code-section-order-injected.s
@@ -0,0 +1,43 @@
+# Check the physical order of BOLT-created injected and cold sections when hot
+# functions are placed at the end.
+
+# REQUIRES: system-linux, bolt-runtime
+
+# RUN: llvm-mc -filetype=obj -triple x86_64 %s -o %t.o
+# RUN: ld.lld --emit-relocs -e _start -o %t %t.o
+# RUN: llvm-bolt %t -o %t.bolt --lite=0 --hugify --split-functions \
+# RUN: --split-strategy=all --split-all-cold --hot-functions-at-end
+# RUN: llvm-nm --defined-only --numeric-sort %t.bolt \
+# RUN: | FileCheck --check-prefix=ORDER %s
+
+# ORDER: __bolt_hugify_start_program
+# ORDER: _start.cold.2
+# ORDER: _start.cold.1
+# ORDER: _start.cold.0
+# ORDER: _start
+
+ .text
+ .globl _start
+ .type _start, at function
+_start:
+ callq target
+ testl %edi, %edi
+ je .Lone
+ # Keep each outlined fragment large enough to pass x86 split profitability.
+ .rept 32
+ addl $1, %edi
+ .endr
+ jmp .Ldone
+.Lone:
+ .rept 32
+ subl $1, %edi
+ .endr
+.Ldone:
+ retq
+ .size _start, .-_start
+
+ .globl target
+ .type target, at function
+target:
+ retq
+ .size target, .-target
diff --git a/bolt/unittests/Core/CMakeLists.txt b/bolt/unittests/Core/CMakeLists.txt
index 297dec7449202..b622071efaf4a 100644
--- a/bolt/unittests/Core/CMakeLists.txt
+++ b/bolt/unittests/Core/CMakeLists.txt
@@ -11,6 +11,7 @@ add_bolt_unittest(CoreTests
MCPlusBuilder.cpp
MemoryMaps.cpp
DynoStats.cpp
+ RewriteInstance.cpp
# FIXME CoreTests uses `llvm::detail::TakeError(llvm::Error)`, but linking
# to LLVMTestingSupport introduces a transitive dependency on the
diff --git a/bolt/unittests/Core/RewriteInstance.cpp b/bolt/unittests/Core/RewriteInstance.cpp
new file mode 100644
index 0000000000000..287e917dbd8b8
--- /dev/null
+++ b/bolt/unittests/Core/RewriteInstance.cpp
@@ -0,0 +1,252 @@
+//===- bolt/unittest/Core/RewriteInstance.cpp -----------------------------===//
+//
+// 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 "bolt/Rewrite/RewriteInstance.h"
+#include "llvm/BinaryFormat/ELF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/TargetSelect.h"
+#include "gtest/gtest.h"
+#include <cstring>
+#include <memory>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::ELF;
+using namespace llvm::object;
+
+namespace opts {
+extern cl::opt<bool> HotFunctionsAtEnd;
+extern cl::opt<bool> HotText;
+} // namespace opts
+
+namespace llvm::bolt {
+
+class RewriteInstanceTest : public testing::Test {
+protected:
+ void SetUp() override {
+#define BOLT_TARGET(target) \
+ LLVMInitialize##target##TargetInfo(); \
+ LLVMInitialize##target##TargetMC(); \
+ LLVMInitialize##target##AsmParser(); \
+ LLVMInitialize##target##Disassembler(); \
+ LLVMInitialize##target##Target(); \
+ LLVMInitialize##target##AsmPrinter();
+
+#include "bolt/Core/TargetConfig.def"
+
+ memcpy(ELFBuffer, "\177ELF", 4);
+ auto *Header = reinterpret_cast<ELF64LE::Ehdr *>(ELFBuffer);
+ Header->e_ident[EI_CLASS] = ELFCLASS64;
+ Header->e_ident[EI_DATA] = ELFDATA2LSB;
+ Header->e_machine = EM_X86_64;
+ Header->e_type = ET_EXEC;
+ MemoryBufferRef Source(StringRef(ELFBuffer, sizeof(ELFBuffer)), "ELF");
+ Object = cantFail(ObjectFile::createObjectFile(Source));
+ Instance =
+ cantFail(RewriteInstance::create(cast<ELFObjectFileBase>(Object.get()),
+ 0, nullptr, "", NullOut, NullErr));
+ OriginalHotFunctionsAtEnd = opts::HotFunctionsAtEnd;
+ OriginalHotText = opts::HotText;
+ }
+
+ void TearDown() override {
+ opts::HotFunctionsAtEnd = OriginalHotFunctionsAtEnd;
+ opts::HotText = OriginalHotText;
+ }
+
+ BinarySection &addTextSection(StringRef Name, StringRef ID) {
+ BinarySection &Section = Instance->BC->registerOrUpdateSection(
+ Name, ELF::SHT_PROGBITS,
+ BinarySection::getFlags(/*IsReadOnly=*/true, /*IsText=*/true,
+ /*IsAllocatable=*/true));
+ Section.setSectionID(ID);
+ return Section;
+ }
+
+ BinarySection &addTextSectionWithoutID(StringRef Name) {
+ return Instance->BC->registerOrUpdateSection(
+ Name, ELF::SHT_PROGBITS,
+ BinarySection::getFlags(/*IsReadOnly=*/true, /*IsText=*/true,
+ /*IsAllocatable=*/true));
+ }
+
+ BinarySection &duplicateTextSection(StringRef Name,
+ const BinarySection &Original,
+ StringRef ID) {
+ BinarySection &Section = Instance->BC->registerSection(Name, Original);
+ Section.setSectionID(ID);
+ return Section;
+ }
+
+ void addNonTextSection(StringRef Name, bool IsAllocatable, StringRef ID) {
+ BinarySection &Section = Instance->BC->registerOrUpdateSection(
+ Name, ELF::SHT_PROGBITS,
+ BinarySection::getFlags(/*IsReadOnly=*/true, /*IsText=*/false,
+ IsAllocatable));
+ Section.setSectionID(ID);
+ }
+
+ std::vector<StringRef> getCodeSectionIDs(bool HotFunctionsAtEnd,
+ bool HotText) {
+ opts::HotFunctionsAtEnd = HotFunctionsAtEnd;
+ opts::HotText = HotText;
+ std::vector<StringRef> IDs;
+ for (const BinarySection *Section : Instance->getCodeSections())
+ IDs.push_back(Section->getSectionID());
+ return IDs;
+ }
+
+ char ELFBuffer[sizeof(ELF64LE::Ehdr)] = {};
+ raw_null_ostream NullOut;
+ raw_null_ostream NullErr;
+ std::unique_ptr<ObjectFile> Object;
+ std::unique_ptr<RewriteInstance> Instance;
+ bool OriginalHotFunctionsAtEnd{false};
+ bool OriginalHotText{false};
+};
+
+TEST_F(RewriteInstanceTest, GetCodeSections_FiltersInvalidSections) {
+ addTextSection(".text.other.valid", "valid");
+ addTextSectionWithoutID(".text.invalid");
+ addNonTextSection(".data", /*IsAllocatable=*/true, "data");
+ addNonTextSection(".debug_info", /*IsAllocatable=*/false, "debug");
+
+ EXPECT_EQ((std::vector<StringRef>{"valid"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false,
+ /*HotText=*/false));
+}
+
+TEST_F(RewriteInstanceTest, GetCodeSections_ForwardLayoutOrdersAllKinds) {
+ addTextSection(".text.cold.2", "cold2");
+ addTextSection(".text.cold.10", "cold10");
+ addTextSection(".text.cold", "cold");
+ addTextSection(".text.cold.1", "cold1");
+ addTextSection(".text.other.low", "other-low");
+ addTextSection(".text.other.high", "other-high");
+ addTextSection(".text.warm", "warm");
+ addTextSection(".text", "main");
+ addTextSection(".text.mover", "mover");
+
+ EXPECT_EQ(
+ (std::vector<StringRef>{"mover", "main", "warm", "cold", "cold1", "cold2",
+ "cold10", "other-low", "other-high"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false, /*HotText=*/true));
+}
+
+TEST_F(RewriteInstanceTest, GetCodeSections_HotAtEndLayoutOrdersAllKinds) {
+ addTextSection(".text.other.high", "other-high");
+ addTextSection(".text.other.low", "other-low");
+ addTextSection(".text.cold.2", "cold2");
+ addTextSection(".text.cold.10", "cold10");
+ addTextSection(".text.cold", "cold");
+ addTextSection(".text.cold.1", "cold1");
+ addTextSection(".text.warm", "warm");
+ addTextSection(".text", "main");
+ addTextSection(".text.mover", "mover");
+
+ EXPECT_EQ(
+ (std::vector<StringRef>{"mover", "other-high", "other-low", "cold10",
+ "cold2", "cold1", "cold", "warm", "main"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/true, /*HotText=*/true));
+}
+
+TEST_F(RewriteInstanceTest,
+ GetCodeSections_ColdNamesAndEquivalentSectionsHaveExpectedOrder) {
+ addTextSection(".text.cold.2", "cold2");
+ addTextSection(".text.cold.10", "cold10");
+ addTextSection(".text.cold", "cold");
+ BinarySection &Cold1 = addTextSection(".text.cold.1", "cold1a");
+ duplicateTextSection(".text.cold.1", Cold1, "cold1b");
+
+ EXPECT_EQ(
+ (std::vector<StringRef>{"cold", "cold1a", "cold1b", "cold2", "cold10"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false, /*HotText=*/false));
+ EXPECT_EQ(
+ (std::vector<StringRef>{"cold10", "cold2", "cold1a", "cold1b", "cold"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/true, /*HotText=*/false));
+}
+
+TEST_F(RewriteInstanceTest, GetCodeSections_EquivalentOtherSectionsStayStable) {
+ BinarySection &Other = addTextSection(".text.other", "other1");
+ duplicateTextSection(".text.other", Other, "other2");
+
+ EXPECT_EQ((std::vector<StringRef>{"other1", "other2"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false,
+ /*HotText=*/false));
+ EXPECT_EQ((std::vector<StringRef>{"other1", "other2"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/true, /*HotText=*/false));
+}
+
+TEST_F(RewriteInstanceTest,
+ GetCodeSections_EquivalentSpecialSectionsStayStable) {
+ BinarySection &Mover = addTextSection(".text.mover", "mover1");
+ duplicateTextSection(".text.mover", Mover, "mover2");
+ BinarySection &Main = addTextSection(".text", "main1");
+ duplicateTextSection(".text", Main, "main2");
+ BinarySection &Warm = addTextSection(".text.warm", "warm1");
+ duplicateTextSection(".text.warm", Warm, "warm2");
+
+ EXPECT_EQ((std::vector<StringRef>{"mover1", "mover2", "main1", "main2",
+ "warm1", "warm2"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false, /*HotText=*/true));
+ EXPECT_EQ((std::vector<StringRef>{"mover1", "mover2", "warm1", "warm2",
+ "main1", "main2"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/true, /*HotText=*/true));
+}
+
+TEST_F(RewriteInstanceTest, GetCodeSections_MoverIsOrdinaryWithoutHotText) {
+ addTextSection(".text.mover", "mover");
+ addTextSection(".text.other", "other");
+ addTextSection(".text", "main");
+
+ EXPECT_EQ((std::vector<StringRef>{"main", "mover", "other"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/false,
+ /*HotText=*/false));
+ EXPECT_EQ((std::vector<StringRef>{"mover", "other", "main"}),
+ getCodeSectionIDs(/*HotFunctionsAtEnd=*/true, /*HotText=*/false));
+}
+
+TEST(CodeSectionOrderTest, RepresentativeNamesFormStrictWeakOrdering) {
+ const std::vector<StringRef> Names = {
+ ".text.mover", ".text.mover", ".text", ".text",
+ ".text.warm", ".text.warm", ".text.cold", ".text.cold.1",
+ ".text.cold.2", ".text.cold.10", ".text.other.a", ".text.other.b",
+ };
+
+ for (const bool HotText : {false, true}) {
+ for (const bool HotFunctionsAtEnd : {false, true}) {
+ const detail::CodeSectionOrder Order(".text.cold", ".text.mover", ".text",
+ ".text.warm", HotText,
+ HotFunctionsAtEnd);
+ const auto Equivalent = [&](StringRef A, StringRef B) {
+ return !Order(A, B) && !Order(B, A);
+ };
+
+ for (StringRef A : Names) {
+ EXPECT_FALSE(Order(A, A));
+ for (StringRef B : Names) {
+ if (Order(A, B)) {
+ EXPECT_FALSE(Order(B, A));
+ }
+ for (StringRef C : Names) {
+ if (Order(A, B) && Order(B, C)) {
+ EXPECT_TRUE(Order(A, C));
+ }
+ if (Equivalent(A, B) && Equivalent(B, C)) {
+ EXPECT_TRUE(Equivalent(A, C));
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+} // namespace llvm::bolt
More information about the llvm-commits
mailing list