114 using namespace llvm;
116 #define DEBUG_TYPE "mergefunc"
118 STATISTIC(NumFunctionsMerged,
"Number of functions merged");
119 STATISTIC(NumThunksWritten,
"Number of thunks generated");
120 STATISTIC(NumAliasesWritten,
"Number of aliases generated");
121 STATISTIC(NumDoubleWeak,
"Number of new functions created");
125 cl::desc(
"How many functions in module could be used for "
126 "MergeFunctions pass sanity check. "
127 "'0' disables this check. Works only with '-debug' key."),
160 :
ModulePass(
ID), FnTree(FunctionNodeCmp(&GlobalNumbers)), FNodesInTree(),
161 HasGlobalAliases(
false) {
165 bool runOnModule(
Module &M)
override;
170 class FunctionNodeCmp {
174 bool operator()(
const FunctionNode &LHS,
const FunctionNode &RHS)
const {
176 if (LHS.getHash() != RHS.getHash())
177 return LHS.getHash() < RHS.getHash();
182 typedef std::set<FunctionNode, FunctionNodeCmp> FnTreeType;
188 std::vector<WeakVH> Deferred;
192 bool doSanityCheck(std::vector<WeakVH> &Worklist);
204 void removeUsers(
Value *V);
226 void replaceFunctionInTree(
const FunctionNode &FN,
Function *
G);
239 bool HasGlobalAliases;
245 INITIALIZE_PASS(MergeFunctions,
"mergefunc",
"Merge Functions",
false,
false)
248 return new MergeFunctions();
251 bool MergeFunctions::doSanityCheck(std::vector<WeakVH> &Worklist) {
253 unsigned TripleNumber = 0;
256 dbgs() <<
"MERGEFUNC-SANITY: Started for first " << Max <<
" functions.\n";
259 for (std::vector<WeakVH>::iterator
I = Worklist.begin(),
E = Worklist.end();
260 I !=
E && i < Max; ++
I, ++
i) {
262 for (std::vector<WeakVH>::iterator J =
I; J !=
E && j < Max; ++J, ++j) {
270 dbgs() <<
"MERGEFUNC-SANITY: Non-symmetric; triple: " << TripleNumber
281 for (std::vector<WeakVH>::iterator K = J; K !=
E && k < Max;
282 ++k, ++K, ++TripleNumber) {
290 bool Transitive =
true;
292 if (Res1 != 0 && Res1 == Res4) {
294 Transitive = Res3 == Res1;
295 }
else if (Res3 != 0 && Res3 == -Res4) {
297 Transitive = Res3 == Res1;
298 }
else if (Res4 != 0 && -Res3 == Res4) {
300 Transitive = Res4 == -Res1;
304 dbgs() <<
"MERGEFUNC-SANITY: Non-transitive; triple: "
305 << TripleNumber <<
"\n";
306 dbgs() <<
"Res1, Res3, Res4: " << Res1 <<
", " << Res3 <<
", "
317 dbgs() <<
"MERGEFUNC-SANITY: " << (Valid ?
"Passed." :
"Failed.") <<
"\n";
323 bool MergeFunctions::runOnModule(
Module &M) {
327 bool Changed =
false;
331 std::vector<std::pair<FunctionComparator::FunctionHash, Function *>>
334 if (!
Func.isDeclaration() && !
Func.hasAvailableExternallyLinkage()) {
340 HashedFuncs.begin(), HashedFuncs.end(),
341 [](
const std::pair<FunctionComparator::FunctionHash, Function *> &a,
342 const std::pair<FunctionComparator::FunctionHash, Function *> &b) {
343 return a.first < b.first;
346 auto S = HashedFuncs.begin();
347 for (
auto I = HashedFuncs.begin(),
IE = HashedFuncs.end(); I !=
IE; ++
I) {
350 if ((I != S && std::prev(I)->first == I->first) ||
351 (std::next(I) !=
IE && std::next(I)->first == I->first) ) {
352 Deferred.push_back(
WeakVH(I->second));
357 std::vector<WeakVH> Worklist;
358 Deferred.swap(Worklist);
360 DEBUG(doSanityCheck(Worklist));
362 DEBUG(
dbgs() <<
"size of module: " << M.size() <<
'\n');
363 DEBUG(
dbgs() <<
"size of worklist: " << Worklist.size() <<
'\n');
366 for (
WeakVH &I : Worklist) {
371 Changed |= insert(F);
374 DEBUG(
dbgs() <<
"size of FnTree: " << FnTree.size() <<
'\n');
375 }
while (!Deferred.empty());
378 GlobalNumbers.clear();
390 if (CS &&
CS.isCallee(U)) {
404 auto CallSiteAttrs =
CS.getAttributes();
406 CallSiteAttrs = CallSiteAttrs.addAttributes(
409 for (
unsigned argIdx = 0; argIdx <
CS.arg_size(); argIdx++) {
415 CS.setAttributes(CallSiteAttrs);
417 remove(
CS.getInstruction()->getParent()->getParent());
469 replaceDirectCallers(G, F);
492 CallInst *CI = Builder.CreateCall(F, Args);
497 Builder.CreateRetVoid();
522 DEBUG(
dbgs() <<
"writeAlias: " << GA->getName() <<
'\n');
539 unsigned MaxAlignment = std::max(G->
getAlignment(), H->getAlignment());
541 if (HasGlobalAliases) {
553 writeThunkOrAlias(F, G);
556 ++NumFunctionsMerged;
560 void MergeFunctions::replaceFunctionInTree(
const FunctionNode &FN,
564 "The two functions must be equal");
566 auto I = FNodesInTree.find(F);
567 assert(I != FNodesInTree.end() &&
"F should be in FNodesInTree");
568 assert(FNodesInTree.count(G) == 0 &&
"FNodesInTree should not contain G");
570 FnTreeType::iterator IterToFNInFnTree = I->second;
571 assert(&(*IterToFNInFnTree) == &FN &&
"F should map to FN in FNodesInTree.");
573 FNodesInTree.erase(I);
574 FNodesInTree.insert({
G, IterToFNInFnTree});
581 bool MergeFunctions::insert(
Function *NewFunction) {
582 std::pair<FnTreeType::iterator, bool> Result =
583 FnTree.insert(FunctionNode(NewFunction));
586 assert(FNodesInTree.count(NewFunction) == 0);
587 FNodesInTree.insert({NewFunction, Result.first});
592 const FunctionNode &OldF = *Result.first;
598 if (NewFunction->
size() == 1) {
601 <<
" is to small to bother merging\n");
611 if ((OldF.getFunc()->isInterposable() && !NewFunction->
isInterposable()) ||
612 (OldF.getFunc()->isInterposable() == NewFunction->
isInterposable() &&
613 OldF.getFunc()->getName() > NewFunction->
getName())) {
616 replaceFunctionInTree(*Result.first, NewFunction);
618 assert(OldF.getFunc() != F &&
"Must have swapped the functions.");
621 DEBUG(
dbgs() <<
" " << OldF.getFunc()->getName()
622 <<
" == " << NewFunction->
getName() <<
'\n');
625 mergeTwoFunctions(OldF.getFunc(), DeleteF);
632 auto I = FNodesInTree.find(F);
633 if (I != FNodesInTree.end()) {
635 FnTree.erase(I->second);
638 FNodesInTree.erase(I);
639 Deferred.emplace_back(F);
645 void MergeFunctions::removeUsers(
Value *V) {
646 std::vector<Value *> Worklist;
647 Worklist.push_back(V);
650 while (!Worklist.empty()) {
651 Value *V = Worklist.back();
656 remove(I->getParent()->getParent());
657 }
else if (isa<GlobalValue>(U)) {
659 }
else if (
Constant *
C = dyn_cast<Constant>(U)) {
660 for (
User *UU :
C->users()) {
661 if (!Visited.
insert(UU).second)
662 Worklist.push_back(UU);
void push_back(const T &Elt)
LinkageTypes getLinkage() const
static PassRegistry * getPassRegistry()
getPassRegistry - Access the global registry object, which is automatically initialized at applicatio...
LLVMContext & getContext() const
getContext - Return a reference to the LLVMContext associated with this function. ...
VisibilityTypes getVisibility() const
LLVM Argument representation.
static Value * createCast(IRBuilder<> &Builder, Value *V, Type *DestTy)
STATISTIC(NumFunctions,"Total number of functions")
AttributeSet getParamAttributes(unsigned Index) const
The attributes for the specified index are returned.
unsigned getStructNumElements() const
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.
This class represents a function call, abstracting a target machine's calling convention.
Like Internal, but omit from symbol table.
bool hasAvailableExternallyLinkage() const
Type * getReturnType() const
Returns the type of the ret val.
void setAlignment(unsigned Align)
CallingConv::ID getCallingConv() const
getCallingConv()/setCallingConv(CC) - These method get and set the calling convention of this functio...
StringRef getName() const
Return a constant reference to the value's name.
void setCallingConv(CallingConv::ID CC)
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.
This provides a uniform API for creating instructions and inserting them into a basic block: either a...
Value * CreateIntToPtr(Value *V, Type *DestTy, const Twine &Name="")
Class to represent function types.
Value * CreateBitCast(Value *V, Type *DestTy, const Twine &Name="")
Type * getStructElementType(unsigned N) const
Value handle that is nullable, but tries to track the Value.
unsigned getAlignment() const
Function Alias Analysis false
void replaceAllUsesWith(Value *V)
Change all uses of this to point to a new Value.
void takeName(Value *V)
Transfer the name from V to this value.
void initializeMergeFunctionsPass(PassRegistry &)
void setAttributes(AttributeSet Attrs)
Set the parameter attributes for this call.
static GCRegistry::Add< CoreCLRGC > E("coreclr","CoreCLR-compatible GC")
static FunctionHash functionHash(Function &)
static Constant * getBitCast(Constant *C, Type *Ty, bool OnlyIfReduced=false)
unsigned getNumSlots() const
Return the number of slots used in this attribute list.
Type * getParamType(unsigned i) const
Parameter type accessors.
initializer< Ty > init(const Ty &Val)
FunctionComparator - Compares two functions to determine whether or not they will generate machine co...
LLVM Basic Block Representation.
The instances of the Type class are immutable: once they are created, they are never changed...
This is an important base class in LLVM.
SmallSet - This maintains a set of unique values, optimizing for the case when the set is small (less...
This file contains the declarations for the subclasses of Constant, which represent the different fla...
void copyAttributesFrom(const GlobalValue *Src) override
copyAttributesFrom - copy all additional attributes (those not needed to create a Function) from the ...
static BasicBlock * Create(LLVMContext &Context, const Twine &Name="", Function *Parent=nullptr, BasicBlock *InsertBefore=nullptr)
Creates a new BasicBlock.
std::pair< NoneType, bool > insert(const T &V)
insert - Insert an element into the set if it isn't already there.
void setTailCall(bool isTC=true)
bool isPointerTy() const
True if this is an instance of PointerType.
static UndefValue * get(Type *T)
Static factory methods - Return an 'undef' object of the specified type.
bool hasWeakLinkage() const
Value * CreateExtractValue(Value *Agg, ArrayRef< unsigned > Idxs, const Twine &Name="")
uint64_t FunctionHash
Hash a function.
void dump() const
Support for debugging, callable in GDB: V->dump()
#define INITIALIZE_PASS(passName, arg, name, cfg, analysis)
bool hasExternalLinkage() const
bool hasGlobalUnnamedAddr() const
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.
Type * getType() const
All values are typed, get the type of this value.
Value handle that asserts if the Value is deleted.
void setLinkage(LinkageTypes LT)
static GCRegistry::Add< ShadowStackGC > C("shadow-stack","Very portable GC for uncooperative code generators")
raw_ostream & dbgs()
dbgs() - This returns a reference to a raw_ostream for debugging messages.
AttributeSet getAttributes() const
Return the attribute list for this Function.
bool isIntegerTy() const
True if this is an instance of IntegerType.
int compare()
Test whether the two functions have equivalent behaviour.
iterator_range< user_iterator > users()
void eraseFromParent() override
eraseFromParent - This method unlinks 'this' from the containing module and deletes it...
bool isStructTy() const
True if this is an instance of StructType.
PointerType * getType() const
Global values are always pointers.
bool isDeclaration() const
Return true if the primary definition of this global value is outside of the current translation unit...
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)
FunctionType * getFunctionType() const
Returns the FunctionType for me.
ModulePass class - This class is used to implement unstructured interprocedural optimizations and ana...
bool isInterposable() const
Return true if this global's definition can be substituted with an arbitrary definition at link time...
Value * CreatePtrToInt(Value *V, Type *DestTy, const Twine &Name="")
bool hasLocalLinkage() const
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.
std::string Hash(const Unit &U)
static Function * Create(FunctionType *Ty, LinkageTypes Linkage, const Twine &N="", Module *M=nullptr)
Value * CreateInsertValue(Value *Agg, Value *Val, ArrayRef< unsigned > Idxs, const Twine &Name="")
AttributeSet addAttributes(LLVMContext &C, unsigned Index, AttributeSet Attrs) const
Add attributes to the attribute set at the given index.
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...
iterator_range< arg_iterator > args()
bool isVoidTy() const
Return true if this is 'void'.