return AG.getAnalysis<AAManager>(F);
}
+ /// Return true if \p Arg is involved in a must-tail call, thus the argument
+ /// of the caller or callee.
+ bool isInvolvedInMustTailCall(const Argument &Arg) const {
+ return FunctionsCalledViaMustTail.count(Arg.getParent()) ||
+ FunctionsWithMustTailCall.count(Arg.getParent());
+ }
+
/// Return the analysis result from a pass \p AP for function \p F.
template <typename AP>
typename AP::Result *getAnalysisResultForFunction(const Function &F) {
/// A map from functions to their instructions that may read or write memory.
FuncRWInstsMapTy FuncRWInstsMap;
+ /// Functions called by a `musttail` call.
+ SmallPtrSet<Function *, 8> FunctionsCalledViaMustTail;
+
+ /// Functions containing a `musttail` call.
+ SmallPtrSet<Function *, 8> FunctionsWithMustTailCall;
+
/// The datalayout used in the module.
const DataLayout &DL;
static AttrBuilder getParameterABIAttributes(int I, AttributeList Attrs) {
static const Attribute::AttrKind ABIAttrs[] = {
- Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca,
- Attribute::InReg, Attribute::Returned, Attribute::SwiftSelf,
- Attribute::SwiftError};
+ Attribute::StructRet, Attribute::ByVal, Attribute::InAlloca,
+ Attribute::InReg, Attribute::SwiftSelf, Attribute::SwiftError};
AttrBuilder Copy;
for (auto AK : ABIAttrs) {
if (Attrs.hasParamAttribute(I, AK))
struct AAAlignArgument final
: AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AAAlign,
AAAlignImpl> {
- AAAlignArgument(const IRPosition &IRP)
- : AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AAAlign,
- AAAlignImpl>(
- IRP) {}
+ using Base =
+ AAArgumentFromCallSiteArgumentsAndMustBeExecutedContext<AAAlign,
+ AAAlignImpl>;
+ AAAlignArgument(const IRPosition &IRP) : Base(IRP) {}
+
+ /// See AbstractAttribute::manifest(...).
+ ChangeStatus manifest(Attributor &A) override {
+ // If the associated argument is involved in a must-tail call we give up
+ // because we would need to keep the argument alignments of caller and
+ // callee in-sync. Just does not seem worth the trouble right now.
+ if (A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))
+ return ChangeStatus::UNCHANGED;
+ return Base::manifest(A);
+ }
/// See AbstractAttribute::trackStatistics()
void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(aligned) }
/// See AbstractAttribute::manifest(...).
ChangeStatus manifest(Attributor &A) override {
+ // If the associated argument is involved in a must-tail call we give up
+ // because we would need to keep the argument alignments of caller and
+ // callee in-sync. Just does not seem worth the trouble right now.
+ if (Argument *Arg = getAssociatedArgument())
+ if (A.getInfoCache().isInvolvedInMustTailCall(*Arg))
+ return ChangeStatus::UNCHANGED;
ChangeStatus Changed = AAAlignImpl::manifest(A);
MaybeAlign InheritAlign =
getAssociatedValue().getPointerAlignment(A.getDataLayout());
"Attributor.");
break;
case Instruction::Call:
- // Calls are interesting but for `llvm.assume` calls we also fill the
- // KnowledgeMap as we find them.
+ // Calls are interesting on their own, additionally:
+ // For `llvm.assume` calls we also fill the KnowledgeMap as we find them.
+ // For `must-tail` calls we remember the caller and callee.
if (IntrinsicInst *Assume = dyn_cast<IntrinsicInst>(&I)) {
if (Assume->getIntrinsicID() == Intrinsic::assume)
fillMapFromAssume(*Assume, InfoCache.KnowledgeMap);
+ } else if (cast<CallInst>(I).isMustTailCall()) {
+ InfoCache.FunctionsWithMustTailCall.insert(&F);
+ InfoCache.FunctionsCalledViaMustTail.insert(
+ cast<CallInst>(I).getCalledFunction());
}
LLVM_FALLTHROUGH;
- case Instruction::Load:
- // The alignment of a pointer is interesting for loads.
- case Instruction::Store:
- // The alignment of a pointer is interesting for stores.
case Instruction::CallBr:
case Instruction::Invoke:
case Instruction::CleanupRet:
case Instruction::Br:
case Instruction::Resume:
case Instruction::Ret:
+ case Instruction::Load:
+ // The alignment of a pointer is interesting for loads.
+ case Instruction::Store:
+ // The alignment of a pointer is interesting for stores.
IsInterestingOpcode = true;
}
if (IsInterestingOpcode)
if (F.isDeclaration())
return;
+ // In non-module runs we need to look at the call sites of a function to
+ // determine if it is part of a must-tail call edge. This will influence what
+ // attributes we can derive.
+ if (!isModulePass() && !InfoCache.FunctionsCalledViaMustTail.count(&F))
+ for (const Use &U : F.uses())
+ if (ImmutableCallSite ICS = ImmutableCallSite(U.getUser()))
+ if (ICS.isCallee(&U) && ICS.isMustTailCall())
+ InfoCache.FunctionsCalledViaMustTail.insert(&F);
+
IRPosition FPos = IRPosition::function(F);
// Check for dead BasicBlocks in every function.