133 using namespace llvm;
135 #define DEBUG_TYPE "mergefunc" 137 STATISTIC(NumFunctionsMerged,
"Number of functions merged");
138 STATISTIC(NumThunksWritten,
"Number of thunks generated");
139 STATISTIC(NumAliasesWritten,
"Number of aliases generated");
140 STATISTIC(NumDoubleWeak,
"Number of new functions created");
144 cl::desc(
"How many functions in module could be used for " 145 "MergeFunctions pass sanity check. " 146 "'0' disables this check. Works only with '-debug' key."),
166 cl::desc(
"Preserve debug info in thunk when mergefunc " 167 "transformations are made."));
172 cl::desc(
"Allow mergefunc to create aliases"));
194 void release() { F =
nullptr; }
206 :
ModulePass(ID), FnTree(FunctionNodeCmp(&GlobalNumbers)) {
210 bool runOnModule(
Module &M)
override;
215 class FunctionNodeCmp {
221 bool operator()(
const FunctionNode &LHS,
const FunctionNode &RHS)
const {
223 if (LHS.getHash() != RHS.getHash())
224 return LHS.getHash() < RHS.getHash();
229 using FnTreeType = std::set<FunctionNode, FunctionNodeCmp>;
235 std::vector<WeakTrackingVH> Deferred;
240 bool doSanityCheck(std::vector<WeakTrackingVH> &Worklist);
253 void removeUsers(
Value *V);
266 void filterInstsUnrelatedToPDI(
BasicBlock *GEntryBlock,
267 std::vector<Instruction *> &PDIUnrelatedWL);
274 void eraseInstsUnrelatedToPDI(std::vector<Instruction *> &PDIUnrelatedWL);
289 void replaceFunctionInTree(
const FunctionNode &FN,
Function *
G);
307 INITIALIZE_PASS(MergeFunctions,
"mergefunc",
"Merge Functions",
false,
false)
310 return new MergeFunctions();
314 bool MergeFunctions::doSanityCheck(std::vector<WeakTrackingVH> &Worklist) {
316 unsigned TripleNumber = 0;
319 dbgs() <<
"MERGEFUNC-SANITY: Started for first " << Max <<
" functions.\n";
322 for (std::vector<WeakTrackingVH>::iterator
I = Worklist.begin(),
324 I !=
E && i < Max; ++
I, ++i) {
326 for (std::vector<WeakTrackingVH>::iterator J =
I; J !=
E && j < Max;
335 dbgs() <<
"MERGEFUNC-SANITY: Non-symmetric; triple: " << TripleNumber
337 dbgs() << *F1 <<
'\n' << *F2 <<
'\n';
345 for (std::vector<WeakTrackingVH>::iterator K = J; K !=
E && k < Max;
346 ++k, ++K, ++TripleNumber) {
354 bool Transitive =
true;
356 if (Res1 != 0 && Res1 == Res4) {
358 Transitive = Res3 == Res1;
359 }
else if (Res3 != 0 && Res3 == -Res4) {
361 Transitive = Res3 == Res1;
362 }
else if (Res4 != 0 && -Res3 == Res4) {
364 Transitive = Res4 == -Res1;
368 dbgs() <<
"MERGEFUNC-SANITY: Non-transitive; triple: " 369 << TripleNumber <<
"\n";
370 dbgs() <<
"Res1, Res3, Res4: " << Res1 <<
", " << Res3 <<
", " 372 dbgs() << *F1 <<
'\n' << *F2 <<
'\n' << *F3 <<
'\n';
379 dbgs() <<
"MERGEFUNC-SANITY: " << (Valid ?
"Passed." :
"Failed.") <<
"\n";
386 bool MergeFunctions::runOnModule(
Module &M) {
390 bool Changed =
false;
394 std::vector<std::pair<FunctionComparator::FunctionHash, Function *>>
397 if (!Func.isDeclaration() && !Func.hasAvailableExternallyLinkage()) {
403 HashedFuncs.begin(), HashedFuncs.end(),
404 [](
const std::pair<FunctionComparator::FunctionHash, Function *> &a,
405 const std::pair<FunctionComparator::FunctionHash, Function *> &b) {
406 return a.first < b.first;
409 auto S = HashedFuncs.begin();
410 for (
auto I = HashedFuncs.begin(),
IE = HashedFuncs.end();
I !=
IE; ++
I) {
413 if ((
I != S && std::prev(
I)->
first ==
I->first) ||
414 (std::next(
I) !=
IE && std::next(
I)->first ==
I->first) ) {
420 std::vector<WeakTrackingVH> Worklist;
421 Deferred.swap(Worklist);
426 LLVM_DEBUG(
dbgs() <<
"size of worklist: " << Worklist.size() <<
'\n');
434 Changed |= insert(F);
437 LLVM_DEBUG(
dbgs() <<
"size of FnTree: " << FnTree.size() <<
'\n');
438 }
while (!Deferred.empty());
441 FNodesInTree.clear();
442 GlobalNumbers.
clear();
454 if (CS && CS.isCallee(U)) {
469 for (
unsigned argIdx = 0; argIdx < CS.arg_size(); argIdx++)
470 NewArgAttrs.
push_back(NewPAL.getParamAttributes(argIdx));
474 NewPAL.getRetAttributes(),
477 remove(CS.getInstruction()->getFunction());
513 void MergeFunctions::eraseInstsUnrelatedToPDI(
514 std::vector<Instruction *> &PDIUnrelatedWL) {
516 dbgs() <<
" Erasing instructions (in reverse order of appearance in " 517 "entry block) unrelated to parameter debug info from entry " 519 while (!PDIUnrelatedWL.empty()) {
527 LLVM_DEBUG(
dbgs() <<
" } // Done erasing instructions unrelated to parameter " 528 "debug info from entry block. \n");
532 void MergeFunctions::eraseTail(
Function *
G) {
533 std::vector<BasicBlock *> WorklistBB;
536 BBI->dropAllReferences();
537 WorklistBB.push_back(&*BBI);
539 while (!WorklistBB.empty()) {
555 void MergeFunctions::filterInstsUnrelatedToPDI(
556 BasicBlock *GEntryBlock, std::vector<Instruction *> &PDIUnrelatedWL) {
557 std::set<Instruction *> PDIRelated;
560 if (
auto *DVI = dyn_cast<DbgValueInst>(&*BI)) {
569 PDIRelated.insert(&*BI);
575 }
else if (
auto *DDI = dyn_cast<DbgDeclareInst>(&*BI)) {
583 AllocaInst *AI = dyn_cast_or_null<AllocaInst>(DDI->getAddress());
590 if (dyn_cast<Argument>(
Arg)) {
594 PDIRelated.insert(AI);
598 PDIRelated.insert(
SI);
602 PDIRelated.insert(&*BI);
625 }
else if (BI->isTerminator() && &*BI == GEntryBlock->
getTerminator()) {
629 PDIRelated.insert(&*BI);
638 <<
" Report parameter debug info related/related instructions: {\n");
643 if (PDIRelated.find(I) == PDIRelated.end()) {
647 PDIUnrelatedWL.push_back(I);
660 if (F->
size() == 1) {
663 <<
" is too small to bother creating a thunk for\n");
680 std::vector<Instruction *> PDIUnrelatedWL;
684 LLVM_DEBUG(
dbgs() <<
"writeThunk: (MergeFunctionsPDI) Do not create a new " 685 "function as thunk; retain original: " 689 dbgs() <<
"writeThunk: (MergeFunctionsPDI) filter parameter related " 692 filterInstsUnrelatedToPDI(GEntryBlock, PDIUnrelatedWL);
693 GEntryBlock->getTerminator()->eraseFromParent();
711 CallInst *CI = Builder.CreateCall(F, Args);
717 RI = Builder.CreateRetVoid();
731 dbgs() <<
"writeThunk: (MergeFunctionsPDI) No DISubprogram for " 735 eraseInstsUnrelatedToPDI(PDIUnrelatedWL);
737 dbgs() <<
"} // End of parameter related debug info filtering for: " 767 PtrType->getElementType(), PtrType->getAddressSpace(),
819 writeThunkOrAlias(F, G);
820 writeThunkOrAlias(F, NewF);
825 ++NumFunctionsMerged;
833 GlobalNumbers.
erase(G);
841 replaceDirectCallers(G, F);
850 ++NumFunctionsMerged;
854 if (writeThunkOrAlias(F, G)) {
855 ++NumFunctionsMerged;
861 void MergeFunctions::replaceFunctionInTree(
const FunctionNode &FN,
865 "The two functions must be equal");
867 auto I = FNodesInTree.find(F);
868 assert(
I != FNodesInTree.end() &&
"F should be in FNodesInTree");
869 assert(FNodesInTree.count(G) == 0 &&
"FNodesInTree should not contain G");
871 FnTreeType::iterator IterToFNInFnTree =
I->second;
872 assert(&(*IterToFNInFnTree) == &FN &&
"F should map to FN in FNodesInTree.");
874 FNodesInTree.erase(
I);
875 FNodesInTree.insert({
G, IterToFNInFnTree});
900 bool MergeFunctions::insert(
Function *NewFunction) {
901 std::pair<FnTreeType::iterator, bool> Result =
902 FnTree.insert(FunctionNode(NewFunction));
905 assert(FNodesInTree.count(NewFunction) == 0);
906 FNodesInTree.insert({NewFunction, Result.first});
912 const FunctionNode &OldF = *Result.first;
917 replaceFunctionInTree(*Result.first, NewFunction);
919 assert(OldF.getFunc() != F &&
"Must have swapped the functions.");
923 <<
" == " << NewFunction->
getName() <<
'\n');
926 mergeTwoFunctions(OldF.getFunc(), DeleteF);
933 auto I = FNodesInTree.find(F);
934 if (
I != FNodesInTree.end()) {
936 FnTree.erase(
I->second);
939 FNodesInTree.erase(
I);
940 Deferred.emplace_back(F);
946 void MergeFunctions::removeUsers(
Value *V) {
947 std::vector<Value *> Worklist;
948 Worklist.push_back(V);
951 while (!Worklist.empty()) {
952 Value *V = Worklist.back();
957 remove(
I->getFunction());
958 }
else if (isa<GlobalValue>(U)) {
960 }
else if (
Constant *
C = dyn_cast<Constant>(U)) {
962 if (!Visited.
insert(UU).second)
963 Worklist.push_back(UU);
Return a value (possibly void), from a function.
SymbolTableList< Instruction >::iterator eraseFromParent()
This method unlinks 'this' from the containing basic block and deletes it.
unsigned getAlignment() const
bool hasLocalLinkage() const
DILocation * get() const
Get the underlying DILocation.
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
GCNRegPressure max(const GCNRegPressure &P1, const GCNRegPressure &P2)
This class represents an incoming formal argument to a Function.
static Value * createCast(IRBuilder<> &Builder, Value *V, Type *DestTy)
This class represents lattice values for constants.
Type * getParamType(unsigned i) const
Parameter type accessors.
A Module instance is used to store all the information related to an LLVM module. ...
std::error_code remove(const Twine &path, bool IgnoreNonExisting=true)
Remove path.
ModulePass * createMergeFunctionsPass()
createMergeFunctionsPass - This pass discovers identical functions and collapses them.
void push_back(const T &Elt)
static bool isFuncOrderCorrect(const Function *F, const Function *G)
This class represents a function call, abstracting a target machine's calling convention.
bool hasAvailableExternallyLinkage() const
Like Internal, but omit from symbol table.
bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time...
STATISTIC(NumFunctions, "Total number of functions")
Type * getStructElementType(unsigned N) const
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...
This defines the Use class.
void setAlignment(unsigned Align)
iterator begin()
Instruction iterator methods.
uint64_t FunctionHash
Hash a function.
ArrayRef< T > makeArrayRef(const T &OneElt)
Construct an ArrayRef from a single element.
A Use represents the edge between a Value definition and its users.
bool isIntegerTy() const
True if this is an instance of IntegerType.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
This file contains the simple types necessary to represent the attributes associated with functions a...
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
bool hasExternalLinkage() const
Class to represent function types.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Type * getType() const
All values are typed, get the type of this value.
Value handle that is nullable, but tries to track the Value.
AttributeList getAttributes() const
Return the attribute list for this Function.
An instruction for storing to memory.
LinkageTypes getLinkage() const
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
bool hasLinkOnceLinkage() const
void takeName(Value *V)
Transfer the name from V to this value.
void initializeMergeFunctionsPass(PassRegistry &)
static bool canCreateAliasFor(Function *F)
void erase(GlobalValue *Global)
Class to represent pointers.
static cl::opt< unsigned > NumFunctionsForSanityCheck("mergefunc-sanity", cl::desc("How many functions in module could be used for " "MergeFunctions pass sanity check. " "'0' disables this check. Works only with '-debug' key."), cl::init(0), cl::Hidden)
static FunctionHash functionHash(Function &)
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
bool isVoidTy() const
Return true if this is 'void'.
const BasicBlock & getEntryBlock() const
initializer< Ty > init(const Ty &Val)
Type * getReturnType() const
Returns the type of the ret val.
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, unsigned AddrSpace, const Twine &N="", Module *M=nullptr)
FunctionComparator - Compares two functions to determine whether or not they will generate machine co...
void setDebugLoc(DebugLoc Loc)
Set the debug location information for this instruction.
VisibilityTypes getVisibility() const
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
DISubprogram * getSubprogram() const
Get the attached subprogram.
static GCRegistry::Add< CoreCLRGC > E("coreclr", "CoreCLR-compatible GC")
This is an important base class in LLVM.
void copyAttributesFrom(const Function *Src)
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
bool isPointerTy() const
True if this is an instance of PointerType.
std::pair< iterator, bool > insert(PtrType Ptr)
Inserts Ptr if and only if there is no element in the container equal to Ptr.
const Instruction & back() const
unsigned getAddressSpace() const
void print(raw_ostream &O, bool IsForDebug=false) const
Implement operator<< on Value.
void setCallingConv(CallingConv::ID CC)
static bool isDiscardableIfUnused(LinkageTypes Linkage)
Whether the definition of this global may be discarded if it is not used in its compilation unit...
unsigned getStructNumElements() const
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
static bool isThunkProfitable(Function *F)
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
void setTailCall(bool isTC=true)
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
bool hasWeakLinkage() const
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."))
Iterator for intrusive lists based on ilist_node.
SmallPtrSet - This class implements a set which is optimized for holding SmallSize or less elements...
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
GlobalNumberState assigns an integer to each global value in the program, which is used by the compar...
This is a 'vector' (really, a variable-sized array), optimized for the case when the array is small...
Module.h This file contains the declarations for the Module class.
bool hasGlobalUnnamedAddr() const
Value handle that asserts if the Value is deleted.
void setLinkage(LinkageTypes LT)
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
FunctionType * getFunctionType() const
Returns the FunctionType for me.
int compare()
Test whether the two functions have equivalent behaviour.
iterator_range< user_iterator > users()
static cl::opt< bool > MergeFunctionsAliases("mergefunc-use-aliases", cl::Hidden, cl::init(false), cl::desc("Allow mergefunc to create aliases"))
amdgpu Simplify well known AMD library false Value Value * Arg
StringRef getName() const
Return a constant reference to the value's name.
SymbolTableList< BasicBlock >::iterator eraseFromParent()
Unlink 'this' from the containing function and delete it.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
void setAttributes(AttributeList A)
Set the parameter attributes for this call.
void eraseFromParent()
eraseFromParent - This method unlinks 'this' from the containing module and deletes it...
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
int compare(DigitsT LDigits, int16_t LScale, DigitsT RDigits, int16_t RScale)
Compare two scaled numbers.
assert(ImpDefSCC.getReg()==AMDGPU::SCC &&ImpDefSCC.isDef())
const BasicBlock & front() const
Module * getParent()
Get the module that this global value is contained inside of...
LLVM Value Representation.
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
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...
constexpr char Args[]
Key for Kernel::Metadata::mArgs.
PointerType * getType() const
Global values are always pointers.
static AttributeList get(LLVMContext &C, ArrayRef< std::pair< unsigned, Attribute >> Attrs)
Create an AttributeList with the specified parameters in it.
iterator_range< arg_iterator > args()
bool isStructTy() const
True if this is an instance of StructType.
an instruction to allocate memory on the stack