summaryrefslogtreecommitdiff
path: root/lib/Transforms/IPO/MergeFunctions.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'lib/Transforms/IPO/MergeFunctions.cpp')
-rw-r--r--lib/Transforms/IPO/MergeFunctions.cpp252
1 files changed, 136 insertions, 116 deletions
diff --git a/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp
index 76b90391fbb1..139941127dee 100644
--- a/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/lib/Transforms/IPO/MergeFunctions.cpp
@@ -90,7 +90,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ADT/ArrayRef.h"
-#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/IR/Argument.h"
@@ -407,10 +407,10 @@ bool MergeFunctions::runOnModule(Module &M) {
std::vector<WeakTrackingVH> Worklist;
Deferred.swap(Worklist);
- DEBUG(doSanityCheck(Worklist));
+ LLVM_DEBUG(doSanityCheck(Worklist));
- DEBUG(dbgs() << "size of module: " << M.size() << '\n');
- DEBUG(dbgs() << "size of worklist: " << Worklist.size() << '\n');
+ LLVM_DEBUG(dbgs() << "size of module: " << M.size() << '\n');
+ LLVM_DEBUG(dbgs() << "size of worklist: " << Worklist.size() << '\n');
// Insert functions and merge them.
for (WeakTrackingVH &I : Worklist) {
@@ -421,7 +421,7 @@ bool MergeFunctions::runOnModule(Module &M) {
Changed |= insert(F);
}
}
- DEBUG(dbgs() << "size of FnTree: " << FnTree.size() << '\n');
+ LLVM_DEBUG(dbgs() << "size of FnTree: " << FnTree.size() << '\n');
} while (!Deferred.empty());
FnTree.clear();
@@ -498,19 +498,20 @@ static Value *createCast(IRBuilder<> &Builder, Value *V, Type *DestTy) {
// parameter debug info, from the entry block.
void MergeFunctions::eraseInstsUnrelatedToPDI(
std::vector<Instruction *> &PDIUnrelatedWL) {
- DEBUG(dbgs() << " Erasing instructions (in reverse order of appearance in "
- "entry block) unrelated to parameter debug info from entry "
- "block: {\n");
+ LLVM_DEBUG(
+ dbgs() << " Erasing instructions (in reverse order of appearance in "
+ "entry block) unrelated to parameter debug info from entry "
+ "block: {\n");
while (!PDIUnrelatedWL.empty()) {
Instruction *I = PDIUnrelatedWL.back();
- DEBUG(dbgs() << " Deleting Instruction: ");
- DEBUG(I->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Deleting Instruction: ");
+ LLVM_DEBUG(I->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
I->eraseFromParent();
PDIUnrelatedWL.pop_back();
}
- DEBUG(dbgs() << " } // Done erasing instructions unrelated to parameter "
- "debug info from entry block. \n");
+ LLVM_DEBUG(dbgs() << " } // Done erasing instructions unrelated to parameter "
+ "debug info from entry block. \n");
}
// Reduce G to its entry block.
@@ -543,99 +544,113 @@ void MergeFunctions::filterInstsUnrelatedToPDI(
for (BasicBlock::iterator BI = GEntryBlock->begin(), BIE = GEntryBlock->end();
BI != BIE; ++BI) {
if (auto *DVI = dyn_cast<DbgValueInst>(&*BI)) {
- DEBUG(dbgs() << " Deciding: ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Deciding: ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
DILocalVariable *DILocVar = DVI->getVariable();
if (DILocVar->isParameter()) {
- DEBUG(dbgs() << " Include (parameter): ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Include (parameter): ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIRelated.insert(&*BI);
} else {
- DEBUG(dbgs() << " Delete (!parameter): ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Delete (!parameter): ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
} else if (auto *DDI = dyn_cast<DbgDeclareInst>(&*BI)) {
- DEBUG(dbgs() << " Deciding: ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Deciding: ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
DILocalVariable *DILocVar = DDI->getVariable();
if (DILocVar->isParameter()) {
- DEBUG(dbgs() << " Parameter: ");
- DEBUG(DILocVar->print(dbgs()));
+ LLVM_DEBUG(dbgs() << " Parameter: ");
+ LLVM_DEBUG(DILocVar->print(dbgs()));
AllocaInst *AI = dyn_cast_or_null<AllocaInst>(DDI->getAddress());
if (AI) {
- DEBUG(dbgs() << " Processing alloca users: ");
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Processing alloca users: ");
+ LLVM_DEBUG(dbgs() << "\n");
for (User *U : AI->users()) {
if (StoreInst *SI = dyn_cast<StoreInst>(U)) {
if (Value *Arg = SI->getValueOperand()) {
if (dyn_cast<Argument>(Arg)) {
- DEBUG(dbgs() << " Include: ");
- DEBUG(AI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Include: ");
+ LLVM_DEBUG(AI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIRelated.insert(AI);
- DEBUG(dbgs() << " Include (parameter): ");
- DEBUG(SI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Include (parameter): ");
+ LLVM_DEBUG(SI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIRelated.insert(SI);
- DEBUG(dbgs() << " Include: ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Include: ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIRelated.insert(&*BI);
} else {
- DEBUG(dbgs() << " Delete (!parameter): ");
- DEBUG(SI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Delete (!parameter): ");
+ LLVM_DEBUG(SI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
}
} else {
- DEBUG(dbgs() << " Defer: ");
- DEBUG(U->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Defer: ");
+ LLVM_DEBUG(U->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
}
} else {
- DEBUG(dbgs() << " Delete (alloca NULL): ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Delete (alloca NULL): ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
} else {
- DEBUG(dbgs() << " Delete (!parameter): ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Delete (!parameter): ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
} else if (dyn_cast<TerminatorInst>(BI) == GEntryBlock->getTerminator()) {
- DEBUG(dbgs() << " Will Include Terminator: ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Will Include Terminator: ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIRelated.insert(&*BI);
} else {
- DEBUG(dbgs() << " Defer: ");
- DEBUG(BI->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " Defer: ");
+ LLVM_DEBUG(BI->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
}
- DEBUG(dbgs()
- << " Report parameter debug info related/related instructions: {\n");
+ LLVM_DEBUG(
+ dbgs()
+ << " Report parameter debug info related/related instructions: {\n");
for (BasicBlock::iterator BI = GEntryBlock->begin(), BE = GEntryBlock->end();
BI != BE; ++BI) {
Instruction *I = &*BI;
if (PDIRelated.find(I) == PDIRelated.end()) {
- DEBUG(dbgs() << " !PDIRelated: ");
- DEBUG(I->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " !PDIRelated: ");
+ LLVM_DEBUG(I->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
PDIUnrelatedWL.push_back(I);
} else {
- DEBUG(dbgs() << " PDIRelated: ");
- DEBUG(I->print(dbgs()));
- DEBUG(dbgs() << "\n");
+ LLVM_DEBUG(dbgs() << " PDIRelated: ");
+ LLVM_DEBUG(I->print(dbgs()));
+ LLVM_DEBUG(dbgs() << "\n");
}
}
- DEBUG(dbgs() << " }\n");
+ LLVM_DEBUG(dbgs() << " }\n");
+}
+
+// Don't merge tiny functions using a thunk, since it can just end up
+// making the function larger.
+static bool isThunkProfitable(Function * F) {
+ if (F->size() == 1) {
+ if (F->front().size() <= 2) {
+ LLVM_DEBUG(dbgs() << "isThunkProfitable: " << F->getName()
+ << " is too small to bother creating a thunk for\n");
+ return false;
+ }
+ }
+ return true;
}
// Replace G with a simple tail call to bitcast(F). Also (unless
@@ -647,51 +662,19 @@ void MergeFunctions::filterInstsUnrelatedToPDI(
// For better debugability, under MergeFunctionsPDI, we do not modify G's
// call sites to point to F even when within the same translation unit.
void MergeFunctions::writeThunk(Function *F, Function *G) {
- if (!G->isInterposable() && !MergeFunctionsPDI) {
- if (G->hasGlobalUnnamedAddr()) {
- // G might have been a key in our GlobalNumberState, and it's illegal
- // to replace a key in ValueMap<GlobalValue *> with a non-global.
- GlobalNumbers.erase(G);
- // If G's address is not significant, replace it entirely.
- Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType());
- G->replaceAllUsesWith(BitcastF);
- } else {
- // Redirect direct callers of G to F. (See note on MergeFunctionsPDI
- // above).
- replaceDirectCallers(G, F);
- }
- }
-
- // If G was internal then we may have replaced all uses of G with F. If so,
- // stop here and delete G. There's no need for a thunk. (See note on
- // MergeFunctionsPDI above).
- if (G->hasLocalLinkage() && G->use_empty() && !MergeFunctionsPDI) {
- G->eraseFromParent();
- return;
- }
-
- // Don't merge tiny functions using a thunk, since it can just end up
- // making the function larger.
- if (F->size() == 1) {
- if (F->front().size() <= 2) {
- DEBUG(dbgs() << "writeThunk: " << F->getName()
- << " is too small to bother creating a thunk for\n");
- return;
- }
- }
-
BasicBlock *GEntryBlock = nullptr;
std::vector<Instruction *> PDIUnrelatedWL;
BasicBlock *BB = nullptr;
Function *NewG = nullptr;
if (MergeFunctionsPDI) {
- DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) Do not create a new "
- "function as thunk; retain original: "
- << G->getName() << "()\n");
+ LLVM_DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) Do not create a new "
+ "function as thunk; retain original: "
+ << G->getName() << "()\n");
GEntryBlock = &G->getEntryBlock();
- DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) filter parameter related "
- "debug info for "
- << G->getName() << "() {\n");
+ LLVM_DEBUG(
+ dbgs() << "writeThunk: (MergeFunctionsPDI) filter parameter related "
+ "debug info for "
+ << G->getName() << "() {\n");
filterInstsUnrelatedToPDI(GEntryBlock, PDIUnrelatedWL);
GEntryBlock->getTerminator()->eraseFromParent();
BB = GEntryBlock;
@@ -730,13 +713,15 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
CI->setDebugLoc(CIDbgLoc);
RI->setDebugLoc(RIDbgLoc);
} else {
- DEBUG(dbgs() << "writeThunk: (MergeFunctionsPDI) No DISubprogram for "
- << G->getName() << "()\n");
+ LLVM_DEBUG(
+ dbgs() << "writeThunk: (MergeFunctionsPDI) No DISubprogram for "
+ << G->getName() << "()\n");
}
eraseTail(G);
eraseInstsUnrelatedToPDI(PDIUnrelatedWL);
- DEBUG(dbgs() << "} // End of parameter related debug info filtering for: "
- << G->getName() << "()\n");
+ LLVM_DEBUG(
+ dbgs() << "} // End of parameter related debug info filtering for: "
+ << G->getName() << "()\n");
} else {
NewG->copyAttributesFrom(G);
NewG->takeName(G);
@@ -745,7 +730,7 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
G->eraseFromParent();
}
- DEBUG(dbgs() << "writeThunk: " << H->getName() << '\n');
+ LLVM_DEBUG(dbgs() << "writeThunk: " << H->getName() << '\n');
++NumThunksWritten;
}
@@ -754,6 +739,10 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
if (F->isInterposable()) {
assert(G->isInterposable());
+ if (!isThunkProfitable(F)) {
+ return;
+ }
+
// Make them both thunks to the same internal function.
Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "",
F->getParent());
@@ -770,11 +759,41 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
F->setAlignment(MaxAlignment);
F->setLinkage(GlobalValue::PrivateLinkage);
++NumDoubleWeak;
+ ++NumFunctionsMerged;
} else {
+ // For better debugability, under MergeFunctionsPDI, we do not modify G's
+ // call sites to point to F even when within the same translation unit.
+ if (!G->isInterposable() && !MergeFunctionsPDI) {
+ if (G->hasGlobalUnnamedAddr()) {
+ // G might have been a key in our GlobalNumberState, and it's illegal
+ // to replace a key in ValueMap<GlobalValue *> with a non-global.
+ GlobalNumbers.erase(G);
+ // If G's address is not significant, replace it entirely.
+ Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType());
+ G->replaceAllUsesWith(BitcastF);
+ } else {
+ // Redirect direct callers of G to F. (See note on MergeFunctionsPDI
+ // above).
+ replaceDirectCallers(G, F);
+ }
+ }
+
+ // If G was internal then we may have replaced all uses of G with F. If so,
+ // stop here and delete G. There's no need for a thunk. (See note on
+ // MergeFunctionsPDI above).
+ if (G->hasLocalLinkage() && G->use_empty() && !MergeFunctionsPDI) {
+ G->eraseFromParent();
+ ++NumFunctionsMerged;
+ return;
+ }
+
+ if (!isThunkProfitable(F)) {
+ return;
+ }
+
writeThunk(F, G);
+ ++NumFunctionsMerged;
}
-
- ++NumFunctionsMerged;
}
/// Replace function F by function G.
@@ -806,7 +825,8 @@ bool MergeFunctions::insert(Function *NewFunction) {
if (Result.second) {
assert(FNodesInTree.count(NewFunction) == 0);
FNodesInTree.insert({NewFunction, Result.first});
- DEBUG(dbgs() << "Inserting as unique: " << NewFunction->getName() << '\n');
+ LLVM_DEBUG(dbgs() << "Inserting as unique: " << NewFunction->getName()
+ << '\n');
return false;
}
@@ -827,8 +847,8 @@ bool MergeFunctions::insert(Function *NewFunction) {
assert(OldF.getFunc() != F && "Must have swapped the functions.");
}
- DEBUG(dbgs() << " " << OldF.getFunc()->getName()
- << " == " << NewFunction->getName() << '\n');
+ LLVM_DEBUG(dbgs() << " " << OldF.getFunc()->getName()
+ << " == " << NewFunction->getName() << '\n');
Function *DeleteF = NewFunction;
mergeTwoFunctions(OldF.getFunc(), DeleteF);
@@ -840,7 +860,7 @@ bool MergeFunctions::insert(Function *NewFunction) {
void MergeFunctions::remove(Function *F) {
auto I = FNodesInTree.find(F);
if (I != FNodesInTree.end()) {
- DEBUG(dbgs() << "Deferred " << F->getName()<< ".\n");
+ LLVM_DEBUG(dbgs() << "Deferred " << F->getName() << ".\n");
FnTree.erase(I->second);
// I->second has been invalidated, remove it from the FNodesInTree map to
// preserve the invariant.
@@ -854,7 +874,7 @@ void MergeFunctions::remove(Function *F) {
void MergeFunctions::removeUsers(Value *V) {
std::vector<Value *> Worklist;
Worklist.push_back(V);
- SmallSet<Value*, 8> Visited;
+ SmallPtrSet<Value*, 8> Visited;
Visited.insert(V);
while (!Worklist.empty()) {
Value *V = Worklist.back();