Skip to content

Commit b6d84e4

Browse files
Merge remote-tracking branch 'upstream/main' into FixTestSegFault
2 parents cdffa12 + c471d36 commit b6d84e4

File tree

1,205 files changed

+33592
-10471
lines changed

Some content is hidden

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

1,205 files changed

+33592
-10471
lines changed

bolt/include/bolt/Core/DebugData.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -226,6 +226,9 @@ class DebugRangesSectionWriter {
226226
/// Needs to be invoked before each \p CU is processed.
227227
void virtual initSection(DWARFUnit &CU){};
228228

229+
/// Initializes Ranges section with empty list.
230+
void initSection();
231+
229232
protected:
230233
std::unique_ptr<DebugBufferVector> RangesBuffer;
231234

bolt/include/bolt/Core/HashUtilities.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616

1717
#include "bolt/Core/BinaryBasicBlock.h"
1818
#include "bolt/Core/BinaryContext.h"
19+
#include "bolt/Profile/ProfileYAMLMapping.h"
1920

2021
namespace llvm {
2122
namespace bolt {
@@ -35,6 +36,13 @@ std::string hashBlock(BinaryContext &BC, const BinaryBasicBlock &BB,
3536

3637
std::string hashBlockLoose(BinaryContext &BC, const BinaryBasicBlock &BB);
3738

39+
std::string hashBlockCalls(BinaryContext &BC, const BinaryBasicBlock &BB);
40+
41+
std::string
42+
hashBlockCalls(const DenseMap<uint32_t, yaml::bolt::BinaryFunctionProfile *>
43+
&IdToYamlFunction,
44+
const yaml::bolt::BinaryBasicBlockProfile &YamlBB);
45+
3846
} // namespace bolt
3947
} // namespace llvm
4048

bolt/include/bolt/Profile/YAMLProfileReader.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class YAMLProfileReader : public ProfileReaderBase {
4040
/// Check if the file contains YAML.
4141
static bool isYAML(StringRef Filename);
4242

43+
using ProfileLookupMap =
44+
DenseMap<uint32_t, yaml::bolt::BinaryFunctionProfile *>;
45+
4346
private:
4447
/// Adjustments for basic samples profiles (without LBR).
4548
bool NormalizeByInsnCount{false};
@@ -56,6 +59,10 @@ class YAMLProfileReader : public ProfileReaderBase {
5659
/// is attributed.
5760
FunctionSet ProfiledFunctions;
5861

62+
/// Maps profiled function id to function, for function matching with calls as
63+
/// anchors.
64+
ProfileLookupMap IdToYamLBF;
65+
5966
/// For LTO symbol resolution.
6067
/// Map a common LTO prefix to a list of YAML profiles matching the prefix.
6168
StringMap<std::vector<yaml::bolt::BinaryFunctionProfile *>> LTOCommonNameMap;

bolt/include/bolt/Utils/NameResolver.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,12 @@ class NameResolver {
6161
std::tie(LHS, RHS) = UniqueName.split(Sep);
6262
return (LHS + Suffix + Twine(Sep) + RHS).str();
6363
}
64+
65+
// Drops the suffix that describes the function's number of names.
66+
static StringRef dropNumNames(StringRef Name) {
67+
const size_t Pos = Name.find("(*");
68+
return Pos != StringRef::npos ? Name.substr(0, Pos) : Name;
69+
}
6470
};
6571

6672
} // namespace bolt

bolt/lib/Core/DebugData.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -137,11 +137,14 @@ DebugRangesSectionWriter::DebugRangesSectionWriter() {
137137
RangesBuffer = std::make_unique<DebugBufferVector>();
138138
RangesStream = std::make_unique<raw_svector_ostream>(*RangesBuffer);
139139

140-
// Add an empty range as the first entry;
141-
writeAddressRanges(*RangesStream.get(), DebugAddressRangesVector{});
142140
Kind = RangesWriterKind::DebugRangesWriter;
143141
}
144142

143+
void DebugRangesSectionWriter::initSection() {
144+
// Adds an empty range to the buffer.
145+
writeAddressRanges(*RangesStream.get(), DebugAddressRangesVector{});
146+
}
147+
145148
uint64_t DebugRangesSectionWriter::addRanges(
146149
DebugAddressRangesVector &&Ranges,
147150
std::map<DebugAddressRangesVector, uint64_t> &CachedRanges) {

bolt/lib/Core/HashUtilities.cpp

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212

1313
#include "bolt/Core/HashUtilities.h"
1414
#include "bolt/Core/BinaryContext.h"
15+
#include "bolt/Utils/NameResolver.h"
1516
#include "llvm/MC/MCInstPrinter.h"
1617

1718
namespace llvm {
@@ -155,5 +156,50 @@ std::string hashBlockLoose(BinaryContext &BC, const BinaryBasicBlock &BB) {
155156
return HashString;
156157
}
157158

159+
/// An even looser hash level relative to $ hashBlockLoose to use with stale
160+
/// profile matching, composed of the names of a block's called functions in
161+
/// lexicographic order.
162+
std::string hashBlockCalls(BinaryContext &BC, const BinaryBasicBlock &BB) {
163+
// The hash is computed by creating a string of all lexicographically ordered
164+
// called function names.
165+
std::vector<std::string> FunctionNames;
166+
for (const MCInst &Instr : BB) {
167+
// Skip non-call instructions.
168+
if (!BC.MIB->isCall(Instr))
169+
continue;
170+
const MCSymbol *CallSymbol = BC.MIB->getTargetSymbol(Instr);
171+
if (!CallSymbol)
172+
continue;
173+
FunctionNames.push_back(std::string(CallSymbol->getName()));
174+
}
175+
std::sort(FunctionNames.begin(), FunctionNames.end());
176+
std::string HashString;
177+
for (const std::string &FunctionName : FunctionNames)
178+
HashString.append(FunctionName);
179+
180+
return HashString;
181+
}
182+
183+
/// The same as the $hashBlockCalls function, but for profiled functions.
184+
std::string
185+
hashBlockCalls(const DenseMap<uint32_t, yaml::bolt::BinaryFunctionProfile *>
186+
&IdToYamlFunction,
187+
const yaml::bolt::BinaryBasicBlockProfile &YamlBB) {
188+
std::vector<std::string> FunctionNames;
189+
for (const yaml::bolt::CallSiteInfo &CallSiteInfo : YamlBB.CallSites) {
190+
auto It = IdToYamlFunction.find(CallSiteInfo.DestId);
191+
if (It == IdToYamlFunction.end())
192+
continue;
193+
StringRef Name = NameResolver::dropNumNames(It->second->Name);
194+
FunctionNames.push_back(std::string(Name));
195+
}
196+
std::sort(FunctionNames.begin(), FunctionNames.end());
197+
std::string HashString;
198+
for (const std::string &FunctionName : FunctionNames)
199+
HashString.append(FunctionName);
200+
201+
return HashString;
202+
}
203+
158204
} // namespace bolt
159205
} // namespace llvm

bolt/lib/Profile/StaleProfileMatching.cpp

Lines changed: 84 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -193,18 +193,43 @@ class StaleMatcher {
193193
public:
194194
/// Initialize stale matcher.
195195
void init(const std::vector<FlowBlock *> &Blocks,
196-
const std::vector<BlendedBlockHash> &Hashes) {
196+
const std::vector<BlendedBlockHash> &Hashes,
197+
const std::vector<uint64_t> &CallHashes) {
197198
assert(Blocks.size() == Hashes.size() &&
199+
Hashes.size() == CallHashes.size() &&
198200
"incorrect matcher initialization");
199201
for (size_t I = 0; I < Blocks.size(); I++) {
200202
FlowBlock *Block = Blocks[I];
201203
uint16_t OpHash = Hashes[I].OpcodeHash;
202204
OpHashToBlocks[OpHash].push_back(std::make_pair(Hashes[I], Block));
205+
if (CallHashes[I])
206+
CallHashToBlocks[CallHashes[I]].push_back(
207+
std::make_pair(Hashes[I], Block));
203208
}
204209
}
205210

206211
/// Find the most similar block for a given hash.
207-
const FlowBlock *matchBlock(BlendedBlockHash BlendedHash) const {
212+
const FlowBlock *matchBlock(BlendedBlockHash BlendedHash,
213+
uint64_t CallHash) const {
214+
const FlowBlock *BestBlock = matchWithOpcodes(BlendedHash);
215+
return BestBlock ? BestBlock : matchWithCalls(BlendedHash, CallHash);
216+
}
217+
218+
/// Returns true if the two basic blocks (in the binary and in the profile)
219+
/// corresponding to the given hashes are matched to each other with a high
220+
/// confidence.
221+
static bool isHighConfidenceMatch(BlendedBlockHash Hash1,
222+
BlendedBlockHash Hash2) {
223+
return Hash1.InstrHash == Hash2.InstrHash;
224+
}
225+
226+
private:
227+
using HashBlockPairType = std::pair<BlendedBlockHash, FlowBlock *>;
228+
std::unordered_map<uint16_t, std::vector<HashBlockPairType>> OpHashToBlocks;
229+
std::unordered_map<uint64_t, std::vector<HashBlockPairType>> CallHashToBlocks;
230+
231+
// Uses OpcodeHash to find the most similar block for a given hash.
232+
const FlowBlock *matchWithOpcodes(BlendedBlockHash BlendedHash) const {
208233
auto BlockIt = OpHashToBlocks.find(BlendedHash.OpcodeHash);
209234
if (BlockIt == OpHashToBlocks.end())
210235
return nullptr;
@@ -220,17 +245,27 @@ class StaleMatcher {
220245
return BestBlock;
221246
}
222247

223-
/// Returns true if the two basic blocks (in the binary and in the profile)
224-
/// corresponding to the given hashes are matched to each other with a high
225-
/// confidence.
226-
static bool isHighConfidenceMatch(BlendedBlockHash Hash1,
227-
BlendedBlockHash Hash2) {
228-
return Hash1.InstrHash == Hash2.InstrHash;
248+
// Uses CallHash to find the most similar block for a given hash.
249+
const FlowBlock *matchWithCalls(BlendedBlockHash BlendedHash,
250+
uint64_t CallHash) const {
251+
if (!CallHash)
252+
return nullptr;
253+
auto BlockIt = CallHashToBlocks.find(CallHash);
254+
if (BlockIt == CallHashToBlocks.end())
255+
return nullptr;
256+
FlowBlock *BestBlock = nullptr;
257+
uint64_t BestDist = std::numeric_limits<uint64_t>::max();
258+
for (const auto &[Hash, Block] : BlockIt->second) {
259+
uint64_t Dist = Hash.OpcodeHash > BlendedHash.OpcodeHash
260+
? Hash.OpcodeHash - BlendedHash.OpcodeHash
261+
: BlendedHash.OpcodeHash - Hash.OpcodeHash;
262+
if (BestBlock == nullptr || Dist < BestDist) {
263+
BestDist = Dist;
264+
BestBlock = Block;
265+
}
266+
}
267+
return BestBlock;
229268
}
230-
231-
private:
232-
using HashBlockPairType = std::pair<BlendedBlockHash, FlowBlock *>;
233-
std::unordered_map<uint16_t, std::vector<HashBlockPairType>> OpHashToBlocks;
234269
};
235270

236271
void BinaryFunction::computeBlockHashes(HashFunction HashFunction) const {
@@ -412,33 +447,62 @@ createFlowFunction(const BinaryFunction::BasicBlockOrderType &BlockOrder) {
412447
/// of the basic blocks in the binary, the count is "matched" to the block.
413448
/// Similarly, if both the source and the target of a count in the profile are
414449
/// matched to a jump in the binary, the count is recorded in CFG.
415-
size_t matchWeightsByHashes(
416-
BinaryContext &BC, const BinaryFunction::BasicBlockOrderType &BlockOrder,
417-
const yaml::bolt::BinaryFunctionProfile &YamlBF, FlowFunction &Func) {
450+
size_t
451+
matchWeightsByHashes(BinaryContext &BC,
452+
const BinaryFunction::BasicBlockOrderType &BlockOrder,
453+
const yaml::bolt::BinaryFunctionProfile &YamlBF,
454+
FlowFunction &Func, HashFunction HashFunction,
455+
YAMLProfileReader::ProfileLookupMap &IdToYamlBF) {
456+
418457
assert(Func.Blocks.size() == BlockOrder.size() + 2);
419458

459+
std::vector<uint64_t> CallHashes;
420460
std::vector<FlowBlock *> Blocks;
421461
std::vector<BlendedBlockHash> BlendedHashes;
422462
for (uint64_t I = 0; I < BlockOrder.size(); I++) {
423463
const BinaryBasicBlock *BB = BlockOrder[I];
424464
assert(BB->getHash() != 0 && "empty hash of BinaryBasicBlock");
465+
466+
std::string CallHashStr = hashBlockCalls(BC, *BB);
467+
if (CallHashStr.empty()) {
468+
CallHashes.push_back(0);
469+
} else {
470+
if (HashFunction == HashFunction::StdHash)
471+
CallHashes.push_back(std::hash<std::string>{}(CallHashStr));
472+
else if (HashFunction == HashFunction::XXH3)
473+
CallHashes.push_back(llvm::xxh3_64bits(CallHashStr));
474+
else
475+
llvm_unreachable("Unhandled HashFunction");
476+
}
477+
425478
Blocks.push_back(&Func.Blocks[I + 1]);
426479
BlendedBlockHash BlendedHash(BB->getHash());
427480
BlendedHashes.push_back(BlendedHash);
428481
LLVM_DEBUG(dbgs() << "BB with index " << I << " has hash = "
429482
<< Twine::utohexstr(BB->getHash()) << "\n");
430483
}
431484
StaleMatcher Matcher;
432-
Matcher.init(Blocks, BlendedHashes);
485+
Matcher.init(Blocks, BlendedHashes, CallHashes);
433486

434487
// Index in yaml profile => corresponding (matched) block
435488
DenseMap<uint64_t, const FlowBlock *> MatchedBlocks;
436489
// Match blocks from the profile to the blocks in CFG
437490
for (const yaml::bolt::BinaryBasicBlockProfile &YamlBB : YamlBF.Blocks) {
438491
assert(YamlBB.Hash != 0 && "empty hash of BinaryBasicBlockProfile");
439492
BlendedBlockHash YamlHash(YamlBB.Hash);
440-
const FlowBlock *MatchedBlock = Matcher.matchBlock(YamlHash);
441-
// Always match the entry block.
493+
494+
const FlowBlock *MatchedBlock = nullptr;
495+
std::string CallHashStr = hashBlockCalls(IdToYamlBF, YamlBB);
496+
uint64_t CallHash = 0;
497+
if (!CallHashStr.empty()) {
498+
if (HashFunction == HashFunction::StdHash)
499+
CallHash = std::hash<std::string>{}(CallHashStr);
500+
else if (HashFunction == HashFunction::XXH3)
501+
CallHash = llvm::xxh3_64bits(CallHashStr);
502+
else
503+
llvm_unreachable("Unhandled HashFunction");
504+
}
505+
MatchedBlock = Matcher.matchBlock(YamlHash, CallHash);
442506
if (MatchedBlock == nullptr && YamlBB.Index == 0)
443507
MatchedBlock = Blocks[0];
444508
if (MatchedBlock != nullptr) {
@@ -763,7 +827,8 @@ bool YAMLProfileReader::inferStaleProfile(
763827

764828
// Match as many block/jump counts from the stale profile as possible
765829
size_t MatchedBlocks =
766-
matchWeightsByHashes(BF.getBinaryContext(), BlockOrder, YamlBF, Func);
830+
matchWeightsByHashes(BF.getBinaryContext(), BlockOrder, YamlBF, Func,
831+
YamlBP.Header.HashFunction, IdToYamLBF);
767832

768833
// Adjust the flow function by marking unreachable blocks Unlikely so that
769834
// they don't get any counts assigned.

bolt/lib/Profile/YAMLProfileReader.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -611,6 +611,10 @@ Error YAMLProfileReader::readProfile(BinaryContext &BC) {
611611
NormalizeByInsnCount = usesEvent("cycles") || usesEvent("instructions");
612612
NormalizeByCalls = usesEvent("branches");
613613

614+
// Map profiled function ids to names.
615+
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions)
616+
IdToYamLBF[YamlBF.Id] = &YamlBF;
617+
614618
uint64_t NumUnused = 0;
615619
for (yaml::bolt::BinaryFunctionProfile &YamlBF : YamlBP.Functions) {
616620
if (YamlBF.Id >= YamlProfileToFunction.size()) {

bolt/lib/Rewrite/DWARFRewriter.cpp

Lines changed: 18 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -620,8 +620,10 @@ void DWARFRewriter::updateDebugInfo() {
620620
AddrWriter = std::make_unique<DebugAddrWriter>(&BC);
621621
}
622622

623-
if (BC.isDWARFLegacyUsed())
623+
if (BC.isDWARFLegacyUsed()) {
624624
LegacyRangesSectionWriter = std::make_unique<DebugRangesSectionWriter>();
625+
LegacyRangesSectionWriter->initSection();
626+
}
625627

626628
DebugLoclistWriter::setAddressWriter(AddrWriter.get());
627629

@@ -651,7 +653,6 @@ void DWARFRewriter::updateDebugInfo() {
651653
"LegacyRangeLists writer for DWO unit already exists.");
652654
auto LegacyRangesSectionWriterByCU =
653655
std::make_unique<DebugRangesSectionWriter>();
654-
LegacyRangesSectionWriterByCU->initSection(CU);
655656
LegacyRangesWritersByCU[*DWOId] =
656657
std::move(LegacyRangesSectionWriterByCU);
657658
}
@@ -2161,21 +2162,21 @@ void DWARFRewriter::convertToRangesPatchDebugInfo(
21612162
DIEBldr.replaceValue(&Die, LowPCAttrInfo.getAttribute(),
21622163
LowPCAttrInfo.getForm(), DIEInteger(0));
21632164
}
2164-
}
2165-
// Original CU didn't have DW_AT_*_base. We converted it's children (or
2166-
// dwo), so need to insert it into CU.
2167-
if (RangesBase) {
2168-
if (Unit.getVersion() >= 5) {
2169-
DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,
2170-
DIEInteger(*RangesBase));
2171-
} else {
2172-
DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,
2173-
DIEInteger(INT_MAX));
2174-
auto RangesWriterIterator =
2175-
LegacyRangesWritersByCU.find(*Unit.getDWOId());
2176-
assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&
2177-
"RangesWriter does not exist for DWOId");
2178-
RangesWriterIterator->second->setDie(&Die);
2165+
// Original CU didn't have DW_AT_*_base. We converted it's children (or
2166+
// dwo), so need to insert it into CU.
2167+
if (RangesBase) {
2168+
if (Unit.getVersion() >= 5) {
2169+
DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,
2170+
DIEInteger(*RangesBase));
2171+
} else {
2172+
DIEBldr.addValue(&Die, RangeBaseAttribute, dwarf::DW_FORM_sec_offset,
2173+
DIEInteger(INT_MAX));
2174+
auto RangesWriterIterator =
2175+
LegacyRangesWritersByCU.find(*Unit.getDWOId());
2176+
assert(RangesWriterIterator != LegacyRangesWritersByCU.end() &&
2177+
"RangesWriter does not exist for DWOId");
2178+
RangesWriterIterator->second->setDie(&Die);
2179+
}
21792180
}
21802181
}
21812182

bolt/test/X86/debug-fission-single-convert.s

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -27,15 +27,15 @@
2727

2828
# CHECK-NOT: warning: DWARF unit from offset {{.*}} incl. to offset {{.*}} excl. tries to read DIEs at offset {{.*}}
2929

30+
# CHECK-DWO-DWO: 00000000
3031
# CHECK-DWO-DWO: 00000010
3132
# CHECK-DWO-DWO: 00000010
32-
# CHECK-DWO-DWO: 00000050
3333
# CHECK-DWO-DWO: DW_TAG_subprogram
34-
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000010
34+
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000000
3535
# CHECK-DWO-DWO: DW_TAG_subprogram
36-
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000030
36+
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000020
3737
# CHECK-DWO-DWO: DW_TAG_subprogram
38-
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000050
38+
# CHECK-DWO-DWO-NEXT: DW_AT_ranges [DW_FORM_sec_offset] (0x00000040
3939

4040
# CHECK-ADDR-SEC: .debug_addr contents:
4141
# CHECK-ADDR-SEC: 0x00000000: Addrs: [

0 commit comments

Comments
 (0)