summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--llvm/include/llvm/IR/GlobalValue.h110
-rw-r--r--llvm/include/llvm/IR/GlobalVariable.h6
-rw-r--r--llvm/lib/Analysis/BasicAliasAnalysis.cpp2
-rw-r--r--llvm/lib/Analysis/ConstantFolding.cpp2
-rw-r--r--llvm/lib/Analysis/GlobalsModRef.cpp9
-rw-r--r--llvm/lib/Analysis/InlineCost.cpp11
-rw-r--r--llvm/lib/Analysis/InstructionSimplify.cpp2
-rw-r--r--llvm/lib/Analysis/Loads.cpp6
-rw-r--r--llvm/lib/Analysis/MemoryBuiltins.cpp2
-rw-r--r--llvm/lib/Analysis/ScalarEvolution.cpp2
-rw-r--r--llvm/lib/Analysis/ValueTracking.cpp6
-rw-r--r--llvm/lib/IR/Value.cpp2
-rw-r--r--llvm/lib/IR/Verifier.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/FunctionAttrs.cpp31
-rw-r--r--llvm/lib/Transforms/IPO/GlobalOpt.cpp2
-rw-r--r--llvm/lib/Transforms/IPO/IPConstantPropagation.cpp7
-rw-r--r--llvm/lib/Transforms/IPO/MergeFunctions.cpp16
-rw-r--r--llvm/lib/Transforms/IPO/PruneEH.cpp5
-rw-r--r--llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp2
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp2
-rw-r--r--llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp2
-rw-r--r--llvm/lib/Transforms/Scalar/SCCP.cpp6
-rw-r--r--llvm/lib/Transforms/Scalar/SROA.cpp2
-rw-r--r--llvm/lib/Transforms/Utils/Evaluator.cpp2
-rw-r--r--llvm/test/Analysis/GlobalsModRef/comdat-ipo.ll21
-rw-r--r--llvm/test/Transforms/FunctionAttrs/comdat-ipo.ll16
-rw-r--r--llvm/test/Transforms/IPConstantProp/comdat-ipo.ll28
-rw-r--r--llvm/test/Transforms/Inline/comdat-ipo.ll19
-rw-r--r--llvm/test/Transforms/ObjCARC/comdat-ipo.ll53
-rw-r--r--llvm/test/Transforms/SCCP/comdat-ipo.ll28
-rw-r--r--llvm/test/Verifier/alias.ll2
32 files changed, 336 insertions, 72 deletions
diff --git a/llvm/include/llvm/IR/GlobalValue.h b/llvm/include/llvm/IR/GlobalValue.h
index 14f42e18711..0d12fe86819 100644
--- a/llvm/include/llvm/IR/GlobalValue.h
+++ b/llvm/include/llvm/IR/GlobalValue.h
@@ -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());
}
diff --git a/llvm/include/llvm/IR/GlobalVariable.h b/llvm/include/llvm/IR/GlobalVariable.h
index 342bdc01bfb..fd08fe005ea 100644
--- a/llvm/include/llvm/IR/GlobalVariable.h
+++ b/llvm/include/llvm/IR/GlobalVariable.h
@@ -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();
diff --git a/llvm/lib/Analysis/BasicAliasAnalysis.cpp b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
index d8f6f109815..ee7d1497c57 100644
--- a/llvm/lib/Analysis/BasicAliasAnalysis.cpp
+++ b/llvm/lib/Analysis/BasicAliasAnalysis.cpp
@@ -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;
}
diff --git a/llvm/lib/Analysis/ConstantFolding.cpp b/llvm/lib/Analysis/ConstantFolding.cpp
index 0e1ca76af8f..017d897def7 100644
--- a/llvm/lib/Analysis/ConstantFolding.cpp
+++ b/llvm/lib/Analysis/ConstantFolding.cpp
@@ -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.
diff --git a/llvm/lib/Analysis/GlobalsModRef.cpp b/llvm/lib/Analysis/GlobalsModRef.cpp
index 3d2b0225735..0dc00789f0f 100644
--- a/llvm/lib/Analysis/GlobalsModRef.cpp
+++ b/llvm/lib/Analysis/GlobalsModRef.cpp
@@ -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() &&
diff --git a/llvm/lib/Analysis/InlineCost.cpp b/llvm/lib/Analysis/InlineCost.cpp
index b4138b2909c..ceab8331a11 100644
--- a/llvm/lib/Analysis/InlineCost.cpp
+++ b/llvm/lib/Analysis/InlineCost.cpp
@@ -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();
diff --git a/llvm/lib/Analysis/InstructionSimplify.cpp b/llvm/lib/Analysis/InstructionSimplify.cpp
index b67990aefda..80b92b50a74 100644
--- a/llvm/lib/Analysis/InstructionSimplify.cpp
+++ b/llvm/lib/Analysis/InstructionSimplify.cpp
@@ -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 {
diff --git a/llvm/lib/Analysis/Loads.cpp b/llvm/lib/Analysis/Loads.cpp
index 5004f2b8f0c..21503ef668b 100644
--- a/llvm/lib/Analysis/Loads.cpp
+++ b/llvm/lib/Analysis/Loads.cpp
@@ -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();
}
diff --git a/llvm/lib/Analysis/MemoryBuiltins.cpp b/llvm/lib/Analysis/MemoryBuiltins.cpp
index b181292d1aa..4391a7a3359 100644
--- a/llvm/lib/Analysis/MemoryBuiltins.cpp
+++ b/llvm/lib/Analysis/MemoryBuiltins.cpp
@@ -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());
}
diff --git a/llvm/lib/Analysis/ScalarEvolution.cpp b/llvm/lib/Analysis/ScalarEvolution.cpp
index 402a1b7c4ea..51e89659257 100644
--- a/llvm/lib/Analysis/ScalarEvolution.cpp
+++ b/llvm/lib/Analysis/ScalarEvolution.cpp
@@ -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);
diff --git a/llvm/lib/Analysis/ValueTracking.cpp b/llvm/lib/Analysis/ValueTracking.cpp
index 144ec63c931..6f8dc2c2937 100644
--- a/llvm/lib/Analysis/ValueTracking.cpp
+++ b/llvm/lib/Analysis/ValueTracking.cpp
@@ -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 {
diff --git a/llvm/lib/IR/Value.cpp b/llvm/lib/IR/Value.cpp
index 468b2a721a4..cc20c4855f2 100644
--- a/llvm/lib/IR/Value.cpp
+++ b/llvm/lib/IR/Value.cpp
@@ -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 {
diff --git a/llvm/lib/IR/Verifier.cpp b/llvm/lib/IR/Verifier.cpp
index b0c77a07d64..c0fb8fcbe07 100644
--- a/llvm/lib/IR/Verifier.cpp
+++ b/llvm/lib/IR/Verifier.cpp
@@ -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.
diff --git a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
index 2392a1ba5e8..d1da0f752ea 100644
--- a/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
+++ b/llvm/lib/Transforms/IPO/DeadArgumentElimination.cpp
@@ -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
diff --git a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
index b145771b40a..ec6062a51f0 100644
--- a/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
+++ b/llvm/lib/Transforms/IPO/FunctionAttrs.cpp
@@ -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
diff --git a/llvm/lib/Transforms/IPO/GlobalOpt.cpp b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
index e793d1b7d7b..5bae069b5d7 100644
--- a/llvm/lib/Transforms/IPO/GlobalOpt.cpp
+++ b/llvm/lib/Transforms/IPO/GlobalOpt.cpp
@@ -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();
diff --git a/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp b/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp
index af541d15525..060aac19efa 100644
--- a/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp
+++ b/llvm/lib/Transforms/IPO/IPConstantPropagation.cpp
@@ -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.
diff --git a/llvm/lib/Transforms/IPO/MergeFunctions.cpp b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
index 719603a38d8..d68c05010d7 100644
--- a/llvm/lib/Transforms/IPO/MergeFunctions.cpp
+++ b/llvm/lib/Transforms/IPO/MergeFunctions.cpp
@@ -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');
diff --git a/llvm/lib/Transforms/IPO/PruneEH.cpp b/llvm/lib/Transforms/IPO/PruneEH.cpp
index 22a95fa03f7..464b86cf47f 100644
--- a/llvm/lib/Transforms/IPO/PruneEH.cpp
+++ b/llvm/lib/Transforms/IPO/PruneEH.cpp
@@ -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 {
diff --git a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
index 48f258c86e7..d27f1071d67 100644
--- a/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
+++ b/llvm/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
@@ -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;
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
index 969e77c1f88..1bb0739f32a 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
@@ -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)
diff --git a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
index f276d667315..ef70d4c4392 100644
--- a/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
+++ b/llvm/lib/Transforms/ObjCARC/ObjCARCContract.cpp
@@ -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;
diff --git a/llvm/lib/Transforms/Scalar/SCCP.cpp b/llvm/lib/Transforms/Scalar/SCCP.cpp
index 80aace2c801..2242a2bcfb1 100644
--- a/llvm/lib/Transforms/Scalar/SCCP.cpp
+++ b/llvm/lib/Transforms/Scalar/SCCP.cpp
@@ -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
diff --git a/llvm/lib/Transforms/Scalar/SROA.cpp b/llvm/lib/Transforms/Scalar/SROA.cpp
index 42d3bd34725..3c42b7957c3 100644
--- a/llvm/lib/Transforms/Scalar/SROA.cpp
+++ b/llvm/lib/Transforms/Scalar/SROA.cpp
@@ -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 {
diff --git a/llvm/lib/Transforms/Utils/Evaluator.cpp b/llvm/lib/Transforms/Utils/Evaluator.cpp
index 47cf5ff5b80..cd130abf451 100644
--- a/llvm/lib/Transforms/Utils/Evaluator.cpp
+++ b/llvm/lib/Transforms/Utils/Evaluator.cpp
@@ -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.
}
diff --git a/llvm/test/Analysis/GlobalsModRef/comdat-ipo.ll b/llvm/test/Analysis/GlobalsModRef/comdat-ipo.ll
new file mode 100644
index 00000000000..a9cc821e7af
--- /dev/null
+++ b/llvm/test/Analysis/GlobalsModRef/comdat-ipo.ll
@@ -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
+}
diff --git a/llvm/test/Transforms/FunctionAttrs/comdat-ipo.ll b/llvm/test/Transforms/FunctionAttrs/comdat-ipo.ll
new file mode 100644
index 00000000000..e82d2fb9215
--- /dev/null
+++ b/llvm/test/Transforms/FunctionAttrs/comdat-ipo.ll
@@ -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
+}
diff --git a/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll b/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll
new file mode 100644
index 00000000000..6c4c44c33e2
--- /dev/null
+++ b/llvm/test/Transforms/IPConstantProp/comdat-ipo.ll
@@ -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
+}
diff --git a/llvm/test/Transforms/Inline/comdat-ipo.ll b/llvm/test/Transforms/Inline/comdat-ipo.ll
new file mode 100644
index 00000000000..8bdea0bdbe0
--- /dev/null
+++ b/llvm/test/Transforms/Inline/comdat-ipo.ll
@@ -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
+}
diff --git a/llvm/test/Transforms/ObjCARC/comdat-ipo.ll b/llvm/test/Transforms/ObjCARC/comdat-ipo.ll
new file mode 100644
index 00000000000..0a5713e9ab6
--- /dev/null
+++ b/llvm/test/Transforms/ObjCARC/comdat-ipo.ll
@@ -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*)
diff --git a/llvm/test/Transforms/SCCP/comdat-ipo.ll b/llvm/test/Transforms/SCCP/comdat-ipo.ll
new file mode 100644
index 00000000000..618075fd5e3
--- /dev/null
+++ b/llvm/test/Transforms/SCCP/comdat-ipo.ll
@@ -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
+}
diff --git a/llvm/test/Verifier/alias.ll b/llvm/test/Verifier/alias.ll
index 1847c0d4214..e14406550db 100644
--- a/llvm/test/Verifier/alias.ll
+++ b/llvm/test/Verifier/alias.ll
@@ -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
OpenPOWER on IntegriCloud