diff --git a/include/llvm/IR/GlobalValue.h b/include/llvm/IR/GlobalValue.h index 14f42e18711..0d12fe86819 100644 --- a/include/llvm/IR/GlobalValue.h +++ b/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/include/llvm/IR/GlobalVariable.h b/include/llvm/IR/GlobalVariable.h index 342bdc01bfb..fd08fe005ea 100644 --- a/include/llvm/IR/GlobalVariable.h +++ b/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/lib/Analysis/BasicAliasAnalysis.cpp b/lib/Analysis/BasicAliasAnalysis.cpp index d8f6f109815..ee7d1497c57 100644 --- a/lib/Analysis/BasicAliasAnalysis.cpp +++ b/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(V)) { - if (!GA->mayBeOverridden()) { + if (!GA->isInterposable()) { V = GA->getAliasee(); continue; } diff --git a/lib/Analysis/ConstantFolding.cpp b/lib/Analysis/ConstantFolding.cpp index 0e1ca76af8f..017d897def7 100644 --- a/lib/Analysis/ConstantFolding.cpp +++ b/lib/Analysis/ConstantFolding.cpp @@ -531,7 +531,7 @@ Constant *llvm::ConstantFoldLoadFromConstPtr(Constant *C, Type *Ty, return GV->getInitializer(); if (auto *GA = dyn_cast(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/lib/Analysis/GlobalsModRef.cpp b/lib/Analysis/GlobalsModRef.cpp index 3d2b0225735..0dc00789f0f 100644 --- a/lib/Analysis/GlobalsModRef.cpp +++ b/lib/Analysis/GlobalsModRef.cpp @@ -471,9 +471,10 @@ void GlobalsAAResult::AnalyzeCallGraph(CallGraph &CG, Module &M) { const std::vector &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(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/lib/Analysis/InlineCost.cpp b/lib/Analysis/InlineCost.cpp index b4138b2909c..ceab8331a11 100644 --- a/lib/Analysis/InlineCost.cpp +++ b/lib/Analysis/InlineCost.cpp @@ -1125,7 +1125,7 @@ ConstantInt *CallAnalyzer::stripAndComputeInBoundsConstantOffsets(Value *&V) { } else if (Operator::getOpcode(V) == Instruction::BitCast) { V = cast(V)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(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/lib/Analysis/InstructionSimplify.cpp b/lib/Analysis/InstructionSimplify.cpp index b67990aefda..80b92b50a74 100644 --- a/lib/Analysis/InstructionSimplify.cpp +++ b/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(V)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(V)) { - if (GA->mayBeOverridden()) + if (GA->isInterposable()) break; V = GA->getAliasee(); } else { diff --git a/lib/Analysis/Loads.cpp b/lib/Analysis/Loads.cpp index 5004f2b8f0c..21503ef668b 100644 --- a/lib/Analysis/Loads.cpp +++ b/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(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/lib/Analysis/MemoryBuiltins.cpp b/lib/Analysis/MemoryBuiltins.cpp index b181292d1aa..4391a7a3359 100644 --- a/lib/Analysis/MemoryBuiltins.cpp +++ b/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/lib/Analysis/ScalarEvolution.cpp b/lib/Analysis/ScalarEvolution.cpp index 402a1b7c4ea..51e89659257 100644 --- a/lib/Analysis/ScalarEvolution.cpp +++ b/lib/Analysis/ScalarEvolution.cpp @@ -4828,7 +4828,7 @@ const SCEV *ScalarEvolution::createSCEV(Value *V) { else if (isa(V)) return getZero(V->getType()); else if (GlobalAlias *GA = dyn_cast(V)) - return GA->mayBeOverridden() ? getUnknown(V) : getSCEV(GA->getAliasee()); + return GA->isInterposable() ? getUnknown(V) : getSCEV(GA->getAliasee()); else if (!isa(V)) return getUnknown(V); diff --git a/lib/Analysis/ValueTracking.cpp b/lib/Analysis/ValueTracking.cpp index 144ec63c931..6f8dc2c2937 100644 --- a/lib/Analysis/ValueTracking.cpp +++ b/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(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(Ptr)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(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(V)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(V)) { - if (GA->mayBeOverridden()) + if (GA->isInterposable()) return V; V = GA->getAliasee(); } else { diff --git a/lib/IR/Value.cpp b/lib/IR/Value.cpp index 468b2a721a4..cc20c4855f2 100644 --- a/lib/IR/Value.cpp +++ b/lib/IR/Value.cpp @@ -460,7 +460,7 @@ static Value *stripPointerCastsAndOffsets(Value *V) { Operator::getOpcode(V) == Instruction::AddrSpaceCast) { V = cast(V)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(V)) { - if (StripKind == PSK_ZeroIndices || GA->mayBeOverridden()) + if (StripKind == PSK_ZeroIndices || GA->isInterposable()) return V; V = GA->getAliasee(); } else { diff --git a/lib/IR/Verifier.cpp b/lib/IR/Verifier.cpp index b0c77a07d64..c0fb8fcbe07 100644 --- a/lib/IR/Verifier.cpp +++ b/lib/IR/Verifier.cpp @@ -626,7 +626,7 @@ void Verifier::visitAliaseeSubExpr(SmallPtrSetImpl &Visited, if (const auto *GA2 = dyn_cast(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/lib/Transforms/IPO/DeadArgumentElimination.cpp b/lib/Transforms/IPO/DeadArgumentElimination.cpp index 2392a1ba5e8..d1da0f752ea 100644 --- a/lib/Transforms/IPO/DeadArgumentElimination.cpp +++ b/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/lib/Transforms/IPO/FunctionAttrs.cpp b/lib/Transforms/IPO/FunctionAttrs.cpp index b145771b40a..ec6062a51f0 100644 --- a/lib/Transforms/IPO/FunctionAttrs.cpp +++ b/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/lib/Transforms/IPO/GlobalOpt.cpp b/lib/Transforms/IPO/GlobalOpt.cpp index e793d1b7d7b..5bae069b5d7 100644 --- a/lib/Transforms/IPO/GlobalOpt.cpp +++ b/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/lib/Transforms/IPO/IPConstantPropagation.cpp b/lib/Transforms/IPO/IPConstantPropagation.cpp index af541d15525..060aac19efa 100644 --- a/lib/Transforms/IPO/IPConstantPropagation.cpp +++ b/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/lib/Transforms/IPO/MergeFunctions.cpp b/lib/Transforms/IPO/MergeFunctions.cpp index 719603a38d8..d68c05010d7 100644 --- a/lib/Transforms/IPO/MergeFunctions.cpp +++ b/lib/Transforms/IPO/MergeFunctions.cpp @@ -1572,7 +1572,7 @@ bool MergeFunctions::runOnModule(Module &M) { if (!*I) continue; Function *F = cast(*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(*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/lib/Transforms/IPO/PruneEH.cpp b/lib/Transforms/IPO/PruneEH.cpp index 22a95fa03f7..464b86cf47f 100644 --- a/lib/Transforms/IPO/PruneEH.cpp +++ b/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/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp index 48f258c86e7..d27f1071d67 100644 --- a/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp +++ b/lib/Transforms/InstCombine/InstCombineLoadStoreAlloca.cpp @@ -640,7 +640,7 @@ static bool isObjectSizeLessThanOrEq(Value *V, uint64_t MaxSize, } if (GlobalAlias *GA = dyn_cast(P)) { - if (GA->mayBeOverridden()) + if (!GA->isInterposable()) return false; Worklist.push_back(GA->getAliasee()); continue; diff --git a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp b/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp index 969e77c1f88..1bb0739f32a 100644 --- a/lib/Transforms/ObjCARC/ObjCARCAPElim.cpp +++ b/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/lib/Transforms/ObjCARC/ObjCARCContract.cpp b/lib/Transforms/ObjCARC/ObjCARCContract.cpp index f276d667315..ef70d4c4392 100644 --- a/lib/Transforms/ObjCARC/ObjCARCContract.cpp +++ b/lib/Transforms/ObjCARC/ObjCARCContract.cpp @@ -605,7 +605,7 @@ bool ObjCARCContract::runOnFunction(Function &F) { cast(Arg)->hasAllZeroIndices()) Arg = cast(Arg)->getPointerOperand(); else if (isa(Arg) && - !cast(Arg)->mayBeOverridden()) + !cast(Arg)->isInterposable()) Arg = cast(Arg)->getAliasee(); else break; diff --git a/lib/Transforms/Scalar/SCCP.cpp b/lib/Transforms/Scalar/SCCP.cpp index 80aace2c801..2242a2bcfb1 100644 --- a/lib/Transforms/Scalar/SCCP.cpp +++ b/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/lib/Transforms/Scalar/SROA.cpp b/lib/Transforms/Scalar/SROA.cpp index 42d3bd34725..3c42b7957c3 100644 --- a/lib/Transforms/Scalar/SROA.cpp +++ b/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(Ptr)->getOperand(0); } else if (GlobalAlias *GA = dyn_cast(Ptr)) { - if (GA->mayBeOverridden()) + if (GA->isInterposable()) break; Ptr = GA->getAliasee(); } else { diff --git a/lib/Transforms/Utils/Evaluator.cpp b/lib/Transforms/Utils/Evaluator.cpp index 47cf5ff5b80..cd130abf451 100644 --- a/lib/Transforms/Utils/Evaluator.cpp +++ b/lib/Transforms/Utils/Evaluator.cpp @@ -427,7 +427,7 @@ bool Evaluator::EvaluateBlock(BasicBlock::iterator CurInst, // Resolve function pointers. Function *Callee = dyn_cast(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/test/Analysis/GlobalsModRef/comdat-ipo.ll b/test/Analysis/GlobalsModRef/comdat-ipo.ll new file mode 100644 index 00000000000..a9cc821e7af --- /dev/null +++ b/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/test/Transforms/FunctionAttrs/comdat-ipo.ll b/test/Transforms/FunctionAttrs/comdat-ipo.ll new file mode 100644 index 00000000000..e82d2fb9215 --- /dev/null +++ b/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/test/Transforms/IPConstantProp/comdat-ipo.ll b/test/Transforms/IPConstantProp/comdat-ipo.ll new file mode 100644 index 00000000000..6c4c44c33e2 --- /dev/null +++ b/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/test/Transforms/Inline/comdat-ipo.ll b/test/Transforms/Inline/comdat-ipo.ll new file mode 100644 index 00000000000..8bdea0bdbe0 --- /dev/null +++ b/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/test/Transforms/ObjCARC/comdat-ipo.ll b/test/Transforms/ObjCARC/comdat-ipo.ll new file mode 100644 index 00000000000..0a5713e9ab6 --- /dev/null +++ b/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/test/Transforms/SCCP/comdat-ipo.ll b/test/Transforms/SCCP/comdat-ipo.ll new file mode 100644 index 00000000000..618075fd5e3 --- /dev/null +++ b/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/test/Verifier/alias.ll b/test/Verifier/alias.ll index 1847c0d4214..e14406550db 100644 --- a/test/Verifier/alias.ll +++ b/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