@@ -31,6 +31,14 @@ static cl::opt<bool> DisableCGDataForMerging(
31
31
" merging is still enabled within a module." ),
32
32
cl::init(false ));
33
33
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" );
34
42
STATISTIC (NumMergedFunctions,
35
43
" Number of functions that are actually merged using function hash" );
36
44
STATISTIC (NumAnalyzedModues, " Number of modules that are analyzed" );
@@ -102,7 +110,7 @@ bool isEligibleFunction(Function *F) {
102
110
return true ;
103
111
}
104
112
105
- static bool isEligibleInstructionForConstantSharing (const Instruction *I) {
113
+ static bool isEligibleInstrunctionForConstantSharing (const Instruction *I) {
106
114
switch (I->getOpcode ()) {
107
115
case Instruction::Load:
108
116
case Instruction::Store:
@@ -114,15 +122,10 @@ static bool isEligibleInstructionForConstantSharing(const Instruction *I) {
114
122
}
115
123
}
116
124
117
- // This function takes an instruction, \p I, and an operand index, \p OpIdx.
118
- // It returns true if the operand should be ignored in the hash computation.
119
- // If \p OpIdx is out of range based on the other instruction context, it cannot
120
- // be ignored.
121
125
static bool ignoreOp (const Instruction *I, unsigned OpIdx) {
122
- if (OpIdx >= I->getNumOperands ())
123
- return false ;
126
+ assert (OpIdx < I->getNumOperands () && " Invalid operand index" );
124
127
125
- if (!isEligibleInstructionForConstantSharing (I))
128
+ if (!isEligibleInstrunctionForConstantSharing (I))
126
129
return false ;
127
130
128
131
if (!isa<Constant>(I->getOperand (OpIdx)))
@@ -200,9 +203,9 @@ void GlobalMergeFunc::analyze(Module &M) {
200
203
struct FuncMergeInfo {
201
204
StableFunctionMap::StableFunctionEntry *SF;
202
205
Function *F;
203
- IndexInstrMap * IndexInstruction;
206
+ std::unique_ptr< IndexInstrMap> IndexInstruction;
204
207
FuncMergeInfo (StableFunctionMap::StableFunctionEntry *SF, Function *F,
205
- IndexInstrMap * IndexInstruction)
208
+ std::unique_ptr< IndexInstrMap> IndexInstruction)
206
209
: SF(SF), F(F), IndexInstruction(std::move(IndexInstruction)) {}
207
210
};
208
211
@@ -417,75 +420,101 @@ static ParamLocsVecTy computeParamInfo(
417
420
bool GlobalMergeFunc::merge (Module &M, const StableFunctionMap *FunctionMap) {
418
421
bool Changed = false ;
419
422
420
- // Collect stable functions related to the current module.
421
- DenseMap<stable_hash, SmallVector<std::pair<Function *, FunctionHashInfo>>>
422
- HashToFuncs;
423
- auto &Maps = FunctionMap->getFunctionMap ();
424
- for (auto &F : M) {
425
- if (!isEligibleFunction (&F))
426
- continue ;
427
- auto FI = llvm::StructuralHashWithDifferences (F, ignoreOp);
428
- if (Maps.contains (FI.FunctionHash ))
429
- HashToFuncs[FI.FunctionHash ].emplace_back (&F, std::move (FI));
430
- }
431
-
432
- for (auto &[Hash, Funcs] : HashToFuncs) {
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.
433
434
std::optional<ParamLocsVecTy> ParamLocsVec;
435
+ Function *MergedFunc = nullptr ;
436
+ std::string MergedModId;
434
437
SmallVector<FuncMergeInfo> FuncMergeInfos;
435
- auto &SFS = Maps.at (Hash);
436
- assert (!SFS.empty ());
437
- auto &RFS = SFS[0 ];
438
-
439
- // Iterate functions with the same hash.
440
- for (auto &[F, FI] : Funcs) {
441
- // Check if the function is compatible with any stable function
442
- // in terms of the number of instructions and ignored operands.
443
- if (RFS->InstCount != FI.IndexInstruction ->size ())
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))
444
451
continue ;
445
452
446
- auto hasValidSharedConst =
447
- [&](StableFunctionMap::StableFunctionEntry *SF) {
448
- for (auto &[Index, Hash] : *SF->IndexOperandHashMap ) {
449
- auto [InstIndex, OpndIndex] = Index;
450
- assert (InstIndex < FI.IndexInstruction ->size ());
451
- auto *Inst = FI.IndexInstruction ->lookup (InstIndex);
452
- if (!ignoreOp (Inst, OpndIndex))
453
- return false ;
454
- }
455
- return true ;
456
- };
457
- if (!hasValidSharedConst (RFS.get ()))
453
+ auto FI = llvm::StructuralHashWithDifferences (*F, ignoreOp);
454
+ uint64_t FuncHash = FI.FunctionHash ;
455
+ if (Hash != FuncHash) {
456
+ ++NumMismatchedFunctionHash;
458
457
continue ;
458
+ }
459
459
460
- for ( auto &SF : SFS ) {
461
- assert (SF-> InstCount == FI. IndexInstruction -> size ()) ;
462
- assert ( hasValidSharedConst (SF. get ())) ;
463
- // Check if there is any stable function that is compatiable with the
464
- // current one.
465
- if (! checkConstHashCompatible ( *SF->IndexOperandHashMap ,
466
- *FI. IndexOperandHashMap ))
467
- continue ;
468
- if (!ParamLocsVec. has_value ()) {
469
- ParamLocsVec = computeParamInfo (SFS);
470
- LLVM_DEBUG ( dbgs () << " [GlobalMergeFunc] Merging hash: " << Hash
471
- << " with Params " << ParamLocsVec-> size () << " \n " ) ;
460
+ if (SF-> InstCount != FI. IndexInstruction -> size () ) {
461
+ ++NumMismatchedInstCount ;
462
+ 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
472
}
473
- if (!checkConstLocationCompatible (*SF, *FI.IndexInstruction ,
474
- *ParamLocsVec))
475
- continue ;
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;
491
+ continue ;
492
+ }
476
493
477
- // If a stable function matching the current one is found,
478
- // create a candidate for merging and proceed to the next function.
479
- FuncMergeInfos.emplace_back (SF.get (), F, FI.IndexInstruction .get ());
480
- break ;
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;
502
+ continue ;
503
+ }
504
+ } else {
505
+ MergedFunc = F;
506
+ MergedModId = *FunctionMap->getNameForId (SF->ModuleNameId );
481
507
}
508
+
509
+ FuncMergeInfos.emplace_back (SF.get (), F, std::move (FI.IndexInstruction ));
510
+ MergedFunctions.insert (F);
482
511
}
483
512
unsigned FuncMergeInfoSize = FuncMergeInfos.size ();
484
513
if (FuncMergeInfoSize == 0 )
485
514
continue ;
486
515
487
516
LLVM_DEBUG (dbgs () << " [GlobalMergeFunc] Merging function count "
488
- << FuncMergeInfoSize << " for hash: " << Hash << " \n " );
517
+ << FuncMergeInfoSize << " in " << ModId << " \n " );
489
518
490
519
for (auto &FMI : FuncMergeInfos) {
491
520
Changed = true ;
0 commit comments