Skip to content
This repository has been archived by the owner on Feb 5, 2019. It is now read-only.

Commit

Permalink
Merge pull request #131 from nikic/some-fixes
Browse files Browse the repository at this point in the history
Misc
  • Loading branch information
alexcrichton authored Nov 28, 2018
2 parents 21a0c9e + 63e77c8 commit a784eca
Show file tree
Hide file tree
Showing 6 changed files with 189 additions and 166 deletions.
8 changes: 0 additions & 8 deletions include/llvm/IR/Instruction.h
Original file line number Diff line number Diff line change
Expand Up @@ -586,14 +586,6 @@ class Instruction : public User,
static_cast<const Instruction *>(this)->getNextNonDebugInstruction());
}

/// Return a pointer to the previous non-debug instruction in the same basic
/// block as 'this', or nullptr if no such instruction exists.
const Instruction *getPrevNonDebugInstruction() const;
Instruction *getPrevNonDebugInstruction() {
return const_cast<Instruction *>(
static_cast<const Instruction *>(this)->getPrevNonDebugInstruction());
}

/// Create a copy of 'this' instruction that is identical in all ways except
/// the following:
/// * The instruction has no parent
Expand Down
7 changes: 0 additions & 7 deletions lib/IR/Instruction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -602,13 +602,6 @@ const Instruction *Instruction::getNextNonDebugInstruction() const {
return nullptr;
}

const Instruction *Instruction::getPrevNonDebugInstruction() const {
for (const Instruction *I = getPrevNode(); I; I = I->getPrevNode())
if (!isa<DbgInfoIntrinsic>(I))
return I;
return nullptr;
}

bool Instruction::isAssociative() const {
unsigned Opcode = getOpcode();
if (isAssociative(Opcode))
Expand Down
87 changes: 73 additions & 14 deletions lib/Transforms/IPO/MergeFunctions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ using namespace llvm;

STATISTIC(NumFunctionsMerged, "Number of functions merged");
STATISTIC(NumThunksWritten, "Number of thunks generated");
STATISTIC(NumAliasesWritten, "Number of aliases generated");
STATISTIC(NumDoubleWeak, "Number of new functions created");

static cl::opt<unsigned> NumFunctionsForSanityCheck(
Expand Down Expand Up @@ -165,6 +166,11 @@ static cl::opt<bool>
cl::desc("Preserve debug info in thunk when mergefunc "
"transformations are made."));

static cl::opt<bool>
MergeFunctionsAliases("mergefunc-use-aliases", cl::Hidden,
cl::init(false),
cl::desc("Allow mergefunc to create aliases"));

namespace {

class FunctionNode {
Expand Down Expand Up @@ -272,6 +278,13 @@ class MergeFunctions : public ModulePass {
/// delete G.
void writeThunk(Function *F, Function *G);

// Replace G with an alias to F (deleting function G)
void writeAlias(Function *F, Function *G);

// Replace G with an alias to F if possible, or a thunk to F if
// profitable. Returns false if neither is the case.
bool writeThunkOrAlias(Function *F, Function *G);

/// Replace function F with function G in the function tree.
void replaceFunctionInTree(const FunctionNode &FN, Function *G);

Expand Down Expand Up @@ -735,27 +748,76 @@ void MergeFunctions::writeThunk(Function *F, Function *G) {
++NumThunksWritten;
}

// Whether this function may be replaced by an alias
static bool canCreateAliasFor(Function *F) {
if (!MergeFunctionsAliases || !F->hasGlobalUnnamedAddr())
return false;

// We should only see linkages supported by aliases here
assert(F->hasLocalLinkage() || F->hasExternalLinkage()
|| F->hasWeakLinkage() || F->hasLinkOnceLinkage());
return true;
}

// Replace G with an alias to F (deleting function G)
void MergeFunctions::writeAlias(Function *F, Function *G) {
Constant *BitcastF = ConstantExpr::getBitCast(F, G->getType());
PointerType *PtrType = G->getType();
auto *GA = GlobalAlias::create(
PtrType->getElementType(), PtrType->getAddressSpace(),
G->getLinkage(), "", BitcastF, G->getParent());

F->setAlignment(std::max(F->getAlignment(), G->getAlignment()));
GA->takeName(G);
GA->setVisibility(G->getVisibility());
GA->setUnnamedAddr(GlobalValue::UnnamedAddr::Global);

removeUsers(G);
G->replaceAllUsesWith(GA);
G->eraseFromParent();

LLVM_DEBUG(dbgs() << "writeAlias: " << GA->getName() << '\n');
++NumAliasesWritten;
}

// Replace G with an alias to F if possible, or a thunk to F if
// profitable. Returns false if neither is the case.
bool MergeFunctions::writeThunkOrAlias(Function *F, Function *G) {
if (canCreateAliasFor(G)) {
writeAlias(F, G);
return true;
}
if (isThunkProfitable(F)) {
writeThunk(F, G);
return true;
}
return false;
}

// Merge two equivalent functions. Upon completion, Function G is deleted.
void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
if (F->isInterposable()) {
assert(G->isInterposable());

if (!isThunkProfitable(F)) {
// Both writeThunkOrAlias() calls below must succeed, either because we can
// create aliases for G and NewF, or because a thunk for F is profitable.
// F here has the same signature as NewF below, so that's what we check.
if (!isThunkProfitable(F) && (!canCreateAliasFor(F) || !canCreateAliasFor(G))) {
return;
}

// Make them both thunks to the same internal function.
Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "",
F->getParent());
H->copyAttributesFrom(F);
H->takeName(F);
Function *NewF = Function::Create(F->getFunctionType(), F->getLinkage(), "",
F->getParent());
NewF->copyAttributesFrom(F);
NewF->takeName(F);
removeUsers(F);
F->replaceAllUsesWith(H);
F->replaceAllUsesWith(NewF);

unsigned MaxAlignment = std::max(G->getAlignment(), H->getAlignment());
unsigned MaxAlignment = std::max(G->getAlignment(), NewF->getAlignment());

writeThunk(F, G);
writeThunk(F, H);
writeThunkOrAlias(F, G);
writeThunkOrAlias(F, NewF);

F->setAlignment(MaxAlignment);
F->setLinkage(GlobalValue::PrivateLinkage);
Expand Down Expand Up @@ -789,12 +851,9 @@ void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
return;
}

if (!isThunkProfitable(F)) {
return;
if (writeThunkOrAlias(F, G)) {
++NumFunctionsMerged;
}

writeThunk(F, G);
++NumFunctionsMerged;
}
}

Expand Down
16 changes: 0 additions & 16 deletions lib/Transforms/Utils/SimplifyCFG.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1372,14 +1372,6 @@ static bool HoistThenElseCodeToIf(BranchInst *BI,
}
}

// As the parent basic block terminator is a branch instruction which is
// removed at the end of the current transformation, use its previous
// non-debug instruction, as the reference insertion point, which will
// provide the debug location for the instruction being hoisted. For BBs
// with only debug instructions, use an empty debug location.
Instruction *InsertPt =
BIParent->getTerminator()->getPrevNonDebugInstruction();

// Okay, it is safe to hoist the terminator.
Instruction *NT = I1->clone();
BIParent->getInstList().insert(BI->getIterator(), NT);
Expand All @@ -1389,14 +1381,6 @@ static bool HoistThenElseCodeToIf(BranchInst *BI,
NT->takeName(I1);
}

// The instruction NT being hoisted, is the terminator for the true branch,
// with debug location (DILocation) within that branch. We can't retain
// its original debug location value, otherwise 'select' instructions that
// are created from any PHI nodes, will take its debug location, giving
// the impression that those 'select' instructions are in the true branch,
// causing incorrect stepping, affecting the debug experience.
NT->setDebugLoc(InsertPt ? InsertPt->getDebugLoc() : DebugLoc());

IRBuilder<NoFolder> Builder(NT);
// Hoisting one of the terminators from our successor is a great thing.
// Unfortunately, the successors of the if/else blocks may have PHI nodes in
Expand Down
121 changes: 0 additions & 121 deletions test/CodeGen/X86/pr39187-g.ll

This file was deleted.

Loading

0 comments on commit a784eca

Please sign in to comment.