[llvm] r265762 - Don't IPO over functions that can be de-refined
Benjamin Kramer via llvm-commits
llvm-commits at lists.llvm.org
Fri Apr 8 06:08:44 PDT 2016
I'm seeing "missed optimization" fallout from this.
$ cat foo.cc
inline void foo(const char *, ...) {}
int main() {
foo("bar");
}
$ clang-old -S -o - log.cc -O2|grep -c bar
0
$ clang-new -S -o - log.cc -O2|grep -c bar
1
Is this something we want to fix or is that how it's supposed to work
now. GCC happily discards foo() here.
On Fri, Apr 8, 2016 at 2:48 AM, Sanjoy Das via llvm-commits
<llvm-commits at lists.llvm.org> wrote:
> Author: sanjoy
> Date: Thu Apr 7 19:48:30 2016
> New Revision: 265762
>
> URL: http://llvm.org/viewvc/llvm-project?rev=265762&view=rev
> Log:
> 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
>
> Added:
> llvm/trunk/test/Analysis/GlobalsModRef/comdat-ipo.ll
> llvm/trunk/test/Transforms/FunctionAttrs/comdat-ipo.ll
> llvm/trunk/test/Transforms/IPConstantProp/comdat-ipo.ll
> llvm/trunk/test/Transforms/Inline/comdat-ipo.ll
> llvm/trunk/test/Transforms/ObjCARC/comdat-ipo.ll
> llvm/trunk/test/Transforms/SCCP/comdat-ipo.ll
> Modified:
> llvm/trunk/include/llvm/IR/GlobalValue.h
> llvm/trunk/include/llvm/IR/GlobalVariable.h
> llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
> llvm/trunk/lib/Analysis/ConstantFolding.cpp
> llvm/trunk/lib/Analysis/GlobalsModRef.cpp
> llvm/trunk/lib/Analysis/InlineCost.cpp
> llvm/trunk/lib/Analysis/InstructionSimplify.cpp
> llvm/trunk/lib/Analysis/Loads.cpp
> llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
> llvm/trunk/lib/Analysis/ScalarEvolution.cpp
> llvm/trunk/lib/Analysis/ValueTracking.cpp
> llvm/trunk/lib/IR/Value.cpp
> llvm/trunk/lib/IR/Verifier.cpp
> llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp
> llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
> llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp
> llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp
> llvm/trunk/lib/Transforms/IPO/PruneEH.cpp
> llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
> llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
> llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
> llvm/trunk/lib/Transforms/Scalar/SROA.cpp
> llvm/trunk/lib/Transforms/Utils/Evaluator.cpp
> llvm/trunk/test/Verifier/alias.ll
>
> Modified: llvm/trunk/include/llvm/IR/GlobalValue.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/GlobalValue.h?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/GlobalValue.h (original)
> +++ llvm/trunk/include/llvm/IR/GlobalValue.h Thu Apr 7 19:48:30 2016
> @@ -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());
> }
>
> Modified: llvm/trunk/include/llvm/IR/GlobalVariable.h
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/IR/GlobalVariable.h?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/include/llvm/IR/GlobalVariable.h (original)
> +++ llvm/trunk/include/llvm/IR/GlobalVariable.h Thu Apr 7 19:48:30 2016
> @@ -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();
>
> Modified: llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp (original)
> +++ llvm/trunk/lib/Analysis/BasicAliasAnalysis.cpp Thu Apr 7 19:48:30 2016
> @@ -359,7 +359,7 @@ static int64_t adjustToPointerSize(int64
> 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;
> }
>
> Modified: llvm/trunk/lib/Analysis/ConstantFolding.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ConstantFolding.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/ConstantFolding.cpp (original)
> +++ llvm/trunk/lib/Analysis/ConstantFolding.cpp Thu Apr 7 19:48:30 2016
> @@ -531,7 +531,7 @@ Constant *llvm::ConstantFoldLoadFromCons
> 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.
>
> Modified: llvm/trunk/lib/Analysis/GlobalsModRef.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/GlobalsModRef.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/GlobalsModRef.cpp (original)
> +++ llvm/trunk/lib/Analysis/GlobalsModRef.cpp Thu Apr 7 19:48:30 2016
> @@ -471,9 +471,10 @@ void GlobalsAAResult::AnalyzeCallGraph(C
> 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::isNonEscapingGloba
> 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() &&
>
> Modified: llvm/trunk/lib/Analysis/InlineCost.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InlineCost.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/InlineCost.cpp (original)
> +++ llvm/trunk/lib/Analysis/InlineCost.cpp Thu Apr 7 19:48:30 2016
> @@ -1125,7 +1125,7 @@ ConstantInt *CallAnalyzer::stripAndCompu
> } 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
> 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();
>
>
> Modified: llvm/trunk/lib/Analysis/InstructionSimplify.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/InstructionSimplify.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/InstructionSimplify.cpp (original)
> +++ llvm/trunk/lib/Analysis/InstructionSimplify.cpp Thu Apr 7 19:48:30 2016
> @@ -616,7 +616,7 @@ static Constant *stripAndComputeConstant
> } 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 {
>
> Modified: llvm/trunk/lib/Analysis/Loads.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/Loads.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/Loads.cpp (original)
> +++ llvm/trunk/lib/Analysis/Loads.cpp Thu Apr 7 19:48:30 2016
> @@ -299,9 +299,9 @@ bool llvm::isSafeToLoadUnconditionally(V
> 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();
> }
>
> Modified: llvm/trunk/lib/Analysis/MemoryBuiltins.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/MemoryBuiltins.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/MemoryBuiltins.cpp (original)
> +++ llvm/trunk/lib/Analysis/MemoryBuiltins.cpp Thu Apr 7 19:48:30 2016
> @@ -529,7 +529,7 @@ SizeOffsetType ObjectSizeOffsetVisitor::
> }
>
> SizeOffsetType ObjectSizeOffsetVisitor::visitGlobalAlias(GlobalAlias &GA) {
> - if (GA.mayBeOverridden())
> + if (GA.isInterposable())
> return unknown();
> return compute(GA.getAliasee());
> }
>
> Modified: llvm/trunk/lib/Analysis/ScalarEvolution.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ScalarEvolution.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/ScalarEvolution.cpp (original)
> +++ llvm/trunk/lib/Analysis/ScalarEvolution.cpp Thu Apr 7 19:48:30 2016
> @@ -4828,7 +4828,7 @@ const SCEV *ScalarEvolution::createSCEV(
> 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);
>
>
> Modified: llvm/trunk/lib/Analysis/ValueTracking.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Analysis/ValueTracking.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Analysis/ValueTracking.cpp (original)
> +++ llvm/trunk/lib/Analysis/ValueTracking.cpp Thu Apr 7 19:48:30 2016
> @@ -1450,7 +1450,7 @@ void computeKnownBits(Value *V, APInt &K
> // 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::GetPointerBaseWithConstantO
> 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 *
> 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 {
>
> Modified: llvm/trunk/lib/IR/Value.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Value.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/Value.cpp (original)
> +++ llvm/trunk/lib/IR/Value.cpp Thu Apr 7 19:48:30 2016
> @@ -460,7 +460,7 @@ static Value *stripPointerCastsAndOffset
> 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 {
>
> Modified: llvm/trunk/lib/IR/Verifier.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/IR/Verifier.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/IR/Verifier.cpp (original)
> +++ llvm/trunk/lib/IR/Verifier.cpp Thu Apr 7 19:48:30 2016
> @@ -626,7 +626,7 @@ void Verifier::visitAliaseeSubExpr(Small
> 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.
>
> Modified: llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/DeadArgumentElimination.cpp Thu Apr 7 19:48:30 2016
> @@ -329,7 +329,7 @@ bool DAE::RemoveDeadArgumentsFromCallers
> // %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
>
> Modified: llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/FunctionAttrs.cpp Thu Apr 7 19:48:30 2016
> @@ -69,9 +69,10 @@ static MemoryAccessKind checkFunctionMem
> // 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 Capt
> }
>
> 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 SCCNo
> // 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 SCCNod
> 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 SCCNod
> 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
>
> Modified: llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/GlobalOpt.cpp Thu Apr 7 19:48:30 2016
> @@ -2366,7 +2366,7 @@ bool GlobalOpt::OptimizeGlobalAliases(Mo
> }
>
> // 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();
>
> Modified: llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/IPConstantPropagation.cpp Thu Apr 7 19:48:30 2016
> @@ -161,9 +161,10 @@ bool IPCP::PropagateConstantReturn(Funct
> 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.
>
> Modified: llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/MergeFunctions.cpp Thu Apr 7 19:48:30 2016
> @@ -1572,7 +1572,7 @@ bool MergeFunctions::runOnModule(Module
> 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
> 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<> &Bu
> // 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
>
> // 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 *Ne
> //
> // 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 *Ne
> }
>
> // 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');
>
> Modified: llvm/trunk/lib/Transforms/IPO/PruneEH.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/IPO/PruneEH.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/IPO/PruneEH.cpp (original)
> +++ llvm/trunk/lib/Transforms/IPO/PruneEH.cpp Thu Apr 7 19:48:30 2016
> @@ -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 {
>
> Modified: llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp (original)
> +++ llvm/trunk/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp Thu Apr 7 19:48:30 2016
> @@ -640,7 +640,7 @@ static bool isObjectSizeLessThanOrEq(Val
> }
>
> if (GlobalAlias *GA = dyn_cast<GlobalAlias>(P)) {
> - if (GA->mayBeOverridden())
> + if (!GA->isInterposable())
> return false;
> Worklist.push_back(GA->getAliasee());
> continue;
>
> Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp (original)
> +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp Thu Apr 7 19:48:30 2016
> @@ -70,7 +70,7 @@ void ObjCARCAPElim::getAnalysisUsage(Ana
> /// 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)
>
> Modified: llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp (original)
> +++ llvm/trunk/lib/Transforms/ObjCARC/ObjCARCContract.cpp Thu Apr 7 19:48:30 2016
> @@ -605,7 +605,7 @@ bool ObjCARCContract::runOnFunction(Func
> 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;
>
> Modified: llvm/trunk/lib/Transforms/Scalar/SCCP.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SCCP.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/SCCP.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/SCCP.cpp Thu Apr 7 19:48:30 2016
> @@ -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
>
> Modified: llvm/trunk/lib/Transforms/Scalar/SROA.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Scalar/SROA.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Scalar/SROA.cpp (original)
> +++ llvm/trunk/lib/Transforms/Scalar/SROA.cpp Thu Apr 7 19:48:30 2016
> @@ -1549,7 +1549,7 @@ static Value *getAdjustedPtr(IRBuilderTy
> 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 {
>
> Modified: llvm/trunk/lib/Transforms/Utils/Evaluator.cpp
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Transforms/Utils/Evaluator.cpp?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/lib/Transforms/Utils/Evaluator.cpp (original)
> +++ llvm/trunk/lib/Transforms/Utils/Evaluator.cpp Thu Apr 7 19:48:30 2016
> @@ -427,7 +427,7 @@ bool Evaluator::EvaluateBlock(BasicBlock
>
> // 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.
> }
>
> Added: llvm/trunk/test/Analysis/GlobalsModRef/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Analysis/GlobalsModRef/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Analysis/GlobalsModRef/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Analysis/GlobalsModRef/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -0,0 +1,21 @@
> +; RUN: opt < %s -basicaa -globals-aa -gvn -S | FileCheck %s
> +
> +; See PR26774
> +
> + at 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
> +}
>
> Added: llvm/trunk/test/Transforms/FunctionAttrs/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/FunctionAttrs/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/FunctionAttrs/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Transforms/FunctionAttrs/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -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
> +}
>
> Added: llvm/trunk/test/Transforms/IPConstantProp/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/IPConstantProp/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/IPConstantProp/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Transforms/IPConstantProp/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -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
> +}
>
> Added: llvm/trunk/test/Transforms/Inline/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/Inline/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/Inline/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Transforms/Inline/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -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
> +}
>
> Added: llvm/trunk/test/Transforms/ObjCARC/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/ObjCARC/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/ObjCARC/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Transforms/ObjCARC/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -0,0 +1,53 @@
> +; RUN: opt -S -objc-arc-apelim < %s | FileCheck %s
> +
> +; See PR26774
> +
> + at 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 }]
> +
> + at 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*)
>
> Added: llvm/trunk/test/Transforms/SCCP/comdat-ipo.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Transforms/SCCP/comdat-ipo.ll?rev=265762&view=auto
> ==============================================================================
> --- llvm/trunk/test/Transforms/SCCP/comdat-ipo.ll (added)
> +++ llvm/trunk/test/Transforms/SCCP/comdat-ipo.ll Thu Apr 7 19:48:30 2016
> @@ -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
> +}
>
> Modified: llvm/trunk/test/Verifier/alias.ll
> URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Verifier/alias.ll?rev=265762&r1=265761&r2=265762&view=diff
> ==============================================================================
> --- llvm/trunk/test/Verifier/alias.ll (original)
> +++ llvm/trunk/test/Verifier/alias.ll Thu Apr 7 19:48:30 2016
> @@ -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
>
>
> _______________________________________________
> llvm-commits mailing list
> llvm-commits at lists.llvm.org
> http://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-commits
More information about the llvm-commits
mailing list