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(); void destroyConstantImpl();
Value *handleOperandChangeImpl(Value *From, Value *To); 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: protected:
/// \brief The intrinsic ID for this subclass (which must be a Function). /// \brief The intrinsic ID for this subclass (which must be a Function).
/// ///
@ -242,14 +292,6 @@ public:
isAvailableExternallyLinkage(Linkage); 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: /// 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 /// Using this method outside of the code generators is almost always a
/// mistake: when working at the IR level use mayBeOverridden instead as it /// mistake: when working at the IR level use mayBeOverridden instead as it
@ -260,6 +302,52 @@ public:
Linkage == CommonLinkage || Linkage == ExternalWeakLinkage; 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 hasExternalLinkage() const { return isExternalLinkage(getLinkage()); }
bool hasAvailableExternallyLinkage() const { bool hasAvailableExternallyLinkage() const {
return isAvailableExternallyLinkage(getLinkage()); return isAvailableExternallyLinkage(getLinkage());
@ -291,8 +379,6 @@ public:
return isDiscardableIfUnused(getLinkage()); return isDiscardableIfUnused(getLinkage());
} }
bool mayBeOverridden() const { return mayBeOverridden(getLinkage()); }
bool isWeakForLinker() const { return isWeakForLinker(getLinkage()); } bool isWeakForLinker() const { return isWeakForLinker(getLinkage()); }
/// Copy all additional attributes (those not needed to create a GlobalValue) /// 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 /// Returns true if this global's definition will be the one chosen by the
/// linker. /// 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 { bool isStrongDefinitionForLinker() const {
return !(isDeclarationForLinker() || isWeakForLinker()); return !(isDeclarationForLinker() || isWeakForLinker());
} }

View File

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

View File

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

View File

@ -531,7 +531,7 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty,
return GV->getInitializer(); return GV->getInitializer();
if (auto *GA = dyn_cast<GlobalAlias>(C)) if (auto *GA = dyn_cast<GlobalAlias>(C))
if (GA->getAliasee() && !GA->mayBeOverridden()) if (GA->getAliasee() && !GA->isInterposable())
return ConstantFoldLoadFromConstPtr(GA->getAliasee(), Ty, DL); return ConstantFoldLoadFromConstPtr(GA->getAliasee(), Ty, DL);
// If the loaded value isn't a constant expr, we can't handle it. // 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; const std::vector<CallGraphNode *> &SCC = *I;
assert(!SCC.empty() && "SCC with no functions?"); assert(!SCC.empty() && "SCC with no functions?");
if (!SCC[0]->getFunction() || SCC[0]->getFunction()->mayBeOverridden()) { if (!SCC[0]->getFunction() || !SCC[0]->getFunction()->isDefinitionExact()) {
// Calls externally or is weak - can't say anything useful. Remove any existing // Calls externally or not exact - can't say anything useful. Remove any
// function records (may have been created when scanning globals). // existing function records (may have been created when scanning
// globals).
for (auto *Node : SCC) for (auto *Node : SCC)
FunctionInfos.erase(Node->getFunction()); FunctionInfos.erase(Node->getFunction());
continue; continue;
@ -699,7 +700,7 @@ bool GlobalsAAResult::isNonEscapingGlobalNoAlias(const GlobalValue *GV,
auto *InputGVar = dyn_cast<GlobalVariable>(InputGV); auto *InputGVar = dyn_cast<GlobalVariable>(InputGV);
if (GVar && InputGVar && if (GVar && InputGVar &&
!GVar->isDeclaration() && !InputGVar->isDeclaration() && !GVar->isDeclaration() && !InputGVar->isDeclaration() &&
!GVar->mayBeOverridden() && !InputGVar->mayBeOverridden()) { !GVar->isInterposable() && !InputGVar->isInterposable()) {
Type *GVType = GVar->getInitializer()->getType(); Type *GVType = GVar->getInitializer()->getType();
Type *InputGVType = InputGVar->getInitializer()->getType(); Type *InputGVType = InputGVar->getInitializer()->getType();
if (GVType->isSized() && InputGVType->isSized() && if (GVType->isSized() && InputGVType->isSized() &&

View File

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

View File

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

View File

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

View File

@ -4828,7 +4828,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) {
else if (isa<ConstantPointerNull>(V)) else if (isa<ConstantPointerNull>(V))
return getZero(V->getType()); return getZero(V->getType());
else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) 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)) else if (!isa<ConstantExpr>(V))
return getUnknown(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 // A weak GlobalAlias is totally unknown. A non-weak GlobalAlias has
// the bits of its aliasee. // the bits of its aliasee.
if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) { if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (!GA->mayBeOverridden()) if (!GA->isInterposable())
computeKnownBits(GA->getAliasee(), KnownZero, KnownOne, Depth + 1, Q); computeKnownBits(GA->getAliasee(), KnownZero, KnownOne, Depth + 1, Q);
return; return;
} }
@ -2640,7 +2640,7 @@ Value *llvm::GetPointerBaseWithConstantOffset(Value *Ptr, int64_t &Offset,
Operator::getOpcode(Ptr) == Instruction::AddrSpaceCast) { Operator::getOpcode(Ptr) == Instruction::AddrSpaceCast) {
Ptr = cast<Operator>(Ptr)->getOperand(0); Ptr = cast<Operator>(Ptr)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) { } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) {
if (GA->mayBeOverridden()) if (GA->isInterposable())
break; break;
Ptr = GA->getAliasee(); Ptr = GA->getAliasee();
} else { } else {
@ -2836,7 +2836,7 @@ Value *llvm::GetUnderlyingObject(Value *V, const DataLayout &DL,
Operator::getOpcode(V) == Instruction::AddrSpaceCast) { Operator::getOpcode(V) == Instruction::AddrSpaceCast) {
V = cast<Operator>(V)->getOperand(0); V = cast<Operator>(V)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) { } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(V)) {
if (GA->mayBeOverridden()) if (GA->isInterposable())
return V; return V;
V = GA->getAliasee(); V = GA->getAliasee();
} else { } else {

View File

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

View File

@ -626,7 +626,7 @@ void Verifier::visitAliaseeSubExpr(SmallPtrSetImpl<const GlobalAlias*> &Visited,
if (const auto *GA2 = dyn_cast<GlobalAlias>(GV)) { if (const auto *GA2 = dyn_cast<GlobalAlias>(GV)) {
Assert(Visited.insert(GA2).second, "Aliases cannot form a cycle", &GA); 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); &GA);
} else { } else {
// Only continue verifying subexpressions of GlobalAliases. // Only continue verifying subexpressions of GlobalAliases.

View File

@ -329,7 +329,7 @@ bool DAE::RemoveDeadArgumentsFromCallers(Function &Fn)
// %v = load i32 %p // %v = load i32 %p
// ret void // ret void
// } // }
if (!Fn.isStrongDefinitionForLinker()) if (!Fn.hasExactDefinition())
return false; return false;
// Functions with local linkage should already have been handled, except the // 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! // Already perfect!
return MAK_ReadNone; return MAK_ReadNone;
// Definitions with weak linkage may be overridden at linktime with // Non-exact function definitions may not be selected at link time, and an
// something that writes memory, so treat them like declarations. // alternative version that writes to memory may be selected. See the comment
if (F.isDeclaration() || F.mayBeOverridden()) { // on GlobalValue::isDefinitionExact for more details.
if (!F.hasExactDefinition()) {
if (AliasAnalysis::onlyReadsMemory(MRB)) if (AliasAnalysis::onlyReadsMemory(MRB))
return MAK_ReadOnly; return MAK_ReadOnly;
@ -284,8 +285,7 @@ struct ArgumentUsesTracker : public CaptureTracker {
} }
Function *F = CS.getCalledFunction(); Function *F = CS.getCalledFunction();
if (!F || F->isDeclaration() || F->mayBeOverridden() || if (!F || !F->hasExactDefinition() || !SCCNodes.count(F)) {
!SCCNodes.count(F)) {
Captured = true; Captured = true;
return true; return true;
} }
@ -490,9 +490,10 @@ static bool addArgumentAttrs(const SCCNodeSet &SCCNodes) {
// Check each function in turn, determining which pointer arguments are not // Check each function in turn, determining which pointer arguments are not
// captured. // captured.
for (Function *F : SCCNodes) { for (Function *F : SCCNodes) {
// Definitions with weak linkage may be overridden at linktime with // We can infer and propagate function attributes only when we know that the
// something that captures pointers, so treat them like declarations. // definition we'll get at link time is *exactly* the definition we see now.
if (F->isDeclaration() || F->mayBeOverridden()) // For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
continue; continue;
// Functions that are readonly (or readnone) and nounwind and don't return // 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)) if (F->doesNotAlias(0))
continue; continue;
// Definitions with weak linkage may be overridden at linktime, so // We can infer and propagate function attributes only when we know that the
// treat them like declarations. // definition we'll get at link time is *exactly* the definition we see now.
if (F->isDeclaration() || F->mayBeOverridden()) // For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
return false; return false;
// We annotate noalias return values, which are only applicable to // We annotate noalias return values, which are only applicable to
@ -859,9 +861,10 @@ static bool addNonNullAttrs(const SCCNodeSet &SCCNodes,
Attribute::NonNull)) Attribute::NonNull))
continue; continue;
// Definitions with weak linkage may be overridden at linktime, so // We can infer and propagate function attributes only when we know that the
// treat them like declarations. // definition we'll get at link time is *exactly* the definition we see now.
if (F->isDeclaration() || F->mayBeOverridden()) // For more details, see GlobalValue::mayBeDerefined.
if (!F->hasExactDefinition())
return false; return false;
// We annotate nonnull return values, which are only applicable to // 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 the aliasee may change at link time, nothing can be done - bail out.
if (J->mayBeOverridden()) if (J->isInterposable())
continue; continue;
Constant *Aliasee = J->getAliasee(); Constant *Aliasee = J->getAliasee();

View File

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

View File

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

View File

@ -93,7 +93,10 @@ bool PruneEH::runOnSCC(CallGraphSCC &SCC) {
if (!F) { if (!F) {
SCCMightUnwind = true; SCCMightUnwind = true;
SCCMightReturn = 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(); SCCMightUnwind |= !F->doesNotThrow();
SCCMightReturn |= !F->doesNotReturn(); SCCMightReturn |= !F->doesNotReturn();
} else { } else {

View File

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

View File

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

View File

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

View File

@ -1724,9 +1724,9 @@ bool IPSCCP::runOnModule(Module &M) {
if (F->isDeclaration()) if (F->isDeclaration())
continue; continue;
// If this is a strong or ODR definition of this function, then we can // If this is an exact definition of this function, then we can propagate
// propagate information about its result into callsites of it. // information about its result into callsites of it.
if (!F->mayBeOverridden()) if (F->hasExactDefinition())
Solver.AddTrackedFunction(&*F); Solver.AddTrackedFunction(&*F);
// If this function only has direct calls that we can see, we can track its // 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) { if (Operator::getOpcode(Ptr) == Instruction::BitCast) {
Ptr = cast<Operator>(Ptr)->getOperand(0); Ptr = cast<Operator>(Ptr)->getOperand(0);
} else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) { } else if (GlobalAlias *GA = dyn_cast<GlobalAlias>(Ptr)) {
if (GA->mayBeOverridden()) if (GA->isInterposable())
break; break;
Ptr = GA->getAliasee(); Ptr = GA->getAliasee();
} else { } else {

View File

@ -427,7 +427,7 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst,
// Resolve function pointers. // Resolve function pointers.
Function *Callee = dyn_cast<Function>(getVal(CS.getCalledValue())); Function *Callee = dyn_cast<Function>(getVal(CS.getCalledValue()));
if (!Callee || Callee->mayBeOverridden()) { if (!Callee || Callee->isInterposable()) {
DEBUG(dbgs() << "Can not resolve function pointer.\n"); DEBUG(dbgs() << "Can not resolve function pointer.\n");
return false; // Cannot resolve. 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_a = global i32 42
@test3_b = weak alias i32, i32* @test3_a @test3_b = weak alias i32, i32* @test3_a
@test3_c = alias i32, i32* @test3_b @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 ; CHECK-NEXT: i32* @test3_c