1//===---- GlobalMergeFunctions.cpp - Global merge functions -------*- C++ -===//
2//
3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4// See https://llvm.org/LICENSE.txt for license information.
5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6//
7//===----------------------------------------------------------------------===//
8//
9// This pass implements the global merge function pass.
10//
11//===----------------------------------------------------------------------===//
12
13#include "llvm/CodeGen/GlobalMergeFunctions.h"
14#include "llvm/ADT/Statistic.h"
15#include "llvm/Analysis/ModuleSummaryAnalysis.h"
16#include "llvm/CGData/CodeGenData.h"
17#include "llvm/CGData/CodeGenDataWriter.h"
18#include "llvm/CodeGen/Passes.h"
19#include "llvm/IR/IRBuilder.h"
20#include "llvm/IR/StructuralHash.h"
21#include "llvm/InitializePasses.h"
22#include "llvm/Support/CommandLine.h"
23#include "llvm/Transforms/Utils/ModuleUtils.h"
24
25#define DEBUG_TYPE "global-merge-func"
26
27using namespace llvm;
28using namespace llvm::support;
29
30static cl::opt<bool> DisableCGDataForMerging(
31 "disable-cgdata-for-merging", cl::Hidden,
32 cl::desc("Disable codegen data for function merging. Local "
33 "merging is still enabled within a module."),
34 cl::init(Val: false));
35
36STATISTIC(NumMergedFunctions,
37 "Number of functions that are actually merged using function hash");
38STATISTIC(NumAnalyzedModues, "Number of modules that are analyzed");
39STATISTIC(NumAnalyzedFunctions, "Number of functions that are analyzed");
40STATISTIC(NumEligibleFunctions, "Number of functions that are eligible");
41
42/// Returns true if the \OpIdx operand of \p CI is the callee operand.
43static bool isCalleeOperand(const CallBase *CI, unsigned OpIdx) {
44 return &CI->getCalledOperandUse() == &CI->getOperandUse(i: OpIdx);
45}
46
47static bool canParameterizeCallOperand(const CallBase *CI, unsigned OpIdx) {
48 if (CI->isInlineAsm())
49 return false;
50 Function *Callee = CI->getCalledOperand()
51 ? dyn_cast_or_null<Function>(
52 Val: CI->getCalledOperand()->stripPointerCasts())
53 : nullptr;
54 if (Callee) {
55 if (Callee->isIntrinsic())
56 return false;
57 auto Name = Callee->getName();
58 // objc_msgSend stubs must be called, and can't have their address taken.
59 if (Name.starts_with(Prefix: "objc_msgSend$"))
60 return false;
61 // Calls to dtrace probes must generate unique patchpoints.
62 if (Name.starts_with(Prefix: "__dtrace"))
63 return false;
64 }
65 if (isCalleeOperand(CI, OpIdx)) {
66 // The operand is the callee and it has already been signed. Ignore this
67 // because we cannot add another ptrauth bundle to the call instruction.
68 if (CI->getOperandBundle(ID: LLVMContext::OB_ptrauth).has_value())
69 return false;
70 } else {
71 // The target of the arc-attached call must be a constant and cannot be
72 // parameterized.
73 if (CI->isOperandBundleOfType(ID: LLVMContext::OB_clang_arc_attachedcall,
74 Idx: OpIdx))
75 return false;
76 }
77 return true;
78}
79
80/// Returns true if function \p F is eligible for merging.
81bool isEligibleFunction(Function *F) {
82 if (F->isDeclaration())
83 return false;
84
85 if (F->hasFnAttribute(Kind: llvm::Attribute::NoMerge) ||
86 F->hasFnAttribute(Kind: llvm::Attribute::AlwaysInline))
87 return false;
88
89 if (F->hasAvailableExternallyLinkage())
90 return false;
91
92 if (F->getFunctionType()->isVarArg())
93 return false;
94
95 if (F->getCallingConv() == CallingConv::SwiftTail)
96 return false;
97
98 // Unnamed functions are skipped for simplicity.
99 if (!F->hasName())
100 return false;
101
102 // If function contains callsites with musttail, if we merge
103 // it, the merged function will have the musttail callsite, but
104 // the number of parameters can change, thus the parameter count
105 // of the callsite will mismatch with the function itself.
106 for (const BasicBlock &BB : *F) {
107 for (const Instruction &I : BB) {
108 const auto *CB = dyn_cast<CallBase>(Val: &I);
109 if (CB && CB->isMustTailCall())
110 return false;
111 }
112 }
113
114 return true;
115}
116
117static bool isEligibleInstructionForConstantSharing(const Instruction *I) {
118 switch (I->getOpcode()) {
119 case Instruction::Load:
120 case Instruction::Store:
121 case Instruction::Call:
122 case Instruction::Invoke:
123 return true;
124 default:
125 return false;
126 }
127}
128
129// This function takes an instruction, \p I, and an operand index, \p OpIdx.
130// It returns true if the operand should be ignored in the hash computation.
131// If \p OpIdx is out of range based on the other instruction context, it cannot
132// be ignored.
133static bool ignoreOp(const Instruction *I, unsigned OpIdx) {
134 if (OpIdx >= I->getNumOperands())
135 return false;
136
137 if (!isEligibleInstructionForConstantSharing(I))
138 return false;
139
140 if (!isa<Constant>(Val: I->getOperand(i: OpIdx)))
141 return false;
142
143 if (const auto *CI = dyn_cast<CallBase>(Val: I))
144 return canParameterizeCallOperand(CI, OpIdx);
145
146 return true;
147}
148
149void GlobalMergeFunc::analyze(Module &M) {
150 ++NumAnalyzedModues;
151 for (Function &Func : M) {
152 ++NumAnalyzedFunctions;
153 if (isEligibleFunction(F: &Func)) {
154 ++NumEligibleFunctions;
155
156 auto FI = llvm::StructuralHashWithDifferences(F: Func, IgnoreOp: ignoreOp);
157
158 // Convert the operand map to a vector for a serialization-friendly
159 // format.
160 IndexOperandHashVecType IndexOperandHashes;
161 for (auto &Pair : *FI.IndexOperandHashMap)
162 IndexOperandHashes.emplace_back(Args&: Pair);
163
164 StableFunction SF(FI.FunctionHash, get_stable_name(Name: Func.getName()).str(),
165 M.getModuleIdentifier(), FI.IndexInstruction->size(),
166 std::move(IndexOperandHashes));
167
168 LocalFunctionMap->insert(Func: SF);
169 }
170 }
171}
172
173/// Tuple to hold function info to process merging.
174struct FuncMergeInfo {
175 StableFunctionMap::StableFunctionEntry *SF;
176 Function *F;
177 IndexInstrMap *IndexInstruction;
178 FuncMergeInfo(StableFunctionMap::StableFunctionEntry *SF, Function *F,
179 IndexInstrMap *IndexInstruction)
180 : SF(SF), F(F), IndexInstruction(std::move(IndexInstruction)) {}
181};
182
183// Given the func info, and the parameterized locations, create and return
184// a new merged function by replacing the original constants with the new
185// parameters.
186static Function *createMergedFunction(FuncMergeInfo &FI,
187 ArrayRef<Type *> ConstParamTypes,
188 const ParamLocsVecTy &ParamLocsVec) {
189 // Synthesize a new merged function name by appending ".Tgm" to the root
190 // function's name.
191 auto *MergedFunc = FI.F;
192 std::string NewFunctionName =
193 MergedFunc->getName().str() + GlobalMergeFunc::MergingInstanceSuffix;
194 auto *M = MergedFunc->getParent();
195 assert(!M->getFunction(NewFunctionName));
196
197 FunctionType *OrigTy = MergedFunc->getFunctionType();
198 // Get the original params' types.
199 SmallVector<Type *> ParamTypes(OrigTy->param_begin(), OrigTy->param_end());
200 // Append const parameter types that are passed in.
201 ParamTypes.append(in_start: ConstParamTypes.begin(), in_end: ConstParamTypes.end());
202 FunctionType *FuncType = FunctionType::get(Result: OrigTy->getReturnType(),
203 Params: ParamTypes, /*isVarArg=*/false);
204
205 // Declare a new function
206 Function *NewFunction =
207 Function::Create(Ty: FuncType, Linkage: MergedFunc->getLinkage(), N: NewFunctionName);
208 if (auto *SP = MergedFunc->getSubprogram())
209 NewFunction->setSubprogram(SP);
210 NewFunction->copyAttributesFrom(Src: MergedFunc);
211 // Preserve entry count for the merged function. Branch weights for blocks
212 // are automatically preserved via splice() which moves the basic blocks.
213 if (auto EC = MergedFunc->getEntryCount())
214 NewFunction->setEntryCount(Count: *EC);
215 NewFunction->setDLLStorageClass(GlobalValue::DefaultStorageClass);
216
217 NewFunction->setLinkage(GlobalValue::InternalLinkage);
218 NewFunction->addFnAttr(Kind: Attribute::NoInline);
219
220 // Add the new function before the root function.
221 M->getFunctionList().insert(where: MergedFunc->getIterator(), New: NewFunction);
222
223 // Move the body of MergedFunc into the NewFunction.
224 NewFunction->splice(ToIt: NewFunction->begin(), FromF: MergedFunc);
225
226 // Update the original args by the new args.
227 auto NewArgIter = NewFunction->arg_begin();
228 for (Argument &OrigArg : MergedFunc->args()) {
229 Argument &NewArg = *NewArgIter++;
230 OrigArg.replaceAllUsesWith(V: &NewArg);
231 }
232
233 // Replace the original Constants by the new args.
234 unsigned NumOrigArgs = MergedFunc->arg_size();
235 for (unsigned ParamIdx = 0; ParamIdx < ParamLocsVec.size(); ++ParamIdx) {
236 Argument *NewArg = NewFunction->getArg(i: NumOrigArgs + ParamIdx);
237 for (auto [InstIndex, OpndIndex] : ParamLocsVec[ParamIdx]) {
238 auto *Inst = FI.IndexInstruction->lookup(Key: InstIndex);
239 auto *OrigC = Inst->getOperand(i: OpndIndex);
240 if (OrigC->getType() != NewArg->getType()) {
241 IRBuilder<> Builder(Inst->getParent(), Inst->getIterator());
242 Inst->setOperand(i: OpndIndex,
243 Val: Builder.CreateAggregateCast(V: NewArg, DestTy: OrigC->getType()));
244 } else {
245 Inst->setOperand(i: OpndIndex, Val: NewArg);
246 }
247 }
248 }
249
250 return NewFunction;
251}
252
253// Given the original function (Thunk) and the merged function (ToFunc), create
254// a thunk to the merged function.
255static void createThunk(FuncMergeInfo &FI, ArrayRef<Constant *> Params,
256 Function *ToFunc) {
257 auto *Thunk = FI.F;
258
259 assert(Thunk->arg_size() + Params.size() ==
260 ToFunc->getFunctionType()->getNumParams());
261
262 // Save entry count before dropping references (which clears metadata).
263 auto EC = Thunk->getEntryCount();
264
265 Thunk->dropAllReferences();
266
267 BasicBlock *BB = BasicBlock::Create(Context&: Thunk->getContext(), Name: "", Parent: Thunk);
268 IRBuilder<> Builder(BB);
269
270 SmallVector<Value *> Args;
271 unsigned ParamIdx = 0;
272 FunctionType *ToFuncTy = ToFunc->getFunctionType();
273
274 // Add arguments which are passed through Thunk.
275 for (Argument &AI : Thunk->args()) {
276 Args.push_back(
277 Elt: Builder.CreateAggregateCast(V: &AI, DestTy: ToFuncTy->getParamType(i: ParamIdx)));
278 ++ParamIdx;
279 }
280
281 // Add new arguments defined by Params.
282 for (auto *Param : Params) {
283 assert(ParamIdx < ToFuncTy->getNumParams());
284 Args.push_back(
285 Elt: Builder.CreateAggregateCast(V: Param, DestTy: ToFuncTy->getParamType(i: ParamIdx)));
286 ++ParamIdx;
287 }
288
289 CallInst *CI = Builder.CreateCall(Callee: ToFunc, Args);
290 bool isSwiftTailCall = ToFunc->getCallingConv() == CallingConv::SwiftTail &&
291 Thunk->getCallingConv() == CallingConv::SwiftTail;
292 CI->setTailCallKind(isSwiftTailCall ? llvm::CallInst::TCK_MustTail
293 : llvm::CallInst::TCK_Tail);
294 CI->setCallingConv(ToFunc->getCallingConv());
295 CI->setAttributes(ToFunc->getAttributes());
296 if (Thunk->getReturnType()->isVoidTy())
297 Builder.CreateRetVoid();
298 else
299 Builder.CreateRet(V: Builder.CreateAggregateCast(V: CI, DestTy: Thunk->getReturnType()));
300
301 // Restore the thunk's original entry count.
302 if (EC)
303 Thunk->setEntryCount(Count: *EC);
304}
305
306// Check if the old merged/optimized IndexOperandHashMap is compatible with
307// the current IndexOperandHashMap. An operand hash may not be stable across
308// different builds due to varying modules combined. To address this, we relax
309// the hash check condition by comparing Const hash patterns instead of absolute
310// hash values. For example, let's assume we have three Consts located at idx1,
311// idx3, and idx6, where their corresponding hashes are hash1, hash2, and hash1
312// in the old merged map below:
313// Old (Merged): [(idx1, hash1), (idx3, hash2), (idx6, hash1)]
314// Current: [(idx1, hash1'), (idx3, hash2'), (idx6, hash1')]
315// If the current function also has three Consts in the same locations,
316// with hash sequences hash1', hash2', and hash1' where the first and third
317// are the same as the old hash sequences, we consider them matched.
318static bool checkConstHashCompatible(
319 const DenseMap<IndexPair, stable_hash> &OldInstOpndIndexToConstHash,
320 const DenseMap<IndexPair, stable_hash> &CurrInstOpndIndexToConstHash) {
321
322 DenseMap<stable_hash, stable_hash> OldHashToCurrHash;
323 for (const auto &[Index, OldHash] : OldInstOpndIndexToConstHash) {
324 auto It = CurrInstOpndIndexToConstHash.find(Val: Index);
325 if (It == CurrInstOpndIndexToConstHash.end())
326 return false;
327
328 auto CurrHash = It->second;
329 auto J = OldHashToCurrHash.find(Val: OldHash);
330 if (J == OldHashToCurrHash.end())
331 OldHashToCurrHash.insert(KV: {OldHash, CurrHash});
332 else if (J->second != CurrHash)
333 return false;
334 }
335
336 return true;
337}
338
339// Validate the locations pointed by a param has the same hash and Constant.
340static bool
341checkConstLocationCompatible(const StableFunctionMap::StableFunctionEntry &SF,
342 const IndexInstrMap &IndexInstruction,
343 const ParamLocsVecTy &ParamLocsVec) {
344 for (auto &ParamLocs : ParamLocsVec) {
345 std::optional<stable_hash> OldHash;
346 std::optional<Constant *> OldConst;
347 for (auto &Loc : ParamLocs) {
348 assert(SF.IndexOperandHashMap->count(Loc));
349 auto CurrHash = SF.IndexOperandHashMap->at(Val: Loc);
350 auto [InstIndex, OpndIndex] = Loc;
351 assert(InstIndex < IndexInstruction.size());
352 const auto *Inst = IndexInstruction.lookup(Key: InstIndex);
353 auto *CurrConst = cast<Constant>(Val: Inst->getOperand(i: OpndIndex));
354 if (!OldHash) {
355 OldHash = CurrHash;
356 OldConst = CurrConst;
357 } else if (CurrConst != *OldConst || CurrHash != *OldHash) {
358 return false;
359 }
360 }
361 }
362 return true;
363}
364
365static ParamLocsVecTy
366computeParamInfo(const StableFunctionMap::StableFunctionEntries &SFS) {
367 std::map<std::vector<stable_hash>, ParamLocs> HashSeqToLocs;
368 auto &RSF = *SFS[0];
369 unsigned StableFunctionCount = SFS.size();
370
371 for (auto &[IndexPair, Hash] : *RSF.IndexOperandHashMap) {
372 // Const hash sequence across stable functions.
373 // We will allocate a parameter per unique hash squence.
374 // can't use SmallVector as key
375 std::vector<stable_hash> ConstHashSeq;
376 ConstHashSeq.push_back(x: Hash);
377 bool Identical = true;
378 for (unsigned J = 1; J < StableFunctionCount; ++J) {
379 auto &SF = SFS[J];
380 auto SHash = SF->IndexOperandHashMap->at(Val: IndexPair);
381 if (Hash != SHash)
382 Identical = false;
383 ConstHashSeq.push_back(x: SHash);
384 }
385
386 if (Identical)
387 continue;
388
389 // For each unique Const hash sequence (parameter), add the locations.
390 HashSeqToLocs[ConstHashSeq].push_back(Elt: IndexPair);
391 }
392
393 ParamLocsVecTy ParamLocsVec;
394 for (auto &[HashSeq, Locs] : HashSeqToLocs)
395 ParamLocsVec.push_back(Elt: std::move(Locs));
396
397 llvm::sort(C&: ParamLocsVec, Comp: [&](const ParamLocs &L, const ParamLocs &R) {
398 return L[0] < R[0];
399 });
400
401 return ParamLocsVec;
402}
403
404bool GlobalMergeFunc::merge(Module &M, const StableFunctionMap *FunctionMap) {
405 bool Changed = false;
406
407 // Collect stable functions related to the current module.
408 DenseMap<stable_hash, SmallVector<std::pair<Function *, FunctionHashInfo>>>
409 HashToFuncs;
410 for (auto &F : M) {
411 if (!isEligibleFunction(F: &F))
412 continue;
413 auto FI = llvm::StructuralHashWithDifferences(F, IgnoreOp: ignoreOp);
414 if (FunctionMap->contains(FunctionHash: FI.FunctionHash))
415 HashToFuncs[FI.FunctionHash].emplace_back(Args: &F, Args: std::move(FI));
416 }
417
418 for (auto &[Hash, Funcs] : HashToFuncs) {
419 std::optional<ParamLocsVecTy> ParamLocsVec;
420 SmallVector<FuncMergeInfo> FuncMergeInfos;
421 auto &SFS = FunctionMap->at(FunctionHash: Hash);
422 assert(!SFS.empty());
423 auto &RFS = SFS[0];
424
425 // Iterate functions with the same hash.
426 for (auto &[F, FI] : Funcs) {
427 // Check if the function is compatible with any stable function
428 // in terms of the number of instructions and ignored operands.
429 if (RFS->InstCount != FI.IndexInstruction->size())
430 continue;
431
432 auto hasValidSharedConst = [&](StableFunctionMap::StableFunctionEntry *SF,
433 FunctionHashInfo &FHI) {
434 for (auto &[Index, Hash] : *SF->IndexOperandHashMap) {
435 auto [InstIndex, OpndIndex] = Index;
436 assert(InstIndex < FHI.IndexInstruction->size());
437 auto *Inst = FHI.IndexInstruction->lookup(Key: InstIndex);
438 if (!ignoreOp(I: Inst, OpIdx: OpndIndex))
439 return false;
440 }
441 return true;
442 };
443 if (!hasValidSharedConst(RFS.get(), FI))
444 continue;
445
446 for (auto &SF : SFS) {
447 assert(SF->InstCount == FI.IndexInstruction->size());
448 assert(hasValidSharedConst(SF.get(), FI));
449 // Check if there is any stable function that is compatiable with the
450 // current one.
451 if (!checkConstHashCompatible(OldInstOpndIndexToConstHash: *SF->IndexOperandHashMap,
452 CurrInstOpndIndexToConstHash: *FI.IndexOperandHashMap))
453 continue;
454 if (!ParamLocsVec.has_value()) {
455 ParamLocsVec = computeParamInfo(SFS);
456 LLVM_DEBUG(dbgs() << "[GlobalMergeFunc] Merging hash: " << Hash
457 << " with Params " << ParamLocsVec->size() << "\n");
458 }
459 if (!checkConstLocationCompatible(SF: *SF, IndexInstruction: *FI.IndexInstruction,
460 ParamLocsVec: *ParamLocsVec))
461 continue;
462
463 // If a stable function matching the current one is found,
464 // create a candidate for merging and proceed to the next function.
465 FuncMergeInfos.emplace_back(Args: SF.get(), Args&: F, Args: FI.IndexInstruction.get());
466 break;
467 }
468 }
469 unsigned FuncMergeInfoSize = FuncMergeInfos.size();
470 if (FuncMergeInfoSize == 0)
471 continue;
472
473 LLVM_DEBUG(dbgs() << "[GlobalMergeFunc] Merging function count "
474 << FuncMergeInfoSize << " for hash: " << Hash << "\n");
475
476 for (auto &FMI : FuncMergeInfos) {
477 Changed = true;
478
479 // We've already validated all locations of constant operands pointed by
480 // the parameters. Populate parameters pointing to the original constants.
481 SmallVector<Constant *> Params;
482 SmallVector<Type *> ParamTypes;
483 for (auto &ParamLocs : *ParamLocsVec) {
484 assert(!ParamLocs.empty());
485 auto &[InstIndex, OpndIndex] = ParamLocs[0];
486 auto *Inst = FMI.IndexInstruction->lookup(Key: InstIndex);
487 auto *Opnd = cast<Constant>(Val: Inst->getOperand(i: OpndIndex));
488 Params.push_back(Elt: Opnd);
489 ParamTypes.push_back(Elt: Opnd->getType());
490 }
491
492 // Create a merged function derived from the current function.
493 Function *MergedFunc =
494 createMergedFunction(FI&: FMI, ConstParamTypes: ParamTypes, ParamLocsVec: *ParamLocsVec);
495
496 LLVM_DEBUG({
497 dbgs() << "[GlobalMergeFunc] Merged function (hash:" << FMI.SF->Hash
498 << ") " << MergedFunc->getName() << " generated from "
499 << FMI.F->getName() << ":\n";
500 MergedFunc->dump();
501 });
502
503 // Transform the current function into a thunk that calls the merged
504 // function.
505 createThunk(FI&: FMI, Params, ToFunc: MergedFunc);
506 LLVM_DEBUG({
507 dbgs() << "[GlobalMergeFunc] Thunk generated: \n";
508 FMI.F->dump();
509 });
510 ++NumMergedFunctions;
511 }
512 }
513
514 return Changed;
515}
516
517void GlobalMergeFunc::initializeMergerMode(const Module &M) {
518 // Initialize the local function map regardless of the merger mode.
519 LocalFunctionMap = std::make_unique<StableFunctionMap>();
520
521 // Disable codegen data for merging. The local merge is still enabled.
522 if (DisableCGDataForMerging)
523 return;
524
525 // (Full)LTO module does not have functions added to the index.
526 // In this case, we run a local merger without using codegen data.
527 if (Index && !Index->hasExportedFunctions(M))
528 return;
529
530 if (cgdata::emitCGData())
531 MergerMode = HashFunctionMode::BuildingHashFuncion;
532 else if (cgdata::hasStableFunctionMap())
533 MergerMode = HashFunctionMode::UsingHashFunction;
534}
535
536void GlobalMergeFunc::emitFunctionMap(Module &M) {
537 LLVM_DEBUG(dbgs() << "Emit function map. Size: " << LocalFunctionMap->size()
538 << "\n");
539 // No need to emit the function map if it is empty.
540 if (LocalFunctionMap->empty())
541 return;
542 SmallVector<char> Buf;
543 raw_svector_ostream OS(Buf);
544
545 std::vector<CGDataPatchItem> PatchItems;
546 StableFunctionMapRecord::serialize(OS, FunctionMap: LocalFunctionMap.get(), PatchItems);
547 CGDataOStream COS(OS);
548 COS.patch(P: PatchItems);
549
550 std::unique_ptr<MemoryBuffer> Buffer = MemoryBuffer::getMemBuffer(
551 InputData: OS.str(), BufferName: "in-memory stable function map", RequiresNullTerminator: false);
552
553 Triple TT(M.getTargetTriple());
554 embedBufferInModule(M, Buf: *Buffer,
555 SectionName: getCodeGenDataSectionName(CGSK: CG_merge, OF: TT.getObjectFormat()),
556 Alignment: Align(4));
557}
558
559bool GlobalMergeFunc::run(Module &M) {
560 initializeMergerMode(M);
561
562 const StableFunctionMap *FuncMap;
563 if (MergerMode == HashFunctionMode::UsingHashFunction) {
564 // Use the prior CG data to optimistically create global merge candidates.
565 FuncMap = cgdata::getStableFunctionMap();
566 } else {
567 analyze(M);
568 // Emit the local function map to the custom section, __llvm_merge before
569 // finalizing it.
570 if (MergerMode == HashFunctionMode::BuildingHashFuncion)
571 emitFunctionMap(M);
572 LocalFunctionMap->finalize();
573 FuncMap = LocalFunctionMap.get();
574 }
575
576 return merge(M, FunctionMap: FuncMap);
577}
578
579namespace {
580
581class GlobalMergeFuncPassWrapper : public ModulePass {
582
583public:
584 static char ID;
585
586 GlobalMergeFuncPassWrapper() : ModulePass(ID) {}
587
588 void getAnalysisUsage(AnalysisUsage &AU) const override {
589 AU.addUsedIfAvailable<ImmutableModuleSummaryIndexWrapperPass>();
590 AU.setPreservesAll();
591 ModulePass::getAnalysisUsage(AU);
592 }
593
594 StringRef getPassName() const override { return "Global Merge Functions"; }
595
596 bool runOnModule(Module &M) override;
597};
598
599} // namespace
600
601char GlobalMergeFuncPassWrapper::ID = 0;
602INITIALIZE_PASS(GlobalMergeFuncPassWrapper, "global-merge-func",
603 "Global merge function pass", false, false)
604
605ModulePass *llvm::createGlobalMergeFuncPass() {
606 return new GlobalMergeFuncPassWrapper();
607}
608
609bool GlobalMergeFuncPassWrapper::runOnModule(Module &M) {
610 const ModuleSummaryIndex *Index = nullptr;
611 if (auto *IndexWrapperPass =
612 getAnalysisIfAvailable<ImmutableModuleSummaryIndexWrapperPass>())
613 Index = IndexWrapperPass->getIndex();
614
615 return GlobalMergeFunc(Index).run(M);
616}
617
618PreservedAnalyses GlobalMergeFuncPass::run(Module &M,
619 AnalysisManager<Module> &AM) {
620 bool Changed = GlobalMergeFunc(ImportSummary).run(M);
621 return Changed ? PreservedAnalyses::none() : PreservedAnalyses::all();
622}
623