133#define DEBUG_TYPE "mergefunc"
135STATISTIC(NumFunctionsMerged,
"Number of functions merged");
136STATISTIC(NumThunksWritten,
"Number of thunks generated");
137STATISTIC(NumAliasesWritten,
"Number of aliases generated");
138STATISTIC(NumDoubleWeak,
"Number of new functions created");
142 cl::desc(
"How many functions in a module could be used for "
143 "MergeFunctions to pass a basic correctness check. "
144 "'0' disables this check. Works only with '-debug' key."),
164 cl::desc(
"Preserve debug info in thunk when mergefunc "
165 "transformations are made."));
170 cl::desc(
"Allow mergefunc to create aliases"));
182 Function *getFunc()
const {
return F; }
187 void replaceBy(Function *
G)
const {
196class MergeFunctions {
198 MergeFunctions() : FnTree(FunctionNodeCmp(&GlobalNumbers)) {
201 template <
typename FuncContainer>
bool run(FuncContainer &Functions);
204 SmallPtrSet<GlobalValue *, 4> &getUsed();
209 class FunctionNodeCmp {
210 GlobalNumberState* GlobalNumbers;
213 FunctionNodeCmp(GlobalNumberState* GN) : GlobalNumbers(GN) {}
215 bool operator()(
const FunctionNode &
LHS,
const FunctionNode &
RHS)
const {
217 if (
LHS.getHash() !=
RHS.getHash())
218 return LHS.getHash() <
RHS.getHash();
219 FunctionComparator FCmp(
LHS.getFunc(),
RHS.getFunc(), GlobalNumbers);
220 return FCmp.compare() < 0;
223 using FnTreeType = std::set<FunctionNode, FunctionNodeCmp>;
225 GlobalNumberState GlobalNumbers;
229 std::vector<WeakTrackingVH> Deferred;
232 SmallPtrSet<GlobalValue *, 4> Used;
237 bool doFunctionalCheck(std::vector<WeakTrackingVH> &Worklist);
242 bool insert(Function *NewFunction);
250 void removeUsers(
Value *V);
254 void replaceDirectCallers(Function *Old, Function *New);
259 void mergeTwoFunctions(Function *
F, Function *
G);
265 filterInstsUnrelatedToPDI(BasicBlock *GEntryBlock,
266 std::vector<Instruction *> &PDIUnrelatedWL,
267 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL);
270 void eraseTail(Function *
G);
277 eraseInstsUnrelatedToPDI(std::vector<Instruction *> &PDIUnrelatedWL,
278 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL);
283 void writeThunk(Function *
F, Function *
G);
286 void writeAlias(Function *
F, Function *
G);
293 bool writeThunkOrAliasIfNeeded(Function *
F, Function *
G,
bool MergeProfile);
296 void replaceFunctionInTree(
const FunctionNode &FN, Function *
G);
307 DenseMap<AssertingVH<Function>, FnTreeType::iterator> FNodesInTree;
310 DenseMap<Function *, Function *> DelToNewMap;
328 MF.getUsed().insert_range(UsedV);
335 return MF.runOnFunctions(
F);
339bool MergeFunctions::doFunctionalCheck(std::vector<WeakTrackingVH> &Worklist) {
341 unsigned TripleNumber = 0;
344 dbgs() <<
"MERGEFUNC-VERIFY: Started for first " << Max <<
" functions.\n";
347 for (std::vector<WeakTrackingVH>::iterator
I = Worklist.begin(),
349 I != E && i < Max; ++
I, ++i) {
351 for (std::vector<WeakTrackingVH>::iterator J =
I; J != E && j < Max;
360 dbgs() <<
"MERGEFUNC-VERIFY: Non-symmetric; triple: " << TripleNumber
362 dbgs() << *F1 <<
'\n' << *F2 <<
'\n';
370 for (std::vector<WeakTrackingVH>::iterator K = J; K !=
E && k < Max;
371 ++k, ++K, ++TripleNumber) {
379 bool Transitive =
true;
381 if (Res1 != 0 && Res1 == Res4) {
383 Transitive = Res3 == Res1;
384 }
else if (Res3 != 0 && Res3 == -Res4) {
386 Transitive = Res3 == Res1;
387 }
else if (Res4 != 0 && -Res3 == Res4) {
389 Transitive = Res4 == -Res1;
393 dbgs() <<
"MERGEFUNC-VERIFY: Non-transitive; triple: "
394 << TripleNumber <<
"\n";
395 dbgs() <<
"Res1, Res3, Res4: " << Res1 <<
", " << Res3 <<
", "
397 dbgs() << *F1 <<
'\n' << *F2 <<
'\n' << *F3 <<
'\n';
404 dbgs() <<
"MERGEFUNC-VERIFY: " << (
Valid ?
"Passed." :
"Failed.") <<
"\n";
435 return !
F.isDeclaration() && !
F.hasAvailableExternallyLinkage() &&
436 !
F.hasFnAttribute(Attribute::NoIPA) &&
443template <
typename FuncContainer>
bool MergeFunctions::run(FuncContainer &M) {
448 std::vector<std::pair<stable_hash, Function *>> HashedFuncs;
449 for (
auto &Func : M) {
458 auto S = HashedFuncs.begin();
459 for (
auto I = HashedFuncs.begin(), IE = HashedFuncs.end();
I != IE; ++
I) {
462 if ((
I != S && std::prev(
I)->first ==
I->first) ||
463 (std::next(
I) != IE && std::next(
I)->first ==
I->first)) {
469 std::vector<WeakTrackingVH> Worklist;
470 Deferred.swap(Worklist);
475 LLVM_DEBUG(
dbgs() <<
"size of worklist: " << Worklist.size() <<
'\n');
482 if (!
F->isDeclaration() && !
F->hasAvailableExternallyLinkage() &&
483 !
F->hasFnAttribute(Attribute::NoIPA)) {
487 LLVM_DEBUG(
dbgs() <<
"size of FnTree: " << FnTree.size() <<
'\n');
488 }
while (!Deferred.empty());
491 FNodesInTree.clear();
492 GlobalNumbers.
clear();
500 [[maybe_unused]]
bool MergeResult = this->
run(
F);
501 assert(MergeResult == !DelToNewMap.empty());
502 return this->DelToNewMap;
522void MergeFunctions::eraseInstsUnrelatedToPDI(
523 std::vector<Instruction *> &PDIUnrelatedWL,
524 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL) {
526 dbgs() <<
" Erasing instructions (in reverse order of appearance in "
527 "entry block) unrelated to parameter debug info from entry "
529 while (!PDIUnrelatedWL.empty()) {
534 I->eraseFromParent();
535 PDIUnrelatedWL.pop_back();
538 while (!PDVRUnrelatedWL.empty()) {
544 PDVRUnrelatedWL.pop_back();
547 LLVM_DEBUG(
dbgs() <<
" } // Done erasing instructions unrelated to parameter "
548 "debug info from entry block. \n");
552void MergeFunctions::eraseTail(
Function *
G) {
553 std::vector<BasicBlock *> WorklistBB;
555 BB.dropAllReferences();
556 WorklistBB.push_back(&BB);
558 while (!WorklistBB.empty()) {
561 WorklistBB.pop_back();
574void MergeFunctions::filterInstsUnrelatedToPDI(
575 BasicBlock *GEntryBlock, std::vector<Instruction *> &PDIUnrelatedWL,
576 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL) {
577 std::set<Instruction *> PDIRelated;
578 std::set<DbgVariableRecord *> PDVRRelated;
591 PDVRRelated.insert(DbgVal);
599 auto ExamineDbgDeclare = [&PDIRelated,
614 if (
Value *Arg =
SI->getValueOperand()) {
619 PDIRelated.insert(AI);
623 PDIRelated.insert(
SI);
627 PDVRRelated.insert(DbgDecl);
658 ExamineDbgValue(&DVR);
661 ExamineDbgDeclare(&DVR);
665 if (BI->isTerminator() && &*BI == GEntryBlock->
getTerminator()) {
669 PDIRelated.insert(&*BI);
678 <<
" Report parameter debug info related/related instructions: {\n");
680 auto IsPDIRelated = [](
auto *Rec,
auto &Container,
auto &UnrelatedCont) {
681 if (Container.find(Rec) == Container.end()) {
685 UnrelatedCont.push_back(Rec);
696 IsPDIRelated(&DVR, PDVRRelated, PDVRUnrelatedWL);
697 IsPDIRelated(&
I, PDIRelated, PDIUnrelatedWL);
707 if (
F->hasKernelCallingConv())
712 if (
F->size() == 1) {
713 if (
F->front().size() < 2) {
715 <<
" is too small to bother creating a thunk for\n");
740 std::optional<uint64_t> GEC =
G->getEntryCount();
742 std::vector<Instruction *> PDIUnrelatedWL;
743 std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
747 LLVM_DEBUG(
dbgs() <<
"writeThunk: (MergeFunctionsPDI) Do not create a new "
748 "function as thunk; retain original: "
749 <<
G->getName() <<
"()\n");
750 GEntryBlock = &
G->getEntryBlock();
752 dbgs() <<
"writeThunk: (MergeFunctionsPDI) filter parameter related "
754 <<
G->getName() <<
"() {\n");
755 filterInstsUnrelatedToPDI(GEntryBlock, PDIUnrelatedWL, PDVRUnrelatedWL);
760 G->getAddressSpace(),
"",
G->getParent());
771 Args.push_back(Builder.CreateAggregateCast(&AI, FFTy->getParamType(i)));
775 CallInst *CI = Builder.CreateCall(
F, Args);
783 if (
H->getReturnType()->isVoidTy()) {
784 RI = Builder.CreateRetVoid();
786 RI = Builder.CreateRet(Builder.CreateAggregateCast(CI,
H->getReturnType()));
800 dbgs() <<
"writeThunk: (MergeFunctionsPDI) No DISubprogram for "
801 <<
G->getName() <<
"()\n");
804 eraseInstsUnrelatedToPDI(PDIUnrelatedWL, PDVRUnrelatedWL);
806 dbgs() <<
"} // End of parameter related debug info filtering for: "
807 <<
G->getName() <<
"()\n");
818 G->replaceAllUsesWith(NewG);
819 G->eraseFromParent();
832 assert(
F->hasLocalLinkage() ||
F->hasExternalLinkage()
833 ||
F->hasWeakLinkage() ||
F->hasLinkOnceLinkage());
842 G->getLinkage(),
"",
F,
G->getParent());
846 if (FAlign || GAlign)
849 F->setAlignment(std::nullopt);
851 GA->setVisibility(
G->getVisibility());
855 G->replaceAllUsesWith(GA);
856 G->eraseFromParent();
871 std::optional<uint64_t> FEntryCount =
F.getEntryCount();
872 std::optional<uint64_t> GEntryCount =
G.getEntryCount();
874 if (!FEntryCount && !GEntryCount && AllImports.
empty())
881 if (FEntryCount || GEntryCount)
883 GEntryCount ? *GEntryCount :
uint64_t{0});
884 F.setEntryCount(Sum, AllImports.
empty() ?
nullptr : &AllImports);
898 if (!ShouldErase && !ShouldAlias && !ShouldThunk)
905 G->eraseFromParent();
923 return F->hasWeakODRLinkage() ||
F->hasLinkOnceODRLinkage();
929 std::optional<uint64_t> FEntryCount =
F->getEntryCount();
936 "if G is ODR, F must also be ODR due to ordering");
948 F->getAddressSpace(),
"",
F->getParent());
952 F->setComdat(
nullptr);
958 F->replaceAllUsesWith(NewF);
963 replaceDirectCallers(
G,
F);
965 replaceDirectCallers(NewF,
F);
973 writeThunkOrAliasIfNeeded(
F,
G,
true);
978 writeThunkOrAliasIfNeeded(
F, NewF,
false);
980 if (NewFAlign || GAlign)
983 F->setAlignment(std::nullopt);
986 ++NumFunctionsMerged;
994 if (
G->hasGlobalUnnamedAddr() && !
Used.contains(
G)) {
1000 G->replaceAllUsesWith(
F);
1004 replaceDirectCallers(
G,
F);
1013 G->eraseFromParent();
1014 ++NumFunctionsMerged;
1018 if (writeThunkOrAliasIfNeeded(
F,
G,
true))
1019 ++NumFunctionsMerged;
1024void MergeFunctions::replaceFunctionInTree(
const FunctionNode &FN,
1028 "The two functions must be equal");
1030 auto I = FNodesInTree.find(
F);
1031 assert(
I != FNodesInTree.end() &&
"F should be in FNodesInTree");
1032 assert(FNodesInTree.count(
G) == 0 &&
"FNodesInTree should not contain G");
1034 FnTreeType::iterator IterToFNInFnTree =
I->second;
1035 assert(&(*IterToFNInFnTree) == &FN &&
"F should map to FN in FNodesInTree.");
1037 FNodesInTree.erase(
I);
1038 FNodesInTree.insert({
G, IterToFNInFnTree});
1051 if (
F->isInterposable() !=
G->isInterposable()) {
1054 return !
F->isInterposable();
1057 if (
F->hasLocalLinkage() !=
G->hasLocalLinkage()) {
1060 return !
F->hasLocalLinkage();
1066 return F->getName() <=
G->getName();
1071bool MergeFunctions::insert(
Function *NewFunction) {
1072 std::pair<FnTreeType::iterator, bool>
Result =
1073 FnTree.insert(FunctionNode(NewFunction));
1076 assert(FNodesInTree.count(NewFunction) == 0);
1077 FNodesInTree.insert({NewFunction,
Result.first});
1083 const FunctionNode &OldF = *
Result.first;
1088 replaceFunctionInTree(*
Result.first, NewFunction);
1090 assert(OldF.getFunc() !=
F &&
"Must have swapped the functions.");
1095 Function *OldFunc = OldF.getFunc();
1098 <<
" == " << NewFunction->
getName() <<
'\n');
1101 mergeTwoFunctions(OldFunc, DeleteF);
1102 this->DelToNewMap.insert({DeleteF, OldFunc});
1108void MergeFunctions::remove(
Function *
F) {
1109 auto I = FNodesInTree.find(
F);
1110 if (
I != FNodesInTree.end()) {
1112 FnTree.erase(
I->second);
1115 FNodesInTree.erase(
I);
1116 Deferred.emplace_back(
F);
1122void MergeFunctions::removeUsers(
Value *V) {
1123 for (
User *U :
V->users())
assert(UImm &&(UImm !=~static_cast< T >(0)) &&"Invalid immediate!")
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This file defines the DenseSet and SmallDenseSet classes.
Module.h This file contains the declarations for the Module class.
This defines the Use class.
static void mergeEntryCountsAndImportsInto(Function &F, Function &G)
static bool canCreateAliasFor(Function *F)
static bool isEligibleForMerging(Function &F)
Check whether F is eligible for function merging.
static bool isODR(const Function *F)
Returns true if F is either weak_odr or linkonce_odr.
static cl::opt< unsigned > NumFunctionsForVerificationCheck("mergefunc-verify", cl::desc("How many functions in a module could be used for " "MergeFunctions to pass a basic correctness check. " "'0' disables this check. Works only with '-debug' key."), cl::init(0), cl::Hidden)
static DenseSet< GlobalValue::GUID > unionImportGUIDs(const Function &F, const Function &G)
static bool canCreateThunkFor(Function *F)
Whether this function may be replaced by a forwarding thunk.
static cl::opt< bool > MergeFunctionsPDI("mergefunc-preserve-debug-info", cl::Hidden, cl::init(false), cl::desc("Preserve debug info in thunk when mergefunc " "transformations are made."))
static bool hasDistinctMetadataIntrinsic(const Function &F)
Check whether F has an intrinsic which references distinct metadata as an operand.
Function * asPtr(Function *Fn)
static void copyMetadataIfPresent(Function *From, Function *To, StringRef Kind)
Copy all metadata of a specific kind from one function to another.
static cl::opt< bool > MergeFunctionsAliases("mergefunc-use-aliases", cl::Hidden, cl::init(false), cl::desc("Allow mergefunc to create aliases"))
static bool isFuncOrderCorrect(const Function *F, const Function *G)
This file defines the SmallVector class.
This file defines the 'Statistic' class, which is designed to be an easy way to expose various metric...
#define STATISTIC(VARNAME, DESC)
an instruction to allocate memory on the stack
This class represents an incoming formal argument to a Function.
Represent a constant reference to an array (0 or more elements consecutively in memory),...
Value handle that asserts if the Value is deleted.
LLVM Basic Block Representation.
iterator begin()
Instruction iterator methods.
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
LLVM_ABI SymbolTableList< BasicBlock >::iterator eraseFromParent()
Unlink 'this' from the containing function and delete it.
InstListType::iterator iterator
Instruction iterators...
const Instruction * getTerminator() const LLVM_READONLY
Returns the terminator instruction; assumes that the block is well-formed.
Base class for all callable instructions (InvokeInst and CallInst) Holds everything related to callin...
void setCallingConv(CallingConv::ID CC)
bool isCallee(Value::const_user_iterator UI) const
Determine whether the passed iterator points to the callee operand's Use.
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)
LLVM_ABI DISubprogram * getSubprogram() const
Get the subprogram for this scope.
Subprogram description. Uses SubclassData1.
LLVM_ABI void eraseFromParent()
Record of a variable value-assignment, aka a non instruction representation of the dbg....
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
bool isDbgDeclare() const
Implements a dense probed hash-table based set.
FunctionComparator - Compares two functions to determine whether or not they will generate machine co...
LLVM_ABI int compare()
Test whether the two functions have equivalent behaviour.
Class to represent function types.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
MaybeAlign getAlign() const
Returns the alignment of the given function.
void setEntryCount(uint64_t Count, const DenseSet< GlobalValue::GUID > *Imports=nullptr)
Set the entry count for this function.
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
static LLVM_ABI GlobalAlias * create(Type *Ty, unsigned AddressSpace, LinkageTypes Linkage, const Twine &Name, Constant *Aliasee, Module *Parent)
If a parent module is specified, the alias is automatically inserted into the end of the specified mo...
void erase(GlobalValue *Global)
LLVM_ABI void setComdat(Comdat *C)
LLVM_ABI void addMetadata(unsigned KindID, MDNode &MD)
Add a metadata attachment.
MDNode * getMetadata(unsigned KindID) const
Get the metadata of given kind attached to this GlobalObject.
@ PrivateLinkage
Like Internal, but omit from symbol table.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
LLVM_ABI InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
LLVM_ABI const Function * getFunction() const
Return the function this instruction belongs to.
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
static MDTuple * get(LLVMContext &Context, ArrayRef< Metadata * > MDs)
LLVMContext & getContext() const
static LLVM_ABI DenseMap< Function *, Function * > runOnFunctions(ArrayRef< Function * > F)
static LLVM_ABI bool runOnModule(Module &M)
LLVM_ABI PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A Module instance is used to store all the information related to an LLVM module.
Class to represent pointers.
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.
Return a value (possibly void), from a function.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements.
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small.
An instruction for storing to memory.
Represent a constant reference to a string, i.e.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
LLVM_ABI void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
LLVM_ABI StringRef getName() const
Return a constant reference to the value's name.
LLVM_ABI void takeName(Value *V)
Transfer the name from V to this value.
Value handle that is nullable, but tries to track the Value.
std::pair< iterator, bool > insert(const ValueT &V)
#define llvm_unreachable(msg)
Marks that the current location is not supposed to be reachable.
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
@ SwiftTail
This follows the Swift calling convention in how arguments are passed but guarantees tail calls will ...
int compare(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale)
Compare two scaled numbers.
@ Valid
The data is already valid.
initializer< Ty > init(const Ty &Val)
DXILDebugInfoMap run(Module &M)
LLVM_ABI std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
This is an optimization pass for GlobalISel generic memory operations.
auto drop_begin(T &&RangeOrContainer, size_t N=1)
Return a range covering RangeOrContainer with the first N elements excluded.
void stable_sort(R &&Range)
decltype(auto) dyn_cast(const From &Val)
dyn_cast<X> - Return the argument parameter cast to the specified type.
iterator_range< early_inc_iterator_impl< detail::IterOfRange< RangeT > > > make_early_inc_range(RangeT &&Range)
Make a range that does early increment to allow mutation of the underlying range without disrupting i...
uint64_t stable_hash
An opaque object representing a stable hash code.
RelativeUniformCounterPtr ValuesPtrExpr VTableAddr Value
auto dyn_cast_or_null(const Y &Val)
LLVM_ABI raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
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...
DWARFExpression::Operation Op
ArrayRef(const T &OneElt) -> ArrayRef< T >
decltype(auto) cast(const From &Val)
cast<X> - Return the argument parameter cast to the specified type.
std::enable_if_t< std::is_unsigned_v< T >, T > SaturatingAdd(T X, T Y, bool *ResultOverflowed=nullptr)
Add two unsigned integers, X and Y, of type T.
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
LLVM_ABI stable_hash StructuralHash(const Function &F, bool DetailedHash=false)
Returns a hash of the function F.
AnalysisManager< Module > ModuleAnalysisManager
Convenience typedef for the Module analysis manager.
LLVM_ABI GlobalVariable * collectUsedGlobalVariables(const Module &M, SmallVectorImpl< GlobalValue * > &Vec, bool CompilerUsed)
Given "llvm.used" or "llvm.compiler.used" as a global name, collect the initializer elements of that ...
This struct is a compact representation of a valid (power of two) or undefined (0) alignment.
Align valueOrOne() const
For convenience, returns a valid alignment or 1 if undefined.
Function object to check whether the first component of a container supported by std::get (like std::...