Skip to content

Commit e328d7a

Browse files
authored
Merge branch 'main' into gisel-vop3p
2 parents 0eac2e9 + ebba554 commit e328d7a

File tree

844 files changed

+37190
-25877
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

844 files changed

+37190
-25877
lines changed

.github/workflows/containers/github-action-ci/Dockerfile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ RUN cmake -B ./build -G Ninja ./llvm \
3232
-DLLVM_ENABLE_RUNTIMES="compiler-rt" \
3333
-DCMAKE_INSTALL_PREFIX="$LLVM_SYSROOT" \
3434
-DLLVM_ENABLE_PROJECTS="bolt;clang;lld;clang-tools-extra" \
35-
-DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build" \
35+
-DLLVM_DISTRIBUTION_COMPONENTS="lld;compiler-rt;clang-format;scan-build;llvm-symbolizer" \
3636
-DCLANG_DEFAULT_LINKER="lld"
3737

3838
RUN ninja -C ./build stage2-clang-bolt stage2-install-distribution && ninja -C ./build install-distribution

.mailmap

Lines changed: 2 additions & 1 deletion

bolt/lib/Core/BinaryContext.cpp

Lines changed: 37 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -579,6 +579,21 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
579579
TrimmedSize = EntriesAsAddress->size();
580580
};
581581

582+
auto printEntryDiagnostics = [&](raw_ostream &OS,
583+
const BinaryFunction *TargetBF) {
584+
OS << "FAIL: function doesn't contain this address\n";
585+
if (!TargetBF)
586+
return;
587+
OS << " ! function containing this address: " << *TargetBF << '\n';
588+
if (!TargetBF->isFragment())
589+
return;
590+
OS << " ! is a fragment with parents: ";
591+
ListSeparator LS;
592+
for (BinaryFunction *Parent : TargetBF->ParentFragments)
593+
OS << LS << *Parent;
594+
OS << '\n';
595+
};
596+
582597
ErrorOr<const BinarySection &> Section = getSectionForAddress(Address);
583598
if (!Section)
584599
return false;
@@ -646,25 +661,9 @@ bool BinaryContext::analyzeJumpTable(const uint64_t Address,
646661

647662
// Function or one of its fragments.
648663
const BinaryFunction *TargetBF = getBinaryFunctionContainingAddress(Value);
649-
const bool DoesBelongToFunction =
650-
BF.containsAddress(Value) ||
651-
(TargetBF && areRelatedFragments(TargetBF, &BF));
652-
if (!DoesBelongToFunction) {
653-
LLVM_DEBUG({
654-
if (!BF.containsAddress(Value)) {
655-
dbgs() << "FAIL: function doesn't contain this address\n";
656-
if (TargetBF) {
657-
dbgs() << " ! function containing this address: "
658-
<< TargetBF->getPrintName() << '\n';
659-
if (TargetBF->isFragment()) {
660-
dbgs() << " ! is a fragment";
661-
for (BinaryFunction *Parent : TargetBF->ParentFragments)
662-
dbgs() << ", parent: " << Parent->getPrintName();
663-
dbgs() << '\n';
664-
}
665-
}
666-
}
667-
});
664+
if (!TargetBF || !areRelatedFragments(TargetBF, &BF)) {
665+
LLVM_DEBUG(printEntryDiagnostics(dbgs(), TargetBF));
666+
(void)printEntryDiagnostics;
668667
break;
669668
}
670669

@@ -703,10 +702,7 @@ void BinaryContext::populateJumpTables() {
703702
++JTI) {
704703
JumpTable *JT = JTI->second;
705704

706-
bool NonSimpleParent = false;
707-
for (BinaryFunction *BF : JT->Parents)
708-
NonSimpleParent |= !BF->isSimple();
709-
if (NonSimpleParent)
705+
if (!llvm::all_of(JT->Parents, std::mem_fn(&BinaryFunction::isSimple)))
710706
continue;
711707

712708
uint64_t NextJTAddress = 0;
@@ -840,33 +836,26 @@ BinaryContext::getOrCreateJumpTable(BinaryFunction &Function, uint64_t Address,
840836
assert(JT->Type == Type && "jump table types have to match");
841837
assert(Address == JT->getAddress() && "unexpected non-empty jump table");
842838

843-
// Prevent associating a jump table to a specific fragment twice.
844-
if (!llvm::is_contained(JT->Parents, &Function)) {
845-
assert(llvm::all_of(JT->Parents,
846-
[&](const BinaryFunction *BF) {
847-
return areRelatedFragments(&Function, BF);
848-
}) &&
849-
"cannot re-use jump table of a different function");
850-
// Duplicate the entry for the parent function for easy access
851-
JT->Parents.push_back(&Function);
852-
if (opts::Verbosity > 2) {
853-
this->outs() << "BOLT-INFO: Multiple fragments access same jump table: "
854-
<< JT->Parents[0]->getPrintName() << "; "
855-
<< Function.getPrintName() << "\n";
856-
JT->print(this->outs());
857-
}
858-
Function.JumpTables.emplace(Address, JT);
859-
for (BinaryFunction *Parent : JT->Parents)
860-
Parent->setHasIndirectTargetToSplitFragment(true);
861-
}
839+
if (llvm::is_contained(JT->Parents, &Function))
840+
return JT->getFirstLabel();
862841

863-
bool IsJumpTableParent = false;
864-
(void)IsJumpTableParent;
865-
for (BinaryFunction *Frag : JT->Parents)
866-
if (Frag == &Function)
867-
IsJumpTableParent = true;
868-
assert(IsJumpTableParent &&
842+
// Prevent associating a jump table to a specific fragment twice.
843+
auto isSibling = std::bind(&BinaryContext::areRelatedFragments, this,
844+
&Function, std::placeholders::_1);
845+
assert(llvm::all_of(JT->Parents, isSibling) &&
869846
"cannot re-use jump table of a different function");
847+
(void)isSibling;
848+
if (opts::Verbosity > 2) {
849+
this->outs() << "BOLT-INFO: multiple fragments access the same jump table"
850+
<< ": " << *JT->Parents[0] << "; " << Function << '\n';
851+
JT->print(this->outs());
852+
}
853+
if (JT->Parents.size() == 1)
854+
JT->Parents.front()->setHasIndirectTargetToSplitFragment(true);
855+
Function.setHasIndirectTargetToSplitFragment(true);
856+
// Duplicate the entry for the parent function for easy access
857+
JT->Parents.push_back(&Function);
858+
Function.JumpTables.emplace(Address, JT);
870859
return JT->getFirstLabel();
871860
}
872861

bolt/lib/Core/BinaryEmitter.cpp

Lines changed: 36 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -809,52 +809,50 @@ void BinaryEmitter::emitJumpTable(const JumpTable &JT, MCSection *HotSection,
809809
Streamer.switchSection(JT.Count > 0 ? HotSection : ColdSection);
810810
Streamer.emitValueToAlignment(Align(JT.EntrySize));
811811
}
812-
MCSymbol *LastLabel = nullptr;
812+
MCSymbol *JTLabel = nullptr;
813813
uint64_t Offset = 0;
814814
for (MCSymbol *Entry : JT.Entries) {
815815
auto LI = JT.Labels.find(Offset);
816-
if (LI != JT.Labels.end()) {
817-
LLVM_DEBUG({
818-
dbgs() << "BOLT-DEBUG: emitting jump table " << LI->second->getName()
819-
<< " (originally was at address 0x"
820-
<< Twine::utohexstr(JT.getAddress() + Offset)
821-
<< (Offset ? ") as part of larger jump table\n" : ")\n");
822-
});
823-
if (!LabelCounts.empty()) {
824-
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: jump table count: "
825-
<< LabelCounts[LI->second] << '\n');
826-
if (LabelCounts[LI->second] > 0)
827-
Streamer.switchSection(HotSection);
828-
else
829-
Streamer.switchSection(ColdSection);
830-
Streamer.emitValueToAlignment(Align(JT.EntrySize));
831-
}
832-
// Emit all labels registered at the address of this jump table
833-
// to sync with our global symbol table. We may have two labels
834-
// registered at this address if one label was created via
835-
// getOrCreateGlobalSymbol() (e.g. LEA instructions referencing
836-
// this location) and another via getOrCreateJumpTable(). This
837-
// creates a race where the symbols created by these two
838-
// functions may or may not be the same, but they are both
839-
// registered in our symbol table at the same address. By
840-
// emitting them all here we make sure there is no ambiguity
841-
// that depends on the order that these symbols were created, so
842-
// whenever this address is referenced in the binary, it is
843-
// certain to point to the jump table identified at this
844-
// address.
845-
if (BinaryData *BD = BC.getBinaryDataByName(LI->second->getName())) {
846-
for (MCSymbol *S : BD->getSymbols())
847-
Streamer.emitLabel(S);
848-
} else {
849-
Streamer.emitLabel(LI->second);
850-
}
851-
LastLabel = LI->second;
816+
if (LI == JT.Labels.end())
817+
goto emitEntry;
818+
JTLabel = LI->second;
819+
LLVM_DEBUG({
820+
dbgs() << "BOLT-DEBUG: emitting jump table " << JTLabel->getName()
821+
<< " (originally was at address 0x"
822+
<< Twine::utohexstr(JT.getAddress() + Offset)
823+
<< (Offset ? ") as part of larger jump table\n" : ")\n");
824+
});
825+
if (!LabelCounts.empty()) {
826+
const uint64_t JTCount = LabelCounts[JTLabel];
827+
LLVM_DEBUG(dbgs() << "BOLT-DEBUG: jump table count: " << JTCount << '\n');
828+
Streamer.switchSection(JTCount ? HotSection : ColdSection);
829+
Streamer.emitValueToAlignment(Align(JT.EntrySize));
830+
}
831+
// Emit all labels registered at the address of this jump table
832+
// to sync with our global symbol table. We may have two labels
833+
// registered at this address if one label was created via
834+
// getOrCreateGlobalSymbol() (e.g. LEA instructions referencing
835+
// this location) and another via getOrCreateJumpTable(). This
836+
// creates a race where the symbols created by these two
837+
// functions may or may not be the same, but they are both
838+
// registered in our symbol table at the same address. By
839+
// emitting them all here we make sure there is no ambiguity
840+
// that depends on the order that these symbols were created, so
841+
// whenever this address is referenced in the binary, it is
842+
// certain to point to the jump table identified at this
843+
// address.
844+
if (BinaryData *BD = BC.getBinaryDataByName(JTLabel->getName())) {
845+
for (MCSymbol *S : BD->getSymbols())
846+
Streamer.emitLabel(S);
847+
} else {
848+
Streamer.emitLabel(JTLabel);
852849
}
850+
emitEntry:
853851
if (JT.Type == JumpTable::JTT_NORMAL) {
854852
Streamer.emitSymbolValue(Entry, JT.OutputEntrySize);
855853
} else { // JTT_PIC
856854
const MCSymbolRefExpr *JTExpr =
857-
MCSymbolRefExpr::create(LastLabel, Streamer.getContext());
855+
MCSymbolRefExpr::create(JTLabel, Streamer.getContext());
858856
const MCSymbolRefExpr *E =
859857
MCSymbolRefExpr::create(Entry, Streamer.getContext());
860858
const MCBinaryExpr *Value =

bolt/lib/Passes/AsmDump.cpp

Lines changed: 6 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -134,13 +134,14 @@ void dumpFunction(const BinaryFunction &BF) {
134134
std::unique_ptr<MCAsmBackend> MAB(
135135
BC.TheTarget->createMCAsmBackend(*BC.STI, *BC.MRI, MCTargetOptions()));
136136
int AsmPrinterVariant = BC.AsmInfo->getAssemblerDialect();
137-
MCInstPrinter *InstructionPrinter(BC.TheTarget->createMCInstPrinter(
138-
*BC.TheTriple, AsmPrinterVariant, *BC.AsmInfo, *BC.MII, *BC.MRI));
137+
std::unique_ptr<MCInstPrinter> InstructionPrinter(
138+
BC.TheTarget->createMCInstPrinter(*BC.TheTriple, AsmPrinterVariant,
139+
*BC.AsmInfo, *BC.MII, *BC.MRI));
139140
auto FOut = std::make_unique<formatted_raw_ostream>(OS);
140141
FOut->SetUnbuffered();
141-
std::unique_ptr<MCStreamer> AsmStreamer(
142-
createAsmStreamer(*LocalCtx, std::move(FOut), InstructionPrinter,
143-
std::move(MCEInstance.MCE), std::move(MAB)));
142+
std::unique_ptr<MCStreamer> AsmStreamer(createAsmStreamer(
143+
*LocalCtx, std::move(FOut), std::move(InstructionPrinter),
144+
std::move(MCEInstance.MCE), std::move(MAB)));
144145
AsmStreamer->initSections(true, *BC.STI);
145146
std::unique_ptr<TargetMachine> TM(BC.TheTarget->createTargetMachine(
146147
*BC.TheTriple, "", "", TargetOptions(), std::nullopt));

bolt/lib/Profile/DataAggregator.cpp

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -871,18 +871,27 @@ DataAggregator::getFallthroughsInTrace(BinaryFunction &BF,
871871

872872
BinaryContext &BC = BF.getBinaryContext();
873873

874-
if (!BF.isSimple())
875-
return std::nullopt;
876-
877-
assert(BF.hasCFG() && "can only record traces in CFG state");
878-
879874
// Offsets of the trace within this function.
880875
const uint64_t From = FirstLBR.To - BF.getAddress();
881876
const uint64_t To = SecondLBR.From - BF.getAddress();
882877

883878
if (From > To)
884879
return std::nullopt;
885880

881+
// Accept fall-throughs inside pseudo functions (PLT/thunks).
882+
// This check has to be above BF.empty as pseudo functions would pass it:
883+
// pseudo => ignored => CFG not built => empty.
884+
// If we return nullopt, trace would be reported as mismatching disassembled
885+
// function contents which it is not. To avoid this, return an empty
886+
// fall-through list instead.
887+
if (BF.isPseudo())
888+
return Branches;
889+
890+
if (!BF.isSimple())
891+
return std::nullopt;
892+
893+
assert(BF.hasCFG() && "can only record traces in CFG state");
894+
886895
const BinaryBasicBlock *FromBB = BF.getBasicBlockContainingOffset(From);
887896
const BinaryBasicBlock *ToBB = BF.getBasicBlockContainingOffset(To);
888897

bolt/test/X86/callcont-fallthru.s

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
# RUN: link_fdata %s %t %t.pa3 PREAGG3
1010
# RUN: link_fdata %s %t %t.pat PREAGGT1
1111
# RUN: link_fdata %s %t %t.pat2 PREAGGT2
12+
# RUN: link_fdata %s %t %t.patplt PREAGGPLT
1213

1314
## Check normal case: fallthrough is not LP or secondary entry.
1415
# RUN: llvm-strip --strip-unneeded %t -o %t.strip
@@ -42,6 +43,12 @@
4243
# RUN: llvm-bolt %t.strip --pa -p %t.pat2 -o %t.out \
4344
# RUN: --print-cfg --print-only=main | FileCheck %s --check-prefix=CHECK3
4445

46+
## Check pre-aggregated traces don't report zero-sized PLT fall-through as
47+
## invalid trace
48+
# RUN: llvm-bolt %t.strip --pa -p %t.patplt -o %t.out | FileCheck %s \
49+
# RUN: --check-prefix=CHECK-PLT
50+
# CHECK-PLT: traces mismatching disassembled function contents: 0
51+
4552
.globl foo
4653
.type foo, %function
4754
foo:
@@ -65,7 +72,10 @@ main:
6572
movl $0x0, -0x4(%rbp)
6673
movl %edi, -0x8(%rbp)
6774
movq %rsi, -0x10(%rbp)
75+
Ltmp0_br:
6876
callq puts@PLT
77+
## Check PLT traces are accepted
78+
# PREAGGPLT: T #Ltmp0_br# #puts@plt# #puts@plt# 3
6979
## Target is an external-origin call continuation
7080
# PREAGG1: B X:0 #Ltmp1# 2 0
7181
# PREAGGT1: T X:0 #Ltmp1# #Ltmp4_br# 2

bolt/test/X86/split-func-jump-table-fragment-bidirection.s

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
# RUN: %clang %cflags %t.o -o %t.exe -Wl,-q
1111
# RUN: llvm-bolt -print-cfg -v=3 %t.exe -o %t.out 2>&1 | FileCheck %s
1212

13-
# CHECK: BOLT-INFO: Multiple fragments access same jump table: main; main.cold.1
13+
# CHECK: BOLT-INFO: multiple fragments access the same jump table: main; main.cold.1
1414
# CHECK: PIC Jump table JUMP_TABLE1 for function main, main.cold.1 at {{.*}} with a total count of 0:
1515

1616
.text

bolt/test/link_fdata.py

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
"""
99

1010
import argparse
11+
import os
1112
import subprocess
1213
import sys
1314
import re
@@ -84,8 +85,16 @@
8485
exit("ERROR: unexpected input:\n%s" % line)
8586

8687
# Read nm output: <symbol value> <symbol type> <symbol name>
88+
is_llvm_nm = os.path.basename(args.nmtool) == "llvm-nm"
8789
nm_output = subprocess.run(
88-
[args.nmtool, "--defined-only", args.objfile], text=True, capture_output=True
90+
[
91+
args.nmtool,
92+
"--defined-only",
93+
"--special-syms" if is_llvm_nm else "--synthetic",
94+
args.objfile,
95+
],
96+
text=True,
97+
capture_output=True,
8998
).stdout
9099
# Populate symbol map
91100
symbols = {}

clang-tools-extra/clang-tidy/bugprone/UnintendedCharOstreamOutputCheck.cpp

Lines changed: 16 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,8 @@
77
//===----------------------------------------------------------------------===//
88

99
#include "UnintendedCharOstreamOutputCheck.h"
10+
#include "../utils/Matchers.h"
11+
#include "../utils/OptionsUtils.h"
1012
#include "clang/AST/Type.h"
1113
#include "clang/ASTMatchers/ASTMatchFinder.h"
1214
#include "clang/ASTMatchers/ASTMatchers.h"
@@ -35,10 +37,14 @@ AST_MATCHER(Type, isChar) {
3537

3638
UnintendedCharOstreamOutputCheck::UnintendedCharOstreamOutputCheck(
3739
StringRef Name, ClangTidyContext *Context)
38-
: ClangTidyCheck(Name, Context), CastTypeName(Options.get("CastTypeName")) {
39-
}
40+
: ClangTidyCheck(Name, Context),
41+
AllowedTypes(utils::options::parseStringList(
42+
Options.get("AllowedTypes", "unsigned char;signed char"))),
43+
CastTypeName(Options.get("CastTypeName")) {}
4044
void UnintendedCharOstreamOutputCheck::storeOptions(
4145
ClangTidyOptions::OptionMap &Opts) {
46+
Options.store(Opts, "AllowedTypes",
47+
utils::options::serializeStringList(AllowedTypes));
4248
if (CastTypeName.has_value())
4349
Options.store(Opts, "CastTypeName", CastTypeName.value());
4450
}
@@ -50,13 +56,20 @@ void UnintendedCharOstreamOutputCheck::registerMatchers(MatchFinder *Finder) {
5056
// with char / unsigned char / signed char
5157
classTemplateSpecializationDecl(
5258
hasTemplateArgument(0, refersToType(isChar()))));
59+
auto IsDeclRefExprFromAllowedTypes = declRefExpr(to(varDecl(
60+
hasType(matchers::matchesAnyListedTypeName(AllowedTypes, false)))));
61+
auto IsExplicitCastExprFromAllowedTypes = explicitCastExpr(hasDestinationType(
62+
matchers::matchesAnyListedTypeName(AllowedTypes, false)));
5363
Finder->addMatcher(
5464
cxxOperatorCallExpr(
5565
hasOverloadedOperatorName("<<"),
5666
hasLHS(hasType(hasUnqualifiedDesugaredType(
5767
recordType(hasDeclaration(cxxRecordDecl(
5868
anyOf(BasicOstream, isDerivedFrom(BasicOstream)))))))),
59-
hasRHS(hasType(hasUnqualifiedDesugaredType(isNumericChar()))))
69+
hasRHS(expr(hasType(hasUnqualifiedDesugaredType(isNumericChar())),
70+
unless(ignoringParenImpCasts(
71+
anyOf(IsDeclRefExprFromAllowedTypes,
72+
IsExplicitCastExprFromAllowedTypes))))))
6073
.bind("x"),
6174
this);
6275
}

0 commit comments

Comments
 (0)