@@ -193,18 +193,43 @@ class StaleMatcher {
193193public:
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
236271void 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.
0 commit comments