131#define DEBUG_TYPE "mergefunc"
133STATISTIC(NumFunctionsMerged,
"Number of functions merged");
134STATISTIC(NumThunksWritten,
"Number of thunks generated");
135STATISTIC(NumAliasesWritten,
"Number of aliases generated");
136STATISTIC(NumDoubleWeak,
"Number of new functions created");
140 cl::desc(
"How many functions in a module could be used for "
141 "MergeFunctions to pass a basic correctness check. "
142 "'0' disables this check. Works only with '-debug' key."),
162 cl::desc(
"Preserve debug info in thunk when mergefunc "
163 "transformations are made."));
168 cl::desc(
"Allow mergefunc to create aliases"));
194class MergeFunctions {
196 MergeFunctions() : FnTree(FunctionNodeCmp(&GlobalNumbers)) {
199 template <
typename FuncContainer>
bool run(FuncContainer &Functions);
207 class FunctionNodeCmp {
213 bool operator()(
const FunctionNode &LHS,
const FunctionNode &RHS)
const {
215 if (
LHS.getHash() !=
RHS.getHash())
216 return LHS.getHash() <
RHS.getHash();
218 return FCmp.compare() < 0;
221 using FnTreeType = std::set<FunctionNode, FunctionNodeCmp>;
227 std::vector<WeakTrackingVH> Deferred;
235 bool doFunctionalCheck(std::vector<WeakTrackingVH> &Worklist);
248 void removeUsers(
Value *V);
263 filterInstsUnrelatedToPDI(
BasicBlock *GEntryBlock,
264 std::vector<Instruction *> &PDIUnrelatedWL,
265 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL);
275 eraseInstsUnrelatedToPDI(std::vector<Instruction *> &PDIUnrelatedWL,
276 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL);
291 void replaceFunctionInTree(
const FunctionNode &FN,
Function *
G);
323 MF.getUsed().insert(UsedV.
begin(), UsedV.
end());
330 return MF.runOnFunctions(
F);
334bool MergeFunctions::doFunctionalCheck(std::vector<WeakTrackingVH> &Worklist) {
336 unsigned TripleNumber = 0;
339 dbgs() <<
"MERGEFUNC-VERIFY: Started for first " << Max <<
" functions.\n";
342 for (std::vector<WeakTrackingVH>::iterator
I = Worklist.begin(),
344 I != E && i < Max; ++
I, ++i) {
346 for (std::vector<WeakTrackingVH>::iterator J =
I; J != E && j < Max;
355 dbgs() <<
"MERGEFUNC-VERIFY: Non-symmetric; triple: " << TripleNumber
357 dbgs() << *F1 <<
'\n' << *F2 <<
'\n';
365 for (std::vector<WeakTrackingVH>::iterator K = J; K != E && k < Max;
366 ++k, ++K, ++TripleNumber) {
374 bool Transitive =
true;
376 if (Res1 != 0 && Res1 == Res4) {
378 Transitive = Res3 == Res1;
379 }
else if (Res3 != 0 && Res3 == -Res4) {
381 Transitive = Res3 == Res1;
382 }
else if (Res4 != 0 && -Res3 == Res4) {
384 Transitive = Res4 == -Res1;
388 dbgs() <<
"MERGEFUNC-VERIFY: Non-transitive; triple: "
389 << TripleNumber <<
"\n";
390 dbgs() <<
"Res1, Res3, Res4: " << Res1 <<
", " << Res3 <<
", "
392 dbgs() << *F1 <<
'\n' << *F2 <<
'\n' << *F3 <<
'\n';
399 dbgs() <<
"MERGEFUNC-VERIFY: " << (Valid ?
"Passed." :
"Failed.") <<
"\n";
411 for (
const Instruction &
I : BB.instructionsWithoutDebug()) {
412 if (!isa<IntrinsicInst>(&
I))
416 auto *MDL = dyn_cast<MetadataAsValue>(
Op);
419 if (
MDNode *
N = dyn_cast<MDNode>(MDL->getMetadata()))
430 return !
F.isDeclaration() && !
F.hasAvailableExternallyLinkage() &&
437template <
typename FuncContainer>
bool MergeFunctions::run(FuncContainer &M) {
438 bool Changed =
false;
442 std::vector<std::pair<stable_hash, Function *>> HashedFuncs;
443 for (
auto &Func : M) {
452 auto S = HashedFuncs.begin();
453 for (
auto I = HashedFuncs.begin(), IE = HashedFuncs.end();
I != IE; ++
I) {
456 if ((
I != S && std::prev(
I)->first ==
I->first) ||
457 (std::next(
I) != IE && std::next(
I)->first ==
I->first)) {
463 std::vector<WeakTrackingVH> Worklist;
464 Deferred.swap(Worklist);
469 LLVM_DEBUG(
dbgs() <<
"size of worklist: " << Worklist.size() <<
'\n');
476 if (!
F->isDeclaration() && !
F->hasAvailableExternallyLinkage()) {
477 Changed |= insert(
F);
480 LLVM_DEBUG(
dbgs() <<
"size of FnTree: " << FnTree.size() <<
'\n');
481 }
while (!Deferred.empty());
484 FNodesInTree.clear();
485 GlobalNumbers.
clear();
493 [[maybe_unused]]
bool MergeResult = this->
run(
F);
494 assert(MergeResult == !DelToNewMap.empty());
495 return this->DelToNewMap;
501 CallBase *CB = dyn_cast<CallBase>(
U.getUser());
517 Type *SrcTy = V->getType();
542void MergeFunctions::eraseInstsUnrelatedToPDI(
543 std::vector<Instruction *> &PDIUnrelatedWL,
544 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL) {
546 dbgs() <<
" Erasing instructions (in reverse order of appearance in "
547 "entry block) unrelated to parameter debug info from entry "
549 while (!PDIUnrelatedWL.empty()) {
554 I->eraseFromParent();
555 PDIUnrelatedWL.pop_back();
558 while (!PDVRUnrelatedWL.empty()) {
564 PDVRUnrelatedWL.pop_back();
567 LLVM_DEBUG(
dbgs() <<
" } // Done erasing instructions unrelated to parameter "
568 "debug info from entry block. \n");
572void MergeFunctions::eraseTail(
Function *
G) {
573 std::vector<BasicBlock *> WorklistBB;
575 BB.dropAllReferences();
576 WorklistBB.push_back(&BB);
578 while (!WorklistBB.empty()) {
594void MergeFunctions::filterInstsUnrelatedToPDI(
595 BasicBlock *GEntryBlock, std::vector<Instruction *> &PDIUnrelatedWL,
596 std::vector<DbgVariableRecord *> &PDVRUnrelatedWL) {
597 std::set<Instruction *> PDIRelated;
598 std::set<DbgVariableRecord *> PDVRRelated;
602 auto ExamineDbgValue = [](
auto *DbgVal,
auto &Container) {
611 Container.insert(DbgVal);
619 auto ExamineDbgDeclare = [&PDIRelated](
auto *DbgDecl,
auto &Container) {
627 AllocaInst *AI = dyn_cast_or_null<AllocaInst>(DbgDecl->getAddress());
632 if (
StoreInst *SI = dyn_cast<StoreInst>(U)) {
633 if (
Value *Arg =
SI->getValueOperand()) {
634 if (isa<Argument>(Arg)) {
638 PDIRelated.insert(AI);
642 PDIRelated.insert(SI);
646 Container.insert(DbgDecl);
677 ExamineDbgValue(&DVR, PDVRRelated);
680 ExamineDbgDeclare(&DVR, PDVRRelated);
684 if (
auto *DVI = dyn_cast<DbgValueInst>(&*BI)) {
685 ExamineDbgValue(DVI, PDIRelated);
686 }
else if (
auto *DDI = dyn_cast<DbgDeclareInst>(&*BI)) {
687 ExamineDbgDeclare(DDI, PDIRelated);
688 }
else if (BI->isTerminator() && &*BI == GEntryBlock->
getTerminator()) {
692 PDIRelated.insert(&*BI);
701 <<
" Report parameter debug info related/related instructions: {\n");
703 auto IsPDIRelated = [](
auto *Rec,
auto &Container,
auto &UnrelatedCont) {
704 if (Container.find(Rec) == Container.end()) {
708 UnrelatedCont.push_back(Rec);
719 IsPDIRelated(&DVR, PDVRRelated, PDVRUnrelatedWL);
720 IsPDIRelated(&
I, PDIRelated, PDIUnrelatedWL);
732 if (
F->size() == 1) {
733 if (
F->front().sizeWithoutDebug() < 2) {
735 <<
" is too small to bother creating a thunk for\n");
746 From->getMetadata(Kind, MDs);
761 std::vector<Instruction *> PDIUnrelatedWL;
762 std::vector<DbgVariableRecord *> PDVRUnrelatedWL;
766 LLVM_DEBUG(
dbgs() <<
"writeThunk: (MergeFunctionsPDI) Do not create a new "
767 "function as thunk; retain original: "
768 <<
G->getName() <<
"()\n");
769 GEntryBlock = &
G->getEntryBlock();
771 dbgs() <<
"writeThunk: (MergeFunctionsPDI) filter parameter related "
773 <<
G->getName() <<
"() {\n");
774 filterInstsUnrelatedToPDI(GEntryBlock, PDIUnrelatedWL, PDVRUnrelatedWL);
779 G->getAddressSpace(),
"",
G->getParent());
795 CallInst *CI = Builder.CreateCall(
F, Args);
803 if (
H->getReturnType()->isVoidTy()) {
804 RI = Builder.CreateRetVoid();
806 RI = Builder.CreateRet(
createCast(Builder, CI,
H->getReturnType()));
820 dbgs() <<
"writeThunk: (MergeFunctionsPDI) No DISubprogram for "
821 <<
G->getName() <<
"()\n");
824 eraseInstsUnrelatedToPDI(PDIUnrelatedWL, PDVRUnrelatedWL);
826 dbgs() <<
"} // End of parameter related debug info filtering for: "
827 <<
G->getName() <<
"()\n");
835 G->replaceAllUsesWith(NewG);
836 G->eraseFromParent();
849 assert(
F->hasLocalLinkage() ||
F->hasExternalLinkage()
850 ||
F->hasWeakLinkage() ||
F->hasLinkOnceLinkage());
858 G->getLinkage(),
"",
F,
G->getParent());
862 if (FAlign || GAlign)
865 F->setAlignment(std::nullopt);
867 GA->setVisibility(
G->getVisibility());
871 G->replaceAllUsesWith(GA);
872 G->eraseFromParent();
894 if (
F->isInterposable()) {
906 F->getAddressSpace(),
"",
F->getParent());
914 F->replaceAllUsesWith(NewF);
921 writeThunkOrAlias(
F,
G);
922 writeThunkOrAlias(
F, NewF);
924 if (NewFAlign || GAlign)
927 F->setAlignment(std::nullopt);
930 ++NumFunctionsMerged;
938 if (
G->hasGlobalUnnamedAddr() && !
Used.contains(
G)) {
944 G->replaceAllUsesWith(
F);
948 replaceDirectCallers(
G,
F);
956 G->eraseFromParent();
957 ++NumFunctionsMerged;
961 if (writeThunkOrAlias(
F,
G)) {
962 ++NumFunctionsMerged;
968void MergeFunctions::replaceFunctionInTree(
const FunctionNode &FN,
972 "The two functions must be equal");
974 auto I = FNodesInTree.find(
F);
975 assert(
I != FNodesInTree.end() &&
"F should be in FNodesInTree");
976 assert(FNodesInTree.count(
G) == 0 &&
"FNodesInTree should not contain G");
978 FnTreeType::iterator IterToFNInFnTree =
I->second;
979 assert(&(*IterToFNInFnTree) == &FN &&
"F should map to FN in FNodesInTree.");
981 FNodesInTree.erase(
I);
982 FNodesInTree.insert({
G, IterToFNInFnTree});
989 if (
F->isInterposable() !=
G->isInterposable()) {
992 return !
F->isInterposable();
994 if (
F->hasLocalLinkage() !=
G->hasLocalLinkage()) {
997 return !
F->hasLocalLinkage();
1002 return F->getName() <=
G->getName();
1007bool MergeFunctions::insert(
Function *NewFunction) {
1008 std::pair<FnTreeType::iterator, bool>
Result =
1009 FnTree.insert(FunctionNode(NewFunction));
1012 assert(FNodesInTree.count(NewFunction) == 0);
1013 FNodesInTree.insert({NewFunction,
Result.first});
1019 const FunctionNode &OldF = *
Result.first;
1024 replaceFunctionInTree(*
Result.first, NewFunction);
1026 assert(OldF.getFunc() !=
F &&
"Must have swapped the functions.");
1030 <<
" == " << NewFunction->
getName() <<
'\n');
1033 mergeTwoFunctions(OldF.getFunc(), DeleteF);
1034 this->DelToNewMap.insert({DeleteF, OldF.getFunc()});
1040void MergeFunctions::remove(
Function *
F) {
1041 auto I = FNodesInTree.find(
F);
1042 if (
I != FNodesInTree.end()) {
1044 FnTree.erase(
I->second);
1047 FNodesInTree.erase(
I);
1048 Deferred.emplace_back(
F);
1054void MergeFunctions::removeUsers(
Value *V) {
1055 for (
User *U :
V->users())
1056 if (
auto *
I = dyn_cast<Instruction>(U))
BlockVerifier::State From
This file contains the declarations for the subclasses of Constant, which represent the different fla...
static Value * createCast(IRBuilder<> &Builder, Value *V, Type *DestTy)
Module.h This file contains the declarations for the Module class.
This defines the Use class.
static bool canCreateAliasFor(Function *F)
static bool isEligibleForMerging(Function &F)
Check whether F is eligible for function merging.
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 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)
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
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
A container for analyses that lazily runs them and caches their results.
This class represents an incoming formal argument to a Function.
ArrayRef - 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.
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 if the block is well formed or null if the block is not well forme...
const Instruction & back() const
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)
This class represents an Operation in the Expression.
Record of a variable value-assignment, aka a non instruction representation of the dbg....
void print(raw_ostream &O, bool IsForDebug=false) const
bool isDbgDeclare() const
FunctionComparator - Compares two functions to determine whether or not they will generate machine co...
int compare()
Test whether the two functions have equivalent behaviour.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
bool IsNewDbgInfoFormat
Is this function using intrinsics to record the position of debugging information,...
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
static 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...
GlobalNumberState assigns an integer to each global value in the program, which is used by the compar...
void erase(GlobalValue *Global)
MaybeAlign getAlign() const
Returns the alignment of the given variable or function.
void setComdat(Comdat *C)
void addMetadata(unsigned KindID, MDNode &MD)
Add a metadata attachment.
@ PrivateLinkage
Like Internal, but omit from symbol table.
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
InstListType::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
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 DenseMap< Function *, Function * > runOnFunctions(ArrayRef< Function * > F)
static bool runOnModule(Module &M)
PreservedAnalyses run(Module &M, ModuleAnalysisManager &AM)
A Module instance is used to store all the information related to an LLVM module.
static PoisonValue * get(Type *T)
Static factory methods - Return an 'poison' object of the specified type.
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.
StringRef - Represent a constant reference to a string, i.e.
The instances of the Type class are immutable: once they are created, they are never changed.
Type * getStructElementType(unsigned N) const
bool isPointerTy() const
True if this is an instance of PointerType.
unsigned getStructNumElements() const
bool isStructTy() const
True if this is an instance of StructType.
bool isIntegerTy() const
True if this is an instance of IntegerType.
A Use represents the edge between a Value definition and its users.
LLVM Value Representation.
void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
iterator_range< user_iterator > users()
iterator_range< use_iterator > uses()
StringRef getName() const
Return a constant reference to the value's name.
void takeName(Value *V)
Transfer the name from V to this value.
Value handle that is nullable, but tries to track the Value.
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.
initializer< Ty > init(const Ty &Val)
PointerTypeMap run(const Module &M)
Compute the PointerTypeMap for the module M.
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)
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...
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
static auto filterDbgVars(iterator_range< simple_ilist< DbgRecord >::iterator > R)
Filter the DbgRecord range to DbgVariableRecord types only and downcast.
stable_hash StructuralHash(const Function &F, bool DetailedHash=false)
Returns a hash of the function F.
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::...