@@ -31,14 +31,6 @@ 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" );
42
34
STATISTIC (NumMergedFunctions,
43
35
" Number of functions that are actually merged using function hash" );
44
36
STATISTIC (NumAnalyzedModues, " Number of modules that are analyzed" );
@@ -110,7 +102,7 @@ bool isEligibleFunction(Function *F) {
110
102
return true ;
111
103
}
112
104
113
- static bool isEligibleInstrunctionForConstantSharing (const Instruction *I) {
105
+ static bool isEligibleInstructionForConstantSharing (const Instruction *I) {
114
106
switch (I->getOpcode ()) {
115
107
case Instruction::Load:
116
108
case Instruction::Store:
@@ -122,10 +114,15 @@ static bool isEligibleInstrunctionForConstantSharing(const Instruction *I) {
122
114
}
123
115
}
124
116
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.
125
121
static bool ignoreOp (const Instruction *I, unsigned OpIdx) {
126
- assert (OpIdx < I->getNumOperands () && " Invalid operand index" );
122
+ if (OpIdx >= I->getNumOperands ())
123
+ return false ;
127
124
128
- if (!isEligibleInstrunctionForConstantSharing (I))
125
+ if (!isEligibleInstructionForConstantSharing (I))
129
126
return false ;
130
127
131
128
if (!isa<Constant>(I->getOperand (OpIdx)))
@@ -203,9 +200,9 @@ void GlobalMergeFunc::analyze(Module &M) {
203
200
struct FuncMergeInfo {
204
201
StableFunctionMap::StableFunctionEntry *SF;
205
202
Function *F;
206
- std::unique_ptr< IndexInstrMap> IndexInstruction;
203
+ IndexInstrMap * IndexInstruction;
207
204
FuncMergeInfo (StableFunctionMap::StableFunctionEntry *SF, Function *F,
208
- std::unique_ptr< IndexInstrMap> IndexInstruction)
205
+ IndexInstrMap * IndexInstruction)
209
206
: SF(SF), F(F), IndexInstruction(std::move(IndexInstruction)) {}
210
207
};
211
208
@@ -420,101 +417,75 @@ static ParamLocsVecTy computeParamInfo(
420
417
bool GlobalMergeFunc::merge (Module &M, const StableFunctionMap *FunctionMap) {
421
418
bool Changed = false ;
422
419
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.
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) {
434
433
std::optional<ParamLocsVecTy> ParamLocsVec;
435
- Function *MergedFunc = nullptr ;
436
- std::string MergedModId;
437
434
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))
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 ())
451
444
continue ;
452
445
453
- auto FI = llvm::StructuralHashWithDifferences (*F, ignoreOp);
454
- uint64_t FuncHash = FI.FunctionHash ;
455
- if (Hash != FuncHash) {
456
- ++NumMismatchedFunctionHash;
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 ()))
457
458
continue ;
458
- }
459
459
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
- }
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
- }
493
-
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;
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 ))
502
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 " );
503
472
}
504
- } else {
505
- MergedFunc = F;
506
- MergedModId = *FunctionMap->getNameForId (SF->ModuleNameId );
507
- }
473
+ if (!checkConstLocationCompatible (*SF, *FI.IndexInstruction ,
474
+ *ParamLocsVec))
475
+ continue ;
508
476
509
- FuncMergeInfos.emplace_back (SF.get (), F, std::move (FI.IndexInstruction ));
510
- MergedFunctions.insert (F);
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 ;
481
+ }
511
482
}
512
483
unsigned FuncMergeInfoSize = FuncMergeInfos.size ();
513
484
if (FuncMergeInfoSize == 0 )
514
485
continue ;
515
486
516
487
LLVM_DEBUG (dbgs () << " [GlobalMergeFunc] Merging function count "
517
- << FuncMergeInfoSize << " in " << ModId << " \n " );
488
+ << FuncMergeInfoSize << " for hash: " << Hash << " \n " );
518
489
519
490
for (auto &FMI : FuncMergeInfos) {
520
491
Changed = true ;
0 commit comments