@@ -31,14 +31,6 @@ static cl::opt<bool> DisableCGDataForMerging(
3131 " merging is still enabled within a module." ),
3232 cl::init(false ));
3333
34- STATISTIC (NumMismatchedFunctionHash,
35- " Number of mismatched function hash for global merge function" );
36- STATISTIC (NumMismatchedInstCount,
37- " Number of mismatched instruction count for global merge function" );
38- STATISTIC (NumMismatchedConstHash,
39- " Number of mismatched const hash for global merge function" );
40- STATISTIC (NumMismatchedModuleId,
41- " Number of mismatched Module Id for global merge function" );
4234STATISTIC (NumMergedFunctions,
4335 " Number of functions that are actually merged using function hash" );
4436STATISTIC (NumAnalyzedModues, " Number of modules that are analyzed" );
@@ -203,9 +195,9 @@ void GlobalMergeFunc::analyze(Module &M) {
203195struct FuncMergeInfo {
204196 StableFunctionMap::StableFunctionEntry *SF;
205197 Function *F;
206- std::unique_ptr< IndexInstrMap> IndexInstruction;
198+ IndexInstrMap * IndexInstruction;
207199 FuncMergeInfo (StableFunctionMap::StableFunctionEntry *SF, Function *F,
208- std::unique_ptr< IndexInstrMap> IndexInstruction)
200+ IndexInstrMap * IndexInstruction)
209201 : SF(SF), F(F), IndexInstruction(std::move(IndexInstruction)) {}
210202};
211203
@@ -420,101 +412,79 @@ static ParamLocsVecTy computeParamInfo(
420412bool GlobalMergeFunc::merge (Module &M, const StableFunctionMap *FunctionMap) {
421413 bool Changed = false ;
422414
423- // Build a map from stable function name to function.
424- StringMap<Function *> StableNameToFuncMap;
425- for (auto &F : M)
426- StableNameToFuncMap[get_stable_name (F.getName ())] = &F;
427- // Track merged functions
428- DenseSet<Function *> MergedFunctions;
429-
430- auto ModId = M.getModuleIdentifier ();
431- for (auto &[Hash, SFS] : FunctionMap->getFunctionMap ()) {
432- // Parameter locations based on the unique hash sequences
433- // across the candidates.
415+ // Collect stable functions related to the current module.
416+ DenseMap<stable_hash, SmallVector<Function *>> HashToFuncs;
417+ DenseMap<Function *, FunctionHashInfo> FuncToFI;
418+ auto &Maps = FunctionMap->getFunctionMap ();
419+ for (auto &F : M) {
420+ if (!isEligibleFunction (&F))
421+ continue ;
422+ auto FI = llvm::StructuralHashWithDifferences (F, ignoreOp);
423+ if (Maps.contains (FI.FunctionHash )) {
424+ HashToFuncs[FI.FunctionHash ].push_back (&F);
425+ FuncToFI.try_emplace (&F, std::move (FI));
426+ }
427+ }
428+
429+ for (auto &[Hash, Funcs] : HashToFuncs) {
434430 std::optional<ParamLocsVecTy> ParamLocsVec;
435- Function *MergedFunc = nullptr ;
436- std::string MergedModId;
437431 SmallVector<FuncMergeInfo> FuncMergeInfos;
438- for (auto &SF : SFS) {
439- // Get the function from the stable name.
440- auto I = StableNameToFuncMap.find (
441- *FunctionMap->getNameForId (SF->FunctionNameId ));
442- if (I == StableNameToFuncMap.end ())
443- continue ;
444- Function *F = I->second ;
445- assert (F);
446- // Skip if the function has been merged before.
447- if (MergedFunctions.count (F))
448- continue ;
449- // Consider the function if it is eligible for merging.
450- if (!isEligibleFunction (F))
451- continue ;
452432
453- auto FI = llvm::StructuralHashWithDifferences (*F, ignoreOp);
454- uint64_t FuncHash = FI.FunctionHash ;
455- if (Hash != FuncHash) {
456- ++NumMismatchedFunctionHash;
457- continue ;
458- }
433+ // Iterate functions with the same hash.
434+ for (auto &F : Funcs) {
435+ auto &SFS = Maps.at (Hash);
436+ auto &FI = FuncToFI.at (F);
459437
460- if (SF->InstCount != FI.IndexInstruction ->size ()) {
461- ++NumMismatchedInstCount;
438+ // Check if the function is compatible with any stable function
439+ // in terms of the number of instructions and ignored operands.
440+ assert (!SFS.empty ());
441+ auto &RFS = SFS[0 ];
442+ if (RFS->InstCount != FI.IndexInstruction ->size ())
462443 continue ;
463- }
464- bool HasValidSharedConst = true ;
465- for (auto &[Index, Hash] : *SF->IndexOperandHashMap ) {
466- auto [InstIndex, OpndIndex] = Index;
467- assert (InstIndex < FI.IndexInstruction ->size ());
468- auto *Inst = FI.IndexInstruction ->lookup (InstIndex);
469- if (!ignoreOp (Inst, OpndIndex)) {
470- HasValidSharedConst = false ;
471- break ;
472- }
473- }
474- if (!HasValidSharedConst) {
475- ++NumMismatchedConstHash;
476- continue ;
477- }
478- if (!checkConstHashCompatible (*SF->IndexOperandHashMap ,
479- *FI.IndexOperandHashMap )) {
480- ++NumMismatchedConstHash;
481- continue ;
482- }
483- if (!ParamLocsVec.has_value ()) {
484- ParamLocsVec = computeParamInfo (SFS);
485- LLVM_DEBUG (dbgs () << " [GlobalMergeFunc] Merging hash: " << Hash
486- << " with Params " << ParamLocsVec->size () << " \n " );
487- }
488- if (!checkConstLocationCompatible (*SF, *FI.IndexInstruction ,
489- *ParamLocsVec)) {
490- ++NumMismatchedConstHash;
444+
445+ auto hasValidSharedConst =
446+ [&](StableFunctionMap::StableFunctionEntry *SF) {
447+ for (auto &[Index, Hash] : *SF->IndexOperandHashMap ) {
448+ auto [InstIndex, OpndIndex] = Index;
449+ assert (InstIndex < FI.IndexInstruction ->size ());
450+ auto *Inst = FI.IndexInstruction ->lookup (InstIndex);
451+ if (!ignoreOp (Inst, OpndIndex))
452+ return false ;
453+ }
454+ return true ;
455+ };
456+ if (!hasValidSharedConst (RFS.get ()))
491457 continue ;
492- }
493458
494- if (MergedFunc) {
495- // Check if the matched functions fall into the same (first) module.
496- // This module check is not strictly necessary as the functions can move
497- // around. We just want to avoid merging functions from different
498- // modules than the first one in the function map, as they may not end
499- // up with being ICFed by the linker.
500- if (MergedModId != *FunctionMap->getNameForId (SF->ModuleNameId )) {
501- ++NumMismatchedModuleId;
459+ for (auto &SF : SFS) {
460+ assert (SF->InstCount == FI.IndexInstruction ->size ());
461+ assert (hasValidSharedConst (SF.get ()));
462+ // Check if there is any stable function that is compatiable with the
463+ // current one.
464+ if (!checkConstHashCompatible (*SF->IndexOperandHashMap ,
465+ *FI.IndexOperandHashMap ))
502466 continue ;
467+ if (!ParamLocsVec.has_value ()) {
468+ ParamLocsVec = computeParamInfo (SFS);
469+ LLVM_DEBUG (dbgs () << " [GlobalMergeFunc] Merging hash: " << Hash
470+ << " with Params " << ParamLocsVec->size () << " \n " );
503471 }
504- } else {
505- MergedFunc = F;
506- MergedModId = *FunctionMap->getNameForId (SF->ModuleNameId );
507- }
472+ if (!checkConstLocationCompatible (*SF, *FI.IndexInstruction ,
473+ *ParamLocsVec))
474+ continue ;
508475
509- FuncMergeInfos.emplace_back (SF.get (), F, std::move (FI.IndexInstruction ));
510- MergedFunctions.insert (F);
476+ // As long as we found one stable function matching the current one,
477+ // we create a candidate for merging and move on to the next function.
478+ FuncMergeInfos.emplace_back (SF.get (), F, FI.IndexInstruction .get ());
479+ break ;
480+ }
511481 }
512482 unsigned FuncMergeInfoSize = FuncMergeInfos.size ();
513483 if (FuncMergeInfoSize == 0 )
514484 continue ;
515485
516486 LLVM_DEBUG (dbgs () << " [GlobalMergeFunc] Merging function count "
517- << FuncMergeInfoSize << " in " << ModId << " \n " );
487+ << FuncMergeInfoSize << " for hash: " << Hash << " \n " );
518488
519489 for (auto &FMI : FuncMergeInfos) {
520490 Changed = true ;
0 commit comments