Don't IPO over functions that can be de-refined

Summary:
Fixes PR26774.

If you're aware of the issue, feel free to skip the "Motivation"
section and jump directly to "This patch".

Motivation:

I define "refinement" as discarding behaviors from a program that the
optimizer has license to discard.  So transforming:

```
void f(unsigned x) {
  unsigned t = 5 / x;
  (void)t;
}
```

to

```
void f(unsigned x) { }
```

is refinement, since the behavior went from "if x == 0 then undefined
else nothing" to "nothing" (the optimizer has license to discard
undefined behavior).

Refinement is a fundamental aspect of many mid-level optimizations done
by LLVM.  For instance, transforming `x == (x + 1)` to `false` also
involves refinement since the expression's value went from "if x is
`undef` then { `true` or `false` } else { `false` }" to "`false`" (by
definition, the optimizer has license to fold `undef` to any non-`undef`
value).

Unfortunately, refinement implies that the optimizer cannot assume
that the implementation of a function it can see has all of the
behavior an unoptimized or a differently optimized version of the same
function can have.  This is a problem for functions with comdat
linkage, where a function can be replaced by an unoptimized or a
differently optimized version of the same source level function.

For instance, FunctionAttrs cannot assume a comdat function is
actually `readnone` even if it does not have any loads or stores in
it; since there may have been loads and stores in the "original
function" that were refined out in the currently visible variant, and
at the link step the linker may in fact choose an implementation with
a load or a store.  As an example, consider a function that does two
atomic loads from the same memory location, and writes to memory only
if the two values are not equal.  The optimizer is allowed to refine
this function by first CSE'ing the two loads, and the folding the
comparision to always report that the two values are equal.  Such a
refined variant will look like it is `readonly`.  However, the
unoptimized version of the function can still write to memory (since
the two loads //can// result in different values), and selecting the
unoptimized version at link time will retroactively invalidate
transforms we may have done under the assumption that the function
does not write to memory.

Note: this is not just a problem with atomics or with linking
differently optimized object files.  See PR26774 for more realistic
examples that involved neither.

This patch:

This change introduces a new set of linkage types, predicated as
`GlobalValue::mayBeDerefined` that returns true if the linkage type
allows a function to be replaced by a differently optimized variant at
link time.  It then changes a set of IPO passes to bail out if they see
such a function.

Reviewers: chandlerc, hfinkel, dexonsmith, joker.eph, rnk

Subscribers: mcrosier, llvm-commits

Differential Revision: http://reviews.llvm.org/D18634

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265762 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
Sanjoy Das 2016-04-08 00:48:30 +00:00
parent 86c8abfe54
commit c9e3e3cbfd
32 changed files with 336 additions and 72 deletions

View File

@ -96,6 +96,56 @@ private:
void destroyConstantImpl();
Value *handleOperandChangeImpl(Value *From, Value *To);
/// Returns true if the definition of this global may be replaced by a
/// differently optimized variant of the same source level function at link
/// time.
bool mayBeDerefined() const {
switch (getLinkage()) {
case WeakODRLinkage:
case LinkOnceODRLinkage:
case AvailableExternallyLinkage:
return true;
case WeakAnyLinkage:
case LinkOnceAnyLinkage:
case CommonLinkage:
case ExternalWeakLinkage:
case ExternalLinkage:
case AppendingLinkage:
case InternalLinkage:
case PrivateLinkage:
return mayBeOverridden();
}
llvm_unreachable("Fully covered switch above!");
}
/// Whether the definition of this global may be replaced by something
/// non-equivalent at link time. For example, if a function has weak linkage
/// then the code defining it may be replaced by different code.
bool mayBeOverridden() const {
switch (getLinkage()) {
case WeakAnyLinkage:
case LinkOnceAnyLinkage:
case CommonLinkage:
case ExternalWeakLinkage:
return true;
case AvailableExternallyLinkage:
case LinkOnceODRLinkage:
case WeakODRLinkage:
// The above three cannot be overridden but can be de-refined.
case ExternalLinkage:
case AppendingLinkage:
case InternalLinkage:
case PrivateLinkage:
return false;
}
llvm_unreachable("Fully covered switch above!");
}
protected:
/// \brief The intrinsic ID for this subclass (which must be a Function).
///
@ -242,14 +292,6 @@ public:
isAvailableExternallyLinkage(Linkage);
}
/// Whether the definition of this global may be replaced by something
/// non-equivalent at link time. For example, if a function has weak linkage
/// then the code defining it may be replaced by different code.
static bool mayBeOverridden(LinkageTypes Linkage) {
return Linkage == WeakAnyLinkage || Linkage == LinkOnceAnyLinkage ||
Linkage == CommonLinkage || Linkage == ExternalWeakLinkage;
}
/// Whether the definition of this global may be replaced at link time. NB:
/// Using this method outside of the code generators is almost always a
/// mistake: when working at the IR level use mayBeOverridden instead as it
@ -260,6 +302,52 @@ public:
Linkage == CommonLinkage || Linkage == ExternalWeakLinkage;
}
/// Return true if the currently visible definition of this global (if any) is
/// exactly the definition we will see at runtime.
///
/// Non-exact linkage types inhibits most non-inlining IPO, since a
/// differently optimized variant of the same function can have different
/// observable or undefined behavior than in the variant currently visible.
/// For instance, we could have started with
///
/// void foo(int *v) {
/// int t = 5 / v[0];
/// (void) t;
/// }
///
/// and "refined" it to
///
/// void foo(int *v) { }
///
/// However, we cannot infer readnone for `foo`, since that would justify
/// DSE'ing a store to `v[0]` across a call to `foo`, which can cause
/// undefined behavior if the linker replaces the actual call destination with
/// the unoptimized `foo`.
///
/// Inlining is okay across non-exact linkage types as long as they're not
/// interposable (see \c isInterposable), since in such cases the currently
/// visible variant is *a* correct implementation of the original source
/// function; it just isn't the *only* correct implementation.
bool isDefinitionExact() const {
return !mayBeDerefined();
}
/// Return true if this global has an exact defintion.
bool hasExactDefinition() const {
// While this computes exactly the same thing as
// isStrongDefinitionForLinker, the intended uses are different. This
// function is intended to help decide if specific inter-procedural
// transforms are correct, while isStrongDefinitionForLinker's intended use
// is in low level code generation.
return !isDeclaration() && isDefinitionExact();
}
/// Return true if this global's definition can be substituted with an
/// *arbitrary* definition at link time. We cannot do any IPO or inlinining
/// across interposable call edges, since the callee can be replaced with
/// something arbitrary at link time.
bool isInterposable() const { return mayBeOverridden(); }
bool hasExternalLinkage() const { return isExternalLinkage(getLinkage()); }
bool hasAvailableExternallyLinkage() const {
return isAvailableExternallyLinkage(getLinkage());
@ -291,8 +379,6 @@ public:
return isDiscardableIfUnused(getLinkage());
}
bool mayBeOverridden() const { return mayBeOverridden(getLinkage()); }
bool isWeakForLinker() const { return isWeakForLinker(getLinkage()); }
/// Copy all additional attributes (those not needed to create a GlobalValue)
@ -365,6 +451,10 @@ public:
/// Returns true if this global's definition will be the one chosen by the
/// linker.
///
/// NB! Ideally this should not be used at the IR level at all. If you're
/// interested in optimization constraints implied by the linker's ability to
/// choose an implementation, prefer using \c hasExactDefinition.
bool isStrongDefinitionForLinker() const {
return !(isDeclarationForLinker() || isWeakForLinker());
}

View File

@ -94,9 +94,9 @@ public:
/// unique.
inline bool hasDefinitiveInitializer() const {
return hasInitializer() &&
// The initializer of a global variable with weak linkage may change at
// link time.
!mayBeOverridden() &&
// The initializer of a global variable may change to something arbitrary
// at link time.
!isInterposable() &&
// The initializer of a global variable with the externally_initialized
// marker may change at runtime before C++ initializers are evaluated.
!isExternallyInitialized();

View File

@ -359,7 +359,7 @@ static int64_t adjustToPointerSize(int64_t Offset, unsigned PointerSize) {
if (!Op) {
// The only non-operator case we can handle are GlobalAliases.
if (const GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->mayBeOverridden()) {
if (!GA->isInterposable()) {
V = GA->getAliasee();
continue;
}

View File

@ -531,7 +531,7 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
return GV->getInitializer();
if (auto *GA = dyn_cast<GlobalAlias>(C))
if (GA->getAliasee() && !GA->mayBeOverridden())
if (GA->getAliasee() && !GA->isInterposable())
return ConstantFoldLoadFromConstPtr(GA->getAliasee(), Ty, DL);
// If the loaded value isn't a constant expr, we can't handle it.

View File

@ -471,9 +471,10 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) {
const std::vector<CallGraphNode *> &SCC = *I;
assert(!SCC.empty() && "SCC with no functions?");
if (!SCC[0]->getFunction() || SCC[0]->getFunction()->mayBeOverridden()) {
// Calls externally or is weak - can't say anything useful. Remove any existing
// function records (may have been created when scanning globals).
if (!SCC[0]->getFunction() || !SCC[0]->getFunction()->isDefinitionExact()) {
// Calls externally or not exact - can't say anything useful. Remove any
// existing function records (may have been created when scanning
// globals).
for (auto *Node : SCC)
FunctionInfos.erase(Node->getFunction());
continue;
@ -699,7 +700,7 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
auto *InputGVar = dyn_cast<GlobalVariable>(InputGV);
if (GVar && InputGVar &&
!GVar->isDeclaration() && !InputGVar->isDeclaration() &&
!GVar->mayBeOverridden() && !InputGVar->mayBeOverridden()) {
!GVar->isInterposable() && !InputGVar->isInterposable()) {
Type *GVType = GVar->getInitializer()->getType();
Type *InputGVType = InputGVar->getInitializer()->getType();
if (GVType->isSized() && InputGVType->isSized() &&

View File

@ -1125,7 +1125,7 @@ ConstantInt *CallAnalyzer::stripAndComputeInBoundsConstantOffsets(Value *&V) {
} else if (Operator::getOpcode(V) == Instruction::BitCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (GA->mayBeOverridden())
if (GA->isInterposable())
break;
V = GA->getAliasee();
} else {
@ -1477,10 +1477,11 @@ InlineCost llvm::getInlineCost(CallSite CS, Function *Callee,
if (CS.getCaller()->hasFnAttribute(Attribute::OptimizeNone))
return llvm::InlineCost::getNever();
// Don't inline functions which can be redefined at link-time to mean
// something else. Don't inline functions marked noinline or call sites
// marked noinline.
if (Callee->mayBeOverridden() ||
// Don't inline functions which can be interposed at link-time. Don't inline
// functions marked noinline or call sites marked noinline.
// Note: inlining non-exact non-interposable fucntions is fine, since we know
// we have *a* correct implementation of the source level function.
if (Callee->isInterposable() ||
Callee->hasFnAttribute(Attribute::NoInline) || CS.isNoInline())
return llvm::InlineCost::getNever();

View File

@ -616,7 +616,7 @@ static Constant *stripAndComputeConstantOffsets(const DataLayout &DL, Value *&V,
} else if (Operator::getOpcode(V) == Instruction::BitCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (GA->mayBeOverridden())
if (GA->isInterposable())
break;
V = GA->getAliasee();
} else {

View File

@ -299,9 +299,9 @@ bool llvm::isSafeToLoadUnconditionally(Value *V, unsigned Align,
BaseAlign = AI->getAlignment();
} else if (const GlobalVariable *GV = dyn_cast<GlobalVariable>(Base)) {
// Global variables are not necessarily safe to load from if they are
// overridden. Their size may change or they may be weak and require a test
// to determine if they were in fact provided.
if (!GV->mayBeOverridden()) {
// interposed arbitrarily. Their size may change or they may be weak and
// require a test to determine if they were in fact provided.
if (!GV->isInterposable()) {
BaseType = GV->getType()->getElementType();
BaseAlign = GV->getAlignment();
}

View File

@ -529,7 +529,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::visitGEPOperator(GEPOperator &GEP) {
}
SizeOffsetType ObjectSizeOffsetVisitor::visitGlobalAlias(GlobalAlias &GA) {
if (GA.mayBeOverridden())
if (GA.isInterposable())
return unknown();
return compute(GA.getAliasee());
}

View File

@ -4828,7 +4828,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
else if (isa<ConstantPointerNull>(V))
return getZero(V->getType());
else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V))
return GA->mayBeOverridden() ? getUnknown(V) : getSCEV(GA->getAliasee());
return GA->isInterposable() ? getUnknown(V) : getSCEV(GA->getAliasee());
else if (!isa<ConstantExpr>(V))
return getUnknown(V);

View File

@ -1450,7 +1450,7 @@ void computeKnownBits(Value *V, APInt &KnownZero, APInt &KnownOne,
// A weak GlobalAlias is totally unknown. A non-weak GlobalAlias has
// the bits of its aliasee.
if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->mayBeOverridden())
if (!GA->isInterposable())
computeKnownBits(GA->getAliasee(), KnownZero, KnownOne, Depth + 1, Q);
return;
}
@ -2640,7 +2640,7 @@ Value *llvm::GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset,
Operator::getOpcode(Ptr) == Instruction::AddrSpaceCast) {
Ptr = cast<Operator>(Ptr)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) {
if (GA->mayBeOverridden())
if (GA->isInterposable())
break;
Ptr = GA->getAliasee();
} else {
@ -2836,7 +2836,7 @@ Value *llvm::GetUnderlyingObject(Value *V, const DataLayout &DL,
Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (GA->mayBeOverridden())
if (GA->isInterposable())
return V;
V = GA->getAliasee();
} else {

View File

@ -460,7 +460,7 @@ static Value *stripPointerCastsAndOffsets(Value *V) {
Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (StripKind == PSK_ZeroIndices || GA->mayBeOverridden())
if (StripKind == PSK_ZeroIndices || GA->isInterposable())
return V;
V = GA->getAliasee();
} else {

View File

@ -626,7 +626,7 @@ void Verifier::visitAliaseeSubExpr(SmallPtrSetImpl<const GlobalAlias*> &Visited,
if (const auto *GA2 = dyn_cast<GlobalAlias>(GV)) {
Assert(Visited.insert(GA2).second, "Aliases cannot form a cycle", &GA);
Assert(!GA2->mayBeOverridden(), "Alias cannot point to a weak alias",
Assert(!GA2->isInterposable(), "Alias cannot point to an interposable alias",
&GA);
} else {
// Only continue verifying subexpressions of GlobalAliases.

View File

@ -329,7 +329,7 @@ bool DAE::RemoveDeadArgumentsFromCallers(Function &Fn)
// %v = load i32 %p
// ret void
// }
if (!Fn.isStrongDefinitionForLinker())
if (!Fn.hasExactDefinition())
return false;
// Functions with local linkage should already have been handled, except the

View File

@ -69,9 +69,10 @@ static MemoryAccessKind checkFunctionMemoryAccess(Function &F, AAResults &AAR,
// Already perfect!
return MAK_ReadNone;
// Definitions with weak linkage may be overridden at linktime with
// something that writes memory, so treat them like declarations.
if (F.isDeclaration() || F.mayBeOverridden()) {
// Non-exact function definitions may not be selected at link time, and an
// alternative version that writes to memory may be selected. See the comment
// on GlobalValue::isDefinitionExact for more details.
if (!F.hasExactDefinition()) {
if (AliasAnalysis::onlyReadsMemory(MRB))
return MAK_ReadOnly;
@ -284,8 +285,7 @@ struct ArgumentUsesTracker : public CaptureTracker {
}
Function *F = CS.getCalledFunction();
if (!F || F->isDeclaration() || F->mayBeOverridden() ||
!SCCNodes.count(F)) {
if (!F || !F->hasExactDefinition() || !SCCNodes.count(F)) {
Captured = true;
return true;
}
@ -490,9 +490,10 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
// Check each function in turn, determining which pointer arguments are not
// captured.
for (Function *F : SCCNodes) {
// Definitions with weak linkage may be overridden at linktime with
// something that captures pointers, so treat them like declarations.
if (F->isDeclaration() || F->mayBeOverridden())
// We can infer and propagate function attributes only when we know that the
// definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
continue;
// Functions that are readonly (or readnone) and nounwind and don't return
@ -745,9 +746,10 @@ static bool addNoAliasAttrs(const SCCNodeSet &SCCNodes) {
if (F->doesNotAlias(0))
continue;
// Definitions with weak linkage may be overridden at linktime, so
// treat them like declarations.
if (F->isDeclaration() || F->mayBeOverridden())
// We can infer and propagate function attributes only when we know that the
// definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
return false;
// We annotate noalias return values, which are only applicable to
@ -859,9 +861,10 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes,
Attribute::NonNull))
continue;
// Definitions with weak linkage may be overridden at linktime, so
// treat them like declarations.
if (F->isDeclaration() || F->mayBeOverridden())
// We can infer and propagate function attributes only when we know that the
// definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
return false;
// We annotate nonnull return values, which are only applicable to

View File

@ -2366,7 +2366,7 @@ bool GlobalOpt::OptimizeGlobalAliases(Module &M) {
}
// If the aliasee may change at link time, nothing can be done - bail out.
if (J->mayBeOverridden())
if (J->isInterposable())
continue;
Constant *Aliasee = J->getAliasee();

View File

@ -161,9 +161,10 @@ bool IPCP::PropagateConstantReturn(Function &F) {
if (F.getReturnType()->isVoidTy())
return false; // No return value.
// If this function could be overridden later in the link stage, we can't
// propagate information about its results into callers.
if (F.mayBeOverridden())
// We can infer and propagate the return value only when we know that the
// definition we'll get at link time is *exactly* the definition we see now.
// For more details, see GlobalValue::mayBeDerefined.
if (!F.isDefinitionExact())
return false;
// Check to see if this function returns a constant.

View File

@ -1572,7 +1572,7 @@ bool MergeFunctions::runOnModule(Module &M) {
if (!*I) continue;
Function *F = cast<Function>(*I);
if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage() &&
!F->mayBeOverridden()) {
!F->isInterposable()) {
Changed |= insert(F);
}
}
@ -1586,7 +1586,7 @@ bool MergeFunctions::runOnModule(Module &M) {
if (!*I) continue;
Function *F = cast<Function>(*I);
if (!F->isDeclaration() && !F->hasAvailableExternallyLinkage() &&
F->mayBeOverridden()) {
F->isInterposable()) {
Changed |= insert(F);
}
}
@ -1683,7 +1683,7 @@ static Value *createCast(IRBuilder<> &Builder, Value *V, Type *DestTy) {
// Replace G with a simple tail call to bitcast(F). Also replace direct uses
// of G with bitcast(F). Deletes G.
void MergeFunctions::writeThunk(Function *F, Function *G) {
if (!G->mayBeOverridden()) {
if (!G->isInterposable()) {
// Redirect direct callers of G to F.
replaceDirectCallers(G, F);
}
@ -1744,8 +1744,8 @@ void MergeFunctions::writeAlias(Function *F, Function *G) {
// Merge two equivalent functions. Upon completion, Function G is deleted.
void MergeFunctions::mergeTwoFunctions(Function *F, Function *G) {
if (F->mayBeOverridden()) {
assert(G->mayBeOverridden());
if (F->isInterposable()) {
assert(G->isInterposable());
// Make them both thunks to the same internal function.
Function *H = Function::Create(F->getFunctionType(), F->getLinkage(), "",
@ -1828,8 +1828,8 @@ bool MergeFunctions::insert(Function *NewFunction) {
//
// When one function is weak and the other is strong there is an order imposed
// already. We process strong functions before weak functions.
if ((OldF.getFunc()->mayBeOverridden() && NewFunction->mayBeOverridden()) ||
(!OldF.getFunc()->mayBeOverridden() && !NewFunction->mayBeOverridden()))
if ((OldF.getFunc()->isInterposable() && NewFunction->isInterposable()) ||
(!OldF.getFunc()->isInterposable() && !NewFunction->isInterposable()))
if (OldF.getFunc()->getName() > NewFunction->getName()) {
// Swap the two functions.
Function *F = OldF.getFunc();
@ -1839,7 +1839,7 @@ bool MergeFunctions::insert(Function *NewFunction) {
}
// Never thunk a strong function to a weak function.
assert(!OldF.getFunc()->mayBeOverridden() || NewFunction->mayBeOverridden());
assert(!OldF.getFunc()->isInterposable() || NewFunction->isInterposable());
DEBUG(dbgs() << " " << OldF.getFunc()->getName()
<< " == " << NewFunction->getName() << '\n');

View File

@ -93,7 +93,10 @@ bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
if (!F) {
SCCMightUnwind = true;
SCCMightReturn = true;
} else if (F->isDeclaration() || F->mayBeOverridden()) {
} else if (F->isDeclaration() || F->isInterposable()) {
// Note: isInterposable (as opposed to hasExactDefinition) is fine above,
// since we're not inferring new attributes here, but only using existing,
// assumed to be correct, function attributes.
SCCMightUnwind |= !F->doesNotThrow();
SCCMightReturn |= !F->doesNotReturn();
} else {

View File

@ -640,7 +640,7 @@ static bool isObjectSizeLessThanOrEq(Value *V, uint64_t MaxSize,
}
if (GlobalAlias *GA = dyn_cast<GlobalAlias>(P)) {
if (GA->mayBeOverridden())
if (!GA->isInterposable())
return false;
Worklist.push_back(GA->getAliasee());
continue;

View File

@ -70,7 +70,7 @@ void ObjCARCAPElim::getAnalysisUsage(AnalysisUsage &AU) const {
/// possibly produce autoreleases.
bool ObjCARCAPElim::MayAutorelease(ImmutableCallSite CS, unsigned Depth) {
if (const Function *Callee = CS.getCalledFunction()) {
if (Callee->isDeclaration() || Callee->mayBeOverridden())
if (!Callee->hasExactDefinition())
return true;
for (const BasicBlock &BB : *Callee) {
for (const Instruction &I : BB)

View File

@ -605,7 +605,7 @@ bool ObjCARCContract::runOnFunction(Function &F) {
cast<GEPOperator>(Arg)->hasAllZeroIndices())
Arg = cast<GEPOperator>(Arg)->getPointerOperand();
else if (isa<GlobalAlias>(Arg) &&
!cast<GlobalAlias>(Arg)->mayBeOverridden())
!cast<GlobalAlias>(Arg)->isInterposable())
Arg = cast<GlobalAlias>(Arg)->getAliasee();
else
break;

View File

@ -1724,9 +1724,9 @@ bool IPSCCP::runOnModule(Module &M) {
if (F->isDeclaration())
continue;
// If this is a strong or ODR definition of this function, then we can
// propagate information about its result into callsites of it.
if (!F->mayBeOverridden())
// If this is an exact definition of this function, then we can propagate
// information about its result into callsites of it.
if (F->hasExactDefinition())
Solver.AddTrackedFunction(&*F);
// If this function only has direct calls that we can see, we can track its

View File

@ -1549,7 +1549,7 @@ static Value *getAdjustedPtr(IRBuilderTy &IRB, const DataLayout &DL, Value *Ptr,
if (Operator::getOpcode(Ptr) == Instruction::BitCast) {
Ptr = cast<Operator>(Ptr)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) {
if (GA->mayBeOverridden())
if (GA->isInterposable())
break;
Ptr = GA->getAliasee();
} else {

View File

@ -427,7 +427,7 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst,
// Resolve function pointers.
Function *Callee = dyn_cast<Function>(getVal(CS.getCalledValue()));
if (!Callee || Callee->mayBeOverridden()) {
if (!Callee || Callee->isInterposable()) {
DEBUG(dbgs() << "Can not resolve function pointer.\n");
return false; // Cannot resolve.
}

View File

@ -0,0 +1,21 @@
; RUN: opt < %s -basicaa -globals-aa -gvn -S | FileCheck %s
; See PR26774
@X = internal global i32 4
define i32 @test(i32* %P) {
; CHECK: @test
; CHECK-NEXT: store i32 12, i32* @X
; CHECK-NEXT: call void @doesnotmodX()
; CHECK-NEXT: %V = load i32, i32* @X
; CHECK-NEXT: ret i32 %V
store i32 12, i32* @X
call void @doesnotmodX( )
%V = load i32, i32* @X
ret i32 %V
}
define linkonce_odr void @doesnotmodX() {
ret void
}

View File

@ -0,0 +1,16 @@
; RUN: opt < %s -functionattrs -S | FileCheck %s
; See PR26774
; CHECK-LABEL: define void @bar(i8* readonly) {
define void @bar(i8* readonly) {
call void @foo(i8* %0)
ret void
}
; CHECK-LABEL: define linkonce_odr void @foo(i8* readonly) {
define linkonce_odr void @foo(i8* readonly) {
call void @bar(i8* %0)
ret void
}

View File

@ -0,0 +1,28 @@
; RUN: opt < %s -ipconstprop -S | FileCheck %s
; See PR26774
define i32 @baz() {
ret i32 10
}
; We can const-prop @baz's return value *into* @foo, but cannot
; constprop @foo's return value into bar.
define linkonce_odr i32 @foo() {
; CHECK-LABEL: @foo(
; CHECK-NEXT: %val = call i32 @baz()
; CHECK-NEXT: ret i32 10
%val = call i32 @baz()
ret i32 %val
}
define i32 @bar() {
; CHECK-LABEL: @bar(
; CHECK-NEXT: %val = call i32 @foo()
; CHECK-NEXT: ret i32 %val
%val = call i32 @foo()
ret i32 %val
}

View File

@ -0,0 +1,19 @@
; RUN: opt -inline -S < %s | FileCheck %s
define i32 @caller() {
; CHECK-LABEL: @caller(
; CHECK-NEXT: %val2 = call i32 @linkonce_callee(i32 42)
; CHECK-NEXT: ret i32 %val2
%val = call i32 @odr_callee()
%val2 = call i32 @linkonce_callee(i32 %val);
ret i32 %val2
}
define linkonce_odr i32 @odr_callee() {
ret i32 42
}
define linkonce i32 @linkonce_callee(i32 %val) {
ret i32 %val
}

View File

@ -0,0 +1,53 @@
; RUN: opt -S -objc-arc-apelim < %s | FileCheck %s
; See PR26774
@llvm.global_ctors = appending global [2 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_x }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_y }]
@x = global i32 0
declare i32 @bar() nounwind
define linkonce_odr i32 @foo() nounwind {
entry:
ret i32 5
}
define internal void @__cxx_global_var_init() {
entry:
%call = call i32 @foo()
store i32 %call, i32* @x, align 4
ret void
}
define internal void @__dxx_global_var_init() {
entry:
%call = call i32 @bar()
store i32 %call, i32* @x, align 4
ret void
}
; CHECK-LABEL: define internal void @_GLOBAL__I_x() {
define internal void @_GLOBAL__I_x() {
entry:
; CHECK: call i8* @objc_autoreleasePoolPush()
; CHECK-NEXT: call void @__cxx_global_var_init()
; CHECK-NEXT: call void @objc_autoreleasePoolPop(i8* %0)
; CHECK-NEXT: ret void
%0 = call i8* @objc_autoreleasePoolPush() nounwind
call void @__cxx_global_var_init()
call void @objc_autoreleasePoolPop(i8* %0) nounwind
ret void
}
define internal void @_GLOBAL__I_y() {
entry:
%0 = call i8* @objc_autoreleasePoolPush() nounwind
call void @__dxx_global_var_init()
call void @objc_autoreleasePoolPop(i8* %0) nounwind
ret void
}
declare i8* @objc_autoreleasePoolPush()
declare void @objc_autoreleasePoolPop(i8*)

View File

@ -0,0 +1,28 @@
; RUN: opt < %s -ipsccp -S | FileCheck %s
; See PR26774
define i32 @baz() {
ret i32 10
}
; We can const-prop @baz's return value *into* @foo, but cannot
; constprop @foo's return value into bar.
define linkonce_odr i32 @foo() {
; CHECK-LABEL: @foo(
; CHECK-NEXT: %val = call i32 @baz()
; CHECK-NEXT: ret i32 10
%val = call i32 @baz()
ret i32 %val
}
define i32 @bar() {
; CHECK-LABEL: @bar(
; CHECK-NEXT: %val = call i32 @foo()
; CHECK-NEXT: ret i32 %val
%val = call i32 @foo()
ret i32 %val
}

View File

@ -29,5 +29,5 @@ define available_externally void @f2() {
@test3_a = global i32 42
@test3_b = weak alias i32, i32* @test3_a
@test3_c = alias i32, i32* @test3_b
; CHECK: Alias cannot point to a weak alias
; CHECK: Alias cannot point to an interposable alias
; CHECK-NEXT: i32* @test3_c