mirror of
https://github.com/RPCS3/llvm.git
synced 2024-11-28 14:10:55 +00:00
Don't IPO over functions that can be de-refined
Summary: Fixes PR26774. If you're aware of the issue, feel free to skip the "Motivation" section and jump directly to "This patch". Motivation: I define "refinement" as discarding behaviors from a program that the optimizer has license to discard. So transforming: ``` void f(unsigned x) { unsigned t = 5 / x; (void)t; } ``` to ``` void f(unsigned x) { } ``` is refinement, since the behavior went from "if x == 0 then undefined else nothing" to "nothing" (the optimizer has license to discard undefined behavior). Refinement is a fundamental aspect of many mid-level optimizations done by LLVM. For instance, transforming `x == (x + 1)` to `false` also involves refinement since the expression's value went from "if x is `undef` then { `true` or `false` } else { `false` }" to "`false`" (by definition, the optimizer has license to fold `undef` to any non-`undef` value). Unfortunately, refinement implies that the optimizer cannot assume that the implementation of a function it can see has all of the behavior an unoptimized or a differently optimized version of the same function can have. This is a problem for functions with comdat linkage, where a function can be replaced by an unoptimized or a differently optimized version of the same source level function. For instance, FunctionAttrs cannot assume a comdat function is actually `readnone` even if it does not have any loads or stores in it; since there may have been loads and stores in the "original function" that were refined out in the currently visible variant, and at the link step the linker may in fact choose an implementation with a load or a store. As an example, consider a function that does two atomic loads from the same memory location, and writes to memory only if the two values are not equal. The optimizer is allowed to refine this function by first CSE'ing the two loads, and the folding the comparision to always report that the two values are equal. Such a refined variant will look like it is `readonly`. However, the unoptimized version of the function can still write to memory (since the two loads //can// result in different values), and selecting the unoptimized version at link time will retroactively invalidate transforms we may have done under the assumption that the function does not write to memory. Note: this is not just a problem with atomics or with linking differently optimized object files. See PR26774 for more realistic examples that involved neither. This patch: This change introduces a new set of linkage types, predicated as `GlobalValue::mayBeDerefined` that returns true if the linkage type allows a function to be replaced by a differently optimized variant at link time. It then changes a set of IPO passes to bail out if they see such a function. Reviewers: chandlerc, hfinkel, dexonsmith, joker.eph, rnk Subscribers: mcrosier, llvm-commits Differential Revision: http://reviews.llvm.org/D18634 git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@265762 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
parent
86c8abfe54
commit
c9e3e3cbfd
@ -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());
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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.
|
||||
|
@ -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() &&
|
||||
|
@ -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();
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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();
|
||||
}
|
||||
|
@ -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());
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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 {
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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();
|
||||
|
@ -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.
|
||||
|
@ -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');
|
||||
|
@ -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 {
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
|
@ -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 {
|
||||
|
@ -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.
|
||||
}
|
||||
|
21
test/Analysis/GlobalsModRef/comdat-ipo.ll
Normal file
21
test/Analysis/GlobalsModRef/comdat-ipo.ll
Normal file
@ -0,0 +1,21 @@
|
||||
; RUN: opt < %s -basicaa -globals-aa -gvn -S | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
@X = internal global i32 4
|
||||
|
||||
define i32 @test(i32* %P) {
|
||||
; CHECK: @test
|
||||
; CHECK-NEXT: store i32 12, i32* @X
|
||||
; CHECK-NEXT: call void @doesnotmodX()
|
||||
; CHECK-NEXT: %V = load i32, i32* @X
|
||||
; CHECK-NEXT: ret i32 %V
|
||||
store i32 12, i32* @X
|
||||
call void @doesnotmodX( )
|
||||
%V = load i32, i32* @X
|
||||
ret i32 %V
|
||||
}
|
||||
|
||||
define linkonce_odr void @doesnotmodX() {
|
||||
ret void
|
||||
}
|
16
test/Transforms/FunctionAttrs/comdat-ipo.ll
Normal file
16
test/Transforms/FunctionAttrs/comdat-ipo.ll
Normal file
@ -0,0 +1,16 @@
|
||||
; RUN: opt < %s -functionattrs -S | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
; CHECK-LABEL: define void @bar(i8* readonly) {
|
||||
define void @bar(i8* readonly) {
|
||||
call void @foo(i8* %0)
|
||||
ret void
|
||||
}
|
||||
|
||||
|
||||
; CHECK-LABEL: define linkonce_odr void @foo(i8* readonly) {
|
||||
define linkonce_odr void @foo(i8* readonly) {
|
||||
call void @bar(i8* %0)
|
||||
ret void
|
||||
}
|
28
test/Transforms/IPConstantProp/comdat-ipo.ll
Normal file
28
test/Transforms/IPConstantProp/comdat-ipo.ll
Normal file
@ -0,0 +1,28 @@
|
||||
; RUN: opt < %s -ipconstprop -S | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
define i32 @baz() {
|
||||
ret i32 10
|
||||
}
|
||||
|
||||
; We can const-prop @baz's return value *into* @foo, but cannot
|
||||
; constprop @foo's return value into bar.
|
||||
|
||||
define linkonce_odr i32 @foo() {
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK-NEXT: %val = call i32 @baz()
|
||||
; CHECK-NEXT: ret i32 10
|
||||
|
||||
%val = call i32 @baz()
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define i32 @bar() {
|
||||
; CHECK-LABEL: @bar(
|
||||
; CHECK-NEXT: %val = call i32 @foo()
|
||||
; CHECK-NEXT: ret i32 %val
|
||||
|
||||
%val = call i32 @foo()
|
||||
ret i32 %val
|
||||
}
|
19
test/Transforms/Inline/comdat-ipo.ll
Normal file
19
test/Transforms/Inline/comdat-ipo.ll
Normal file
@ -0,0 +1,19 @@
|
||||
; RUN: opt -inline -S < %s | FileCheck %s
|
||||
|
||||
define i32 @caller() {
|
||||
; CHECK-LABEL: @caller(
|
||||
; CHECK-NEXT: %val2 = call i32 @linkonce_callee(i32 42)
|
||||
; CHECK-NEXT: ret i32 %val2
|
||||
|
||||
%val = call i32 @odr_callee()
|
||||
%val2 = call i32 @linkonce_callee(i32 %val);
|
||||
ret i32 %val2
|
||||
}
|
||||
|
||||
define linkonce_odr i32 @odr_callee() {
|
||||
ret i32 42
|
||||
}
|
||||
|
||||
define linkonce i32 @linkonce_callee(i32 %val) {
|
||||
ret i32 %val
|
||||
}
|
53
test/Transforms/ObjCARC/comdat-ipo.ll
Normal file
53
test/Transforms/ObjCARC/comdat-ipo.ll
Normal file
@ -0,0 +1,53 @@
|
||||
; RUN: opt -S -objc-arc-apelim < %s | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
@llvm.global_ctors = appending global [2 x { i32, void ()* }] [{ i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_x }, { i32, void ()* } { i32 65535, void ()* @_GLOBAL__I_y }]
|
||||
|
||||
@x = global i32 0
|
||||
|
||||
declare i32 @bar() nounwind
|
||||
|
||||
define linkonce_odr i32 @foo() nounwind {
|
||||
entry:
|
||||
ret i32 5
|
||||
}
|
||||
|
||||
define internal void @__cxx_global_var_init() {
|
||||
entry:
|
||||
%call = call i32 @foo()
|
||||
store i32 %call, i32* @x, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @__dxx_global_var_init() {
|
||||
entry:
|
||||
%call = call i32 @bar()
|
||||
store i32 %call, i32* @x, align 4
|
||||
ret void
|
||||
}
|
||||
|
||||
; CHECK-LABEL: define internal void @_GLOBAL__I_x() {
|
||||
define internal void @_GLOBAL__I_x() {
|
||||
entry:
|
||||
; CHECK: call i8* @objc_autoreleasePoolPush()
|
||||
; CHECK-NEXT: call void @__cxx_global_var_init()
|
||||
; CHECK-NEXT: call void @objc_autoreleasePoolPop(i8* %0)
|
||||
; CHECK-NEXT: ret void
|
||||
|
||||
%0 = call i8* @objc_autoreleasePoolPush() nounwind
|
||||
call void @__cxx_global_var_init()
|
||||
call void @objc_autoreleasePoolPop(i8* %0) nounwind
|
||||
ret void
|
||||
}
|
||||
|
||||
define internal void @_GLOBAL__I_y() {
|
||||
entry:
|
||||
%0 = call i8* @objc_autoreleasePoolPush() nounwind
|
||||
call void @__dxx_global_var_init()
|
||||
call void @objc_autoreleasePoolPop(i8* %0) nounwind
|
||||
ret void
|
||||
}
|
||||
|
||||
declare i8* @objc_autoreleasePoolPush()
|
||||
declare void @objc_autoreleasePoolPop(i8*)
|
28
test/Transforms/SCCP/comdat-ipo.ll
Normal file
28
test/Transforms/SCCP/comdat-ipo.ll
Normal file
@ -0,0 +1,28 @@
|
||||
; RUN: opt < %s -ipsccp -S | FileCheck %s
|
||||
|
||||
; See PR26774
|
||||
|
||||
define i32 @baz() {
|
||||
ret i32 10
|
||||
}
|
||||
|
||||
; We can const-prop @baz's return value *into* @foo, but cannot
|
||||
; constprop @foo's return value into bar.
|
||||
|
||||
define linkonce_odr i32 @foo() {
|
||||
; CHECK-LABEL: @foo(
|
||||
; CHECK-NEXT: %val = call i32 @baz()
|
||||
; CHECK-NEXT: ret i32 10
|
||||
|
||||
%val = call i32 @baz()
|
||||
ret i32 %val
|
||||
}
|
||||
|
||||
define i32 @bar() {
|
||||
; CHECK-LABEL: @bar(
|
||||
; CHECK-NEXT: %val = call i32 @foo()
|
||||
; CHECK-NEXT: ret i32 %val
|
||||
|
||||
%val = call i32 @foo()
|
||||
ret i32 %val
|
||||
}
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user