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