25#define DEBUG_TYPE "global-merge-func"
32 cl::desc(
"Disable codegen data for function merging. Local "
33 "merging is still enabled within a module."),
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");
55 if (Callee->isIntrinsic())
57 auto Name = Callee->getName();
59 if (Name.starts_with(
"objc_msgSend$"))
62 if (Name.starts_with(
"__dtrace"))
82 if (
F->isDeclaration())
85 if (
F->hasFnAttribute(llvm::Attribute::NoMerge) ||
86 F->hasFnAttribute(llvm::Attribute::AlwaysInline))
89 if (
F->hasAvailableExternallyLinkage())
92 if (
F->getFunctionType()->isVarArg())
109 if (CB && CB->isMustTailCall())
118 switch (
I->getOpcode()) {
119 case Instruction::Load:
120 case Instruction::Store:
121 case Instruction::Call:
122 case Instruction::Invoke:
134 if (OpIdx >=
I->getNumOperands())
160 ++NumAnalyzedFunctions;
162 ++NumEligibleFunctions;
169 for (
auto &Pair : *FI.IndexOperandHashMap)
173 M.getModuleIdentifier(), FI.IndexInstruction->size(),
174 std::move(IndexOperandHashes));
176 LocalFunctionMap->insert(SF);
199 auto *MergedFunc = FI.
F;
200 std::string NewFunctionName =
202 auto *M = MergedFunc->getParent();
203 assert(!M->getFunction(NewFunctionName));
209 ParamTypes.
append(ConstParamTypes.
begin(), ConstParamTypes.
end());
216 if (
auto *SP = MergedFunc->getSubprogram())
221 if (
auto EC = MergedFunc->getEntryCount())
226 NewFunction->
addFnAttr(Attribute::NoInline);
229 M->getFunctionList().insert(MergedFunc->getIterator(), NewFunction);
232 NewFunction->
splice(NewFunction->
begin(), MergedFunc);
235 auto NewArgIter = NewFunction->
arg_begin();
236 for (
Argument &OrigArg : MergedFunc->args()) {
242 unsigned NumOrigArgs = MergedFunc->arg_size();
243 for (
unsigned ParamIdx = 0; ParamIdx < ParamLocsVec.
size(); ++ParamIdx) {
245 for (
auto [InstIndex, OpndIndex] : ParamLocsVec[ParamIdx]) {
248 if (OrigC->getType() != NewArg->
getType()) {
250 Inst->setOperand(OpndIndex,
251 Builder.CreateAggregateCast(NewArg, OrigC->
getType()));
253 Inst->setOperand(OpndIndex, NewArg);
271 auto EC = Thunk->getEntryCount();
273 Thunk->dropAllReferences();
279 unsigned ParamIdx = 0;
283 for (
Argument &AI : Thunk->args()) {
285 Builder.CreateAggregateCast(&AI, ToFuncTy->getParamType(ParamIdx)));
290 for (
auto *Param : Params) {
291 assert(ParamIdx < ToFuncTy->getNumParams());
293 Builder.CreateAggregateCast(Param, ToFuncTy->getParamType(ParamIdx)));
297 CallInst *CI = Builder.CreateCall(ToFunc, Args);
304 if (Thunk->getReturnType()->isVoidTy())
305 Builder.CreateRetVoid();
307 Builder.CreateRet(Builder.CreateAggregateCast(CI, Thunk->getReturnType()));
311 Thunk->setEntryCount(*EC);
331 for (
const auto &[Index, OldHash] : OldInstOpndIndexToConstHash) {
332 auto It = CurrInstOpndIndexToConstHash.
find(Index);
333 if (It == CurrInstOpndIndexToConstHash.
end())
336 auto CurrHash = It->second;
337 auto J = OldHashToCurrHash.
find(OldHash);
338 if (J == OldHashToCurrHash.
end())
339 OldHashToCurrHash.
insert({OldHash, CurrHash});
340 else if (J->second != CurrHash)
353 std::optional<stable_hash> OldHash;
354 std::optional<Constant *> OldConst;
358 auto [InstIndex, OpndIndex] =
Loc;
360 const auto *Inst = IndexInstruction.
lookup(InstIndex);
364 OldConst = CurrConst;
365 }
else if (CurrConst != *OldConst || CurrHash != *OldHash) {
375 std::map<std::vector<stable_hash>,
ParamLocs> HashSeqToLocs;
377 unsigned StableFunctionCount = SFS.
size();
379 for (
auto &[
IndexPair, Hash] : *RSF.IndexOperandHashMap) {
383 std::vector<stable_hash> ConstHashSeq;
384 ConstHashSeq.push_back(Hash);
385 bool Identical =
true;
386 for (
unsigned J = 1; J < StableFunctionCount; ++J) {
388 auto SHash = SF->IndexOperandHashMap->at(
IndexPair);
391 ConstHashSeq.push_back(SHash);
398 HashSeqToLocs[ConstHashSeq].push_back(
IndexPair);
402 for (
auto &[HashSeq, Locs] : HashSeqToLocs)
422 if (FunctionMap->
contains(FI.FunctionHash))
423 HashToFuncs[FI.FunctionHash].emplace_back(&
F, std::move(FI));
426 for (
auto &[Hash, Funcs] : HashToFuncs) {
427 std::optional<ParamLocsVecTy> ParamLocsVec;
429 auto &SFS = FunctionMap->
at(Hash);
434 for (
auto &[
F, FI] : Funcs) {
437 if (RFS->InstCount != FI.IndexInstruction->size())
443 auto [InstIndex, OpndIndex] = Index;
444 assert(InstIndex < FHI.IndexInstruction->
size());
445 auto *Inst = FHI.IndexInstruction->lookup(InstIndex);
451 if (!hasValidSharedConst(RFS.get(), FI))
454 for (
auto &SF : SFS) {
456 assert(hasValidSharedConst(SF.get(), FI));
460 *FI.IndexOperandHashMap))
462 if (!ParamLocsVec.has_value()) {
465 <<
" with Params " << ParamLocsVec->size() <<
"\n");
473 FuncMergeInfos.
emplace_back(SF.get(),
F, FI.IndexInstruction.get());
477 unsigned FuncMergeInfoSize = FuncMergeInfos.
size();
478 if (FuncMergeInfoSize == 0)
482 << FuncMergeInfoSize <<
" for hash: " << Hash <<
"\n");
484 for (
auto &FMI : FuncMergeInfos) {
493 auto &[InstIndex, OpndIndex] =
ParamLocs[0];
494 auto *Inst = FMI.IndexInstruction->lookup(InstIndex);
505 dbgs() <<
"[GlobalMergeFunc] Merged function (hash:" << FMI.SF->Hash
506 <<
") " << MergedFunc->
getName() <<
" generated from "
507 << FMI.F->getName() <<
":\n";
515 dbgs() <<
"[GlobalMergeFunc] Thunk generated: \n";
518 ++NumMergedFunctions;
527 LocalFunctionMap = std::make_unique<StableFunctionMap>();
535 if (Index && !Index->hasExportedFunctions(M))
545 LLVM_DEBUG(
dbgs() <<
"Emit function map. Size: " << LocalFunctionMap->size()
548 if (LocalFunctionMap->empty())
553 std::vector<CGDataPatchItem> PatchItems;
556 COS.
patch(PatchItems);
559 OS.
str(),
"in-memory stable function map",
false);
561 Triple TT(M.getTargetTriple());
580 LocalFunctionMap->finalize();
581 FuncMap = LocalFunctionMap.get();
584 return merge(M, FuncMap);
589class GlobalMergeFuncPassWrapper :
public ModulePass {
594 GlobalMergeFuncPassWrapper() :
ModulePass(ID) {}
602 StringRef getPassName()
const override {
return "Global Merge Functions"; }
604 bool runOnModule(
Module &M)
override;
609char GlobalMergeFuncPassWrapper::ID = 0;
611 "Global merge function pass",
false,
false)
614 return new GlobalMergeFuncPassWrapper();
617bool GlobalMergeFuncPassWrapper::runOnModule(
Module &M) {
619 if (
auto *IndexWrapperPass =
620 getAnalysisIfAvailable<ImmutableModuleSummaryIndexWrapperPass>())
621 Index = IndexWrapperPass->getIndex();
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static FunctionHashInfo hashFunction(const Function &F)
static bool checkConstHashCompatible(const DenseMap< IndexPair, stable_hash > &OldInstOpndIndexToConstHash, const DenseMap< IndexPair, stable_hash > &CurrInstOpndIndexToConstHash)
static ParamLocsVecTy computeParamInfo(const StableFunctionMap::StableFunctionEntries &SFS)
static cl::opt< bool > DisableCGDataForMerging("disable-cgdata-for-merging", cl::Hidden, cl::desc("Disable codegen data for function merging. Local " "merging is still enabled within a module."), cl::init(false))
static bool canParameterizeCallOperand(const CallBase *CI, unsigned OpIdx)
static Function * createMergedFunction(FuncMergeInfo &FI, ArrayRef< Type * > ConstParamTypes, const ParamLocsVecTy &ParamLocsVec)
static void createThunk(FuncMergeInfo &FI, ArrayRef< Constant * > Params, Function *ToFunc)
static bool isEligibleInstructionForConstantSharing(const Instruction *I)
static bool ignoreOp(const Instruction *I, unsigned OpIdx)
bool isEligibleFunction(Function *F)
Returns true if function F is eligible for merging.
static bool checkConstLocationCompatible(const StableFunctionMap::StableFunctionEntry &SF, const IndexInstrMap &IndexInstruction, const ParamLocsVecTy &ParamLocsVec)
static bool isCalleeOperand(const CallBase *CI, unsigned OpIdx)
Returns true if the \OpIdx operand of CI is the callee operand.
Machine Check Debug Module
This is the interface to build a ModuleSummaryIndex for a module.
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
A container for analyses that lazily runs them and caches their results.
Represent the analysis usage information of a pass.
AnalysisUsage & addUsedIfAvailable()
Add the specified Pass class to the set of analyses used by this pass.
void setPreservesAll()
Set by analyses that do not transform their input at all.
This class represents an incoming formal argument to a Function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
size_t size() const
Get the array size.
LLVM Basic Block Representation.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
A wrapper class to abstract writer stream with support of bytes back patching.
LLVM_ABI void patch(ArrayRef< CGDataPatchItem > P)
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
bool isInlineAsm() const
Check if this call is an inline asm statement.
void setCallingConv(CallingConv::ID CC)
bool isOperandBundleOfType(uint32_t ID, unsigned Idx) const
Return true if the operand at index Idx is a bundle operand that has tag ID ID.
std::optional< OperandBundleUse > getOperandBundle(StringRef Name) const
Return an operand bundle by name, if present.
Value * getCalledOperand() const
const Use & getCalledOperandUse() const
void setAttributes(AttributeList A)
Set the attributes for this call.
This class represents a function call, abstracting a target machine's calling convention.
void setTailCallKind(TailCallKind TCK)
iterator find(const_arg_type_t< KeyT > Val)
std::pair< iterator, bool > insert(const std::pair< KeyT, ValueT > &KV)
unsigned getNumParams() const
Return the number of fixed parameters this function type requires.
static LLVM_ABI FunctionType * get(Type *Result, ArrayRef< Type * > Params, bool isVarArg)
This static method is the primary way of constructing a FunctionType.
void addFnAttr(Attribute::AttrKind Kind)
Add function attributes to this function.
void setSubprogram(DISubprogram *SP)
Set the attached subprogram.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
void splice(Function::iterator ToIt, Function *FromF)
Transfer all blocks from FromF to this function at ToIt.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
AttributeList getAttributes() const
Return the attribute list for this Function.
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
Argument * getArg(unsigned i) const
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
GlobalMergeFunc is a ModulePass that implements a function merging mechanism using stable function ha...
LLVM_ABI void analyze(Module &M)
Analyze module to create stable function into LocalFunctionMap.
LLVM_ABI void initializeMergerMode(const Module &M)
LLVM_ABI bool merge(Module &M, const StableFunctionMap *FunctionMap)
Merge functions in the module using the given function map.
LLVM_ABI void emitFunctionMap(Module &M)
Emit LocalFunctionMap into __llvm_merge section.
LLVM_ABI bool run(Module &M)
static constexpr char MergingInstanceSuffix[]
The suffix used to identify the merged function that parameterizes the constant values.
void setDLLStorageClass(DLLStorageClassTypes C)
void setLinkage(LinkageTypes LT)
@ InternalLinkage
Rename collisions when linking (static functions).
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Legacy wrapper pass to provide the ModuleSummaryIndex object.
@ OB_clang_arc_attachedcall
ValueT lookup(const KeyT &Key) const
static std::unique_ptr< MemoryBuffer > getMemBuffer(StringRef InputData, StringRef BufferName="", bool RequiresNullTerminator=true)
Open the specified memory range as a MemoryBuffer.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
Class to hold module path string table and global value map, and encapsulate methods for operating on...
A Module instance is used to store all the information related to an LLVM module.
virtual void getAnalysisUsage(AnalysisUsage &) const
getAnalysisUsage - This function should be overriden by passes that need analysis information to do t...
A set of analyses that are preserved following a run of a transformation pass.
static PreservedAnalyses none()
Convenience factory function for the empty preserved set.
static PreservedAnalyses all()
Construct a special preserved set that preserves all passes.
reference emplace_back(ArgTypes &&... Args)
void append(ItTy in_start, ItTy in_end)
Add the specified range to the end of the SmallVector.
void push_back(const T &Elt)
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
std::string str() const
Get the contents as an std::string.
Triple - Helper class for working with autoconf configuration names.
const Use & getOperandUse(unsigned i) const
Value * getOperand(unsigned i) const
Type * getType() const
All values are typed, get the type of this value.
LLVM_ABI void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
LLVM_ABI const Value * stripPointerCasts() const
Strip off pointer casts, all-zero GEPs and address space casts.
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void dump() const
Support for debugging, callable in GDB: V->dump()
A raw_ostream that writes to an SmallVector or SmallString.
StringRef str() const
Return a StringRef for the vector contents.
@ SwiftTail
This follows the Swift calling convention in how arguments are passed but guarantees tail calls will ...
bool hasStableFunctionMap()
const StableFunctionMap * getStableFunctionMap()
initializer< Ty > init(const Ty &Val)
This is an optimization pass for GlobalISel generic memory operations.
auto size(R &&Range, std::enable_if_t< std::is_base_of< std::random_access_iterator_tag, typename std::iterator_traits< decltype(Range.begin())>::iterator_category >::value, void > *=nullptr)
Get the size of a range.
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
MapVector< unsigned, Instruction * > IndexInstrMap
A map from an instruction index to an instruction pointer.
LLVM_ABI ModulePass * createGlobalMergeFuncPass()
This pass performs merging similar functions globally.
SmallVector< IndexPairHash > IndexOperandHashVecType
auto dyn_cast_or_null(const Y &Val)
void sort(IteratorTy Start, IteratorTy End)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
StringRef get_stable_name(StringRef Name)
bool isa(const From &Val)
isa<X> - Return true if the parameter to the template is an instance of one of the template type argu...
SmallVector< IndexPair, 4 > ParamLocs
std::pair< unsigned, unsigned > IndexPair
The pair of an instruction index and a operand index.
LLVM_ABI FunctionHashInfo StructuralHashWithDifferences(const Function &F, IgnoreOperandFunc IgnoreOp, bool SourceQualifyLocalGlobals=false)
Computes a structural hash of a given function, considering the structure and content of the function...
SmallVector< ParamLocs, 8 > ParamLocsVecTy
OutputIt move(R &&Range, OutputIt Out)
Provide wrappers to std::move which take ranges instead of having to pass begin/end explicitly.
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
LLVM_ABI GlobalVariable * embedBufferInModule(Module &M, MemoryBufferRef Buf, StringRef SectionName, Align Alignment=Align(1), bool SectionExclude=true)
Embed the memory buffer Buf into the module M as a global using the specified section name.
LLVM_ABI std::string getCodeGenDataSectionName(CGDataSectKind CGSK, Triple::ObjectFormatType OF, bool AddSegmentInfo=true)
Implement std::hash so that hash_code can be used in STL containers.
Tuple to hold function info to process merging.
FuncMergeInfo(StableFunctionMap::StableFunctionEntry *SF, Function *F, IndexInstrMap *IndexInstruction)
StableFunctionMap::StableFunctionEntry * SF
IndexInstrMap * IndexInstruction
This struct is a compact representation of a valid (non-zero power of two) alignment.
LLVM_ABI PreservedAnalyses run(Module &M, AnalysisManager< Module > &)
const ModuleSummaryIndex * ImportSummary
static LLVM_ABI void serialize(raw_ostream &OS, const StableFunctionMap *FunctionMap, std::vector< CGDataPatchItem > &PatchItems)
A static helper function to serialize the stable function map without owning the stable function map.
An efficient form of StableFunction for fast look-up.
std::unique_ptr< IndexOperandHashMapType > IndexOperandHashMap
A map from an IndexPair to a stable_hash which was skipped.
unsigned InstCount
The number of instructions.
SmallVector< std::unique_ptr< StableFunctionEntry > > StableFunctionEntries
LLVM_ABI const StableFunctionEntries & at(HashFuncsMapType::key_type FunctionHash) const
bool contains(HashFuncsMapType::key_type FunctionHash) const
A stable function is a function with a stable hash while tracking the locations of ignored operands a...