Skip to content

Commit

Permalink
Merge branch 'llvm:main' into bugfix_ws_multi_resource_reserve
Browse files Browse the repository at this point in the history
  • Loading branch information
kaiyan96 authored Jul 25, 2024
2 parents d998033 + 456c512 commit 4064349
Show file tree
Hide file tree
Showing 577 changed files with 19,737 additions and 5,480 deletions.
15 changes: 14 additions & 1 deletion bolt/include/bolt/Core/BinaryContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
#include "bolt/RuntimeLibs/RuntimeLibrary.h"
#include "llvm/ADT/AddressRanges.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/EquivalenceClasses.h"
#include "llvm/ADT/StringMap.h"
#include "llvm/ADT/iterator.h"
#include "llvm/BinaryFormat/Dwarf.h"
Expand Down Expand Up @@ -241,6 +242,10 @@ class BinaryContext {
/// Function fragments to skip.
std::unordered_set<BinaryFunction *> FragmentsToSkip;

/// Fragment equivalence classes to query belonging to the same "family" in
/// presence of multiple fragments/multiple parents.
EquivalenceClasses<const BinaryFunction *> FragmentClasses;

/// The runtime library.
std::unique_ptr<RuntimeLibrary> RtLibrary;

Expand Down Expand Up @@ -1032,7 +1037,15 @@ class BinaryContext {
/// fragment_name == parent_name.cold(.\d+)?
/// True if the Function is registered, false if the check failed.
bool registerFragment(BinaryFunction &TargetFunction,
BinaryFunction &Function) const;
BinaryFunction &Function);

/// Return true if two functions belong to the same "family": are fragments
/// of one another, or fragments of the same parent, or transitively fragment-
/// related.
bool areRelatedFragments(const BinaryFunction *LHS,
const BinaryFunction *RHS) const {
return FragmentClasses.isEquivalent(LHS, RHS);
}

/// Add interprocedural reference for \p Function to \p Address
void addInterproceduralReference(BinaryFunction *Function, uint64_t Address) {
Expand Down
10 changes: 0 additions & 10 deletions bolt/include/bolt/Core/BinaryFunction.h
Original file line number Diff line number Diff line change
Expand Up @@ -1793,11 +1793,6 @@ class BinaryFunction {
return ParentFragments.contains(&Other);
}

/// Returns if this function is a parent of \p Other function.
bool isParentOf(const BinaryFunction &Other) const {
return Fragments.contains(&Other);
}

/// Return the child fragment form parent function
iterator_range<FragmentsSetTy::const_iterator> getFragments() const {
return iterator_range<FragmentsSetTy::const_iterator>(Fragments.begin(),
Expand All @@ -1807,11 +1802,6 @@ class BinaryFunction {
/// Return the parent function for split function fragments.
FragmentsSetTy *getParentFragments() { return &ParentFragments; }

/// Returns if this function is a parent or child of \p Other function.
bool isParentOrChildOf(const BinaryFunction &Other) const {
return isChildOf(Other) || isParentOf(Other);
}

/// Set the profile data for the number of times the function was called.
BinaryFunction &setExecutionCount(uint64_t Count) {
ExecutionCount = Count;
Expand Down
19 changes: 11 additions & 8 deletions bolt/lib/Core/BinaryContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -646,7 +646,7 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
const BinaryFunction *TargetBF = getBinaryFunctionContainingAddress(Value);
const bool DoesBelongToFunction =
BF.containsAddress(Value) ||
(TargetBF && TargetBF->isParentOrChildOf(BF));
(TargetBF && areRelatedFragments(TargetBF, &BF));
if (!DoesBelongToFunction) {
LLVM_DEBUG({
if (!BF.containsAddress(Value)) {
Expand Down Expand Up @@ -839,9 +839,11 @@ BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,
assert(Address == JT->getAddress() && "unexpected non-empty jump table");

// Prevent associating a jump table to a specific fragment twice.
// This simple check arises from the assumption: no more than 2 fragments.
if (JT->Parents.size() == 1 && JT->Parents[0] != &Function) {
assert(JT->Parents[0]->isParentOrChildOf(Function) &&
if (!llvm::is_contained(JT->Parents, &Function)) {
assert(llvm::all_of(JT->Parents,
[&](const BinaryFunction *BF) {
return areRelatedFragments(&Function, BF);
}) &&
"cannot re-use jump table of a different function");
// Duplicate the entry for the parent function for easy access
JT->Parents.push_back(&Function);
Expand All @@ -852,8 +854,8 @@ BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,
JT->print(this->outs());
}
Function.JumpTables.emplace(Address, JT);
JT->Parents[0]->setHasIndirectTargetToSplitFragment(true);
JT->Parents[1]->setHasIndirectTargetToSplitFragment(true);
for (BinaryFunction *Parent : JT->Parents)
Parent->setHasIndirectTargetToSplitFragment(true);
}

bool IsJumpTableParent = false;
Expand Down Expand Up @@ -1209,12 +1211,13 @@ void BinaryContext::generateSymbolHashes() {
}

bool BinaryContext::registerFragment(BinaryFunction &TargetFunction,
BinaryFunction &Function) const {
BinaryFunction &Function) {
assert(TargetFunction.isFragment() && "TargetFunction must be a fragment");
if (TargetFunction.isChildOf(Function))
return true;
TargetFunction.addParentFragment(Function);
Function.addFragment(TargetFunction);
FragmentClasses.unionSets(&TargetFunction, &Function);
if (!HasRelocations) {
TargetFunction.setSimple(false);
Function.setSimple(false);
Expand Down Expand Up @@ -1336,7 +1339,7 @@ void BinaryContext::processInterproceduralReferences() {

if (TargetFunction) {
if (TargetFunction->isFragment() &&
!TargetFunction->isChildOf(Function)) {
!areRelatedFragments(TargetFunction, &Function)) {
this->errs()
<< "BOLT-WARNING: interprocedural reference between unrelated "
"fragments: "
Expand Down
2 changes: 1 addition & 1 deletion bolt/lib/Core/Exceptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -207,7 +207,7 @@ Error BinaryFunction::parseLSDA(ArrayRef<uint8_t> LSDASectionData,
"BOLT-ERROR: cannot find landing pad fragment");
BC.addInterproceduralReference(this, Fragment->getAddress());
BC.processInterproceduralReferences();
assert(isParentOrChildOf(*Fragment) &&
assert(BC.areRelatedFragments(this, Fragment) &&
"BOLT-ERROR: cannot have landing pads in different functions");
setHasIndirectTargetToSplitFragment(true);
BC.addFragmentsToSkip(this);
Expand Down
4 changes: 3 additions & 1 deletion bolt/lib/Profile/DataAggregator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -88,6 +88,7 @@ MaxSamples("max-samples",
cl::cat(AggregatorCategory));

extern cl::opt<opts::ProfileFormatKind> ProfileFormat;
extern cl::opt<bool> ProfileUsePseudoProbes;
extern cl::opt<std::string> SaveProfile;

cl::opt<bool> ReadPreAggregated(
Expand Down Expand Up @@ -2298,7 +2299,8 @@ std::error_code DataAggregator::writeBATYAML(BinaryContext &BC,

yaml::bolt::BinaryProfile BP;

const MCPseudoProbeDecoder *PseudoProbeDecoder = BC.getPseudoProbeDecoder();
const MCPseudoProbeDecoder *PseudoProbeDecoder =
opts::ProfileUsePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr;

// Fill out the header info.
BP.Header.Version = 1;
Expand Down
5 changes: 5 additions & 0 deletions bolt/lib/Profile/YAMLProfileReader.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,11 @@ llvm::cl::opt<bool>
llvm::cl::opt<bool> ProfileUseDFS("profile-use-dfs",
cl::desc("use DFS order for YAML profile"),
cl::Hidden, cl::cat(BoltOptCategory));

llvm::cl::opt<bool> ProfileUsePseudoProbes(
"profile-use-pseudo-probes",
cl::desc("Use pseudo probes for profile generation and matching"),
cl::Hidden, cl::cat(BoltOptCategory));
} // namespace opts

namespace llvm {
Expand Down
4 changes: 3 additions & 1 deletion bolt/lib/Profile/YAMLProfileWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@

namespace opts {
extern llvm::cl::opt<bool> ProfileUseDFS;
extern llvm::cl::opt<bool> ProfileUsePseudoProbes;
} // namespace opts

namespace llvm {
Expand Down Expand Up @@ -57,7 +58,8 @@ YAMLProfileWriter::convert(const BinaryFunction &BF, bool UseDFS,
const BoltAddressTranslation *BAT) {
yaml::bolt::BinaryFunctionProfile YamlBF;
const BinaryContext &BC = BF.getBinaryContext();
const MCPseudoProbeDecoder *PseudoProbeDecoder = BC.getPseudoProbeDecoder();
const MCPseudoProbeDecoder *PseudoProbeDecoder =
opts::ProfileUsePseudoProbes ? BC.getPseudoProbeDecoder() : nullptr;

const uint16_t LBRProfile = BF.getProfileFlags() & BinaryFunction::PF_LBR;

Expand Down
6 changes: 5 additions & 1 deletion bolt/lib/Rewrite/PseudoProbeRewriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ static cl::opt<PrintPseudoProbesOptions> PrintPseudoProbes(
clEnumValN(PPP_All, "all", "enable all debugging printout")),
cl::Hidden, cl::cat(BoltCategory));

extern cl::opt<bool> ProfileUsePseudoProbes;
} // namespace opts

namespace {
Expand Down Expand Up @@ -89,12 +90,15 @@ class PseudoProbeRewriter final : public MetadataRewriter {
};

Error PseudoProbeRewriter::preCFGInitializer() {
parsePseudoProbe();
if (opts::ProfileUsePseudoProbes)
parsePseudoProbe();

return Error::success();
}

Error PseudoProbeRewriter::postEmitFinalizer() {
if (!opts::ProfileUsePseudoProbes)
parsePseudoProbe();
updatePseudoProbes();

return Error::success();
Expand Down
12 changes: 10 additions & 2 deletions bolt/test/X86/pseudoprobe-decoding-inline.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,11 @@
# PREAGG: B X:0 #main# 1 0
## Check pseudo-probes in regular YAML profile (non-BOLTed binary)
# RUN: link_fdata %s %S/../../../llvm/test/tools/llvm-profgen/Inputs/inline-cs-pseudoprobe.perfbin %t.preagg PREAGG
# RUN: perf2bolt %S/../../../llvm/test/tools/llvm-profgen/Inputs/inline-cs-pseudoprobe.perfbin -p %t.preagg --pa -w %t.yaml -o %t.fdata
# RUN: perf2bolt %S/../../../llvm/test/tools/llvm-profgen/Inputs/inline-cs-pseudoprobe.perfbin -p %t.preagg --pa -w %t.yaml -o %t.fdata --profile-use-pseudo-probes
# RUN: FileCheck --input-file %t.yaml %s --check-prefix CHECK-YAML
## Check pseudo-probes in BAT YAML profile (BOLTed binary)
# RUN: link_fdata %s %t.bolt %t.preagg2 PREAGG
# RUN: perf2bolt %t.bolt -p %t.preagg2 --pa -w %t.yaml2 -o %t.fdata2
# RUN: perf2bolt %t.bolt -p %t.preagg2 --pa -w %t.yaml2 -o %t.fdata2 --profile-use-pseudo-probes
# RUN: FileCheck --input-file %t.yaml2 %s --check-prefix CHECK-YAML
# CHECK-YAML: name: bar
# CHECK-YAML: - bid: 0
Expand All @@ -29,6 +29,14 @@
# CHECK-YAML: pseudo_probes: [ { guid: 0xDB956436E78DD5FA, id: 1, type: 0 }, { guid: 0x5CF8C24CDB18BDAC, id: 1, type: 0 }, { guid: 0x5CF8C24CDB18BDAC, id: 2, type: 0 } ]
# CHECK-YAML: guid: 0xDB956436E78DD5FA
# CHECK-YAML: pseudo_probe_desc_hash: 0x10000FFFFFFFF
#
## Check that without --profile-use-pseudo-probes option, no pseudo probes are
## generated
# RUN: perf2bolt %S/../../../llvm/test/tools/llvm-profgen/Inputs/inline-cs-pseudoprobe.perfbin -p %t.preagg --pa -w %t.yaml -o %t.fdata
# RUN: FileCheck --input-file %t.yaml %s --check-prefix CHECK-NO-OPT
# CHECK-NO-OPT-NOT: pseudo_probes
# CHECK-NO-OPT-NOT: guid
# CHECK-NO-OPT-NOT: pseudo_probe_desc_hash

CHECK: Report of decoding input pseudo probe binaries

Expand Down
95 changes: 95 additions & 0 deletions bolt/test/X86/three-way-split-jt.s
Original file line number Diff line number Diff line change
@@ -0,0 +1,95 @@
## This reproduces an issue where the function is split into three fragments
## and all fragments access the same jump table.

# REQUIRES: system-linux

# RUN: llvm-mc -filetype=obj -triple x86_64-unknown-unknown %s -o %t.o
# RUN: llvm-strip --strip-unneeded %t.o
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
# RUN: llvm-bolt %t.exe -o %t.out -v=1 -print-only=main.warm -print-cfg 2>&1 | FileCheck %s

# CHECK-DAG: BOLT-INFO: marking main.warm as a fragment of main
# CHECK-DAG: BOLT-INFO: marking main.cold as a fragment of main
# CHECK-DAG: BOLT-INFO: processing main.warm as a sibling of non-ignored function
# CHECK-DAG: BOLT-INFO: processing main.cold as a sibling of non-ignored function
# CHECK-DAG: BOLT-WARNING: Ignoring main.cold
# CHECK-DAG: BOLT-WARNING: Ignoring main.warm
# CHECK-DAG: BOLT-WARNING: Ignoring main
# CHECK: BOLT-WARNING: skipped 3 functions due to cold fragments

# CHECK: PIC Jump table JUMP_TABLE for function main, main.warm, main.cold
# CHECK-NEXT: 0x0000 : __ENTRY_main@0x[[#]]
# CHECK-NEXT: 0x0004 : __ENTRY_main@0x[[#]]
# CHECK-NEXT: 0x0008 : __ENTRY_main.cold@0x[[#]]
# CHECK-NEXT: 0x000c : __ENTRY_main@0x[[#]]
.globl main
.type main, %function
.p2align 2
main:
LBB0:
andl $0xf, %ecx
cmpb $0x4, %cl
## exit through ret
ja LBB3

## jump table dispatch, jumping to label indexed by val in %ecx
LBB1:
leaq JUMP_TABLE(%rip), %r8
movzbl %cl, %ecx
movslq (%r8,%rcx,4), %rax
addq %rax, %r8
jmpq *%r8

LBB2:
xorq %rax, %rax
LBB3:
addq $0x8, %rsp
ret
.size main, .-main

.globl main.warm
.type main.warm, %function
.p2align 2
main.warm:
LBB20:
andl $0xb, %ebx
cmpb $0x1, %cl
# exit through ret
ja LBB23

## jump table dispatch, jumping to label indexed by val in %ecx
LBB21:
leaq JUMP_TABLE(%rip), %r8
movzbl %cl, %ecx
movslq (%r8,%rcx,4), %rax
addq %rax, %r8
jmpq *%r8

LBB22:
xorq %rax, %rax
LBB23:
addq $0x8, %rsp
ret
.size main.warm, .-main.warm

## cold fragment is only reachable through jump table
.globl main.cold
.type main.cold, %function
main.cold:
leaq JUMP_TABLE(%rip), %r8
movzbl %cl, %ecx
movslq (%r8,%rcx,4), %rax
addq %rax, %r8
jmpq *%r8
LBB4:
callq abort
.size main.cold, .-main.cold

.rodata
## jmp table, entries must be R_X86_64_PC32 relocs
.globl JUMP_TABLE
JUMP_TABLE:
.long LBB2-JUMP_TABLE
.long LBB3-JUMP_TABLE
.long LBB4-JUMP_TABLE
.long LBB3-JUMP_TABLE
13 changes: 13 additions & 0 deletions clang-tools-extra/clang-doc/HTMLGenerator.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
#include "llvm/Support/JSON.h"
#include "llvm/Support/Path.h"
#include "llvm/Support/raw_ostream.h"
#include <algorithm>
#include <optional>
#include <string>

Expand Down Expand Up @@ -979,6 +980,18 @@ static llvm::Error serializeIndex(ClangDocContext &CDCtx) {
"error creating index file: " +
FileErr.message());
}
llvm::SmallString<128> RootPath(CDCtx.OutDirectory);
if (llvm::sys::path::is_relative(RootPath)) {
llvm::sys::fs::make_absolute(RootPath);
}
// Replace the escaped characters with a forward slash. It shouldn't matter
// when rendering the webpage in a web browser. This helps to prevent the
// JavaScript from escaping characters incorrectly, and introducing bad paths
// in the URLs.
std::string RootPathEscaped = RootPath.str().str();
std::replace(RootPathEscaped.begin(), RootPathEscaped.end(), '\\', '/');
OS << "var RootPath = \"" << RootPathEscaped << "\";\n";

CDCtx.Idx.sort();
llvm::json::OStream J(OS, 2);
std::function<void(Index)> IndexToJSON = [&](const Index &I) {
Expand Down
Loading

0 comments on commit 4064349

Please sign in to comment.