|  | //===- Attributor.cpp - Module-wide attribute deduction -------------------===// | 
|  | // | 
|  | // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. | 
|  | // See https://llvm.org/LICENSE.txt for license information. | 
|  | // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  | // | 
|  | // This file implements an interprocedural pass that deduces and/or propagates | 
|  | // attributes. This is done in an abstract interpretation style fixpoint | 
|  | // iteration. See the Attributor.h file comment and the class descriptions in | 
|  | // that file for more information. | 
|  | // | 
|  | //===----------------------------------------------------------------------===// | 
|  |  | 
|  | #include "llvm/Transforms/IPO/Attributor.h" | 
|  |  | 
|  | #include "llvm/ADT/ArrayRef.h" | 
|  | #include "llvm/ADT/PointerIntPair.h" | 
|  | #include "llvm/ADT/STLExtras.h" | 
|  | #include "llvm/ADT/SmallPtrSet.h" | 
|  | #include "llvm/ADT/Statistic.h" | 
|  | #include "llvm/Analysis/AliasAnalysis.h" | 
|  | #include "llvm/Analysis/CallGraph.h" | 
|  | #include "llvm/Analysis/InlineCost.h" | 
|  | #include "llvm/Analysis/MemoryBuiltins.h" | 
|  | #include "llvm/Analysis/MustExecute.h" | 
|  | #include "llvm/IR/AttributeMask.h" | 
|  | #include "llvm/IR/Attributes.h" | 
|  | #include "llvm/IR/Constant.h" | 
|  | #include "llvm/IR/ConstantFold.h" | 
|  | #include "llvm/IR/Constants.h" | 
|  | #include "llvm/IR/DataLayout.h" | 
|  | #include "llvm/IR/GlobalValue.h" | 
|  | #include "llvm/IR/GlobalVariable.h" | 
|  | #include "llvm/IR/Instruction.h" | 
|  | #include "llvm/IR/Instructions.h" | 
|  | #include "llvm/IR/IntrinsicInst.h" | 
|  | #include "llvm/IR/LLVMContext.h" | 
|  | #include "llvm/IR/ValueHandle.h" | 
|  | #include "llvm/Support/Casting.h" | 
|  | #include "llvm/Support/CommandLine.h" | 
|  | #include "llvm/Support/Debug.h" | 
|  | #include "llvm/Support/DebugCounter.h" | 
|  | #include "llvm/Support/FileSystem.h" | 
|  | #include "llvm/Support/GraphWriter.h" | 
|  | #include "llvm/Support/ModRef.h" | 
|  | #include "llvm/Support/raw_ostream.h" | 
|  | #include "llvm/Transforms/Utils/BasicBlockUtils.h" | 
|  | #include "llvm/Transforms/Utils/Cloning.h" | 
|  | #include "llvm/Transforms/Utils/Local.h" | 
|  | #include <cstdint> | 
|  | #include <memory> | 
|  |  | 
|  | #ifdef EXPENSIVE_CHECKS | 
|  | #include "llvm/IR/Verifier.h" | 
|  | #endif | 
|  |  | 
|  | #include <cassert> | 
|  | #include <optional> | 
|  | #include <string> | 
|  |  | 
|  | using namespace llvm; | 
|  |  | 
|  | #define DEBUG_TYPE "attributor" | 
|  | #define VERBOSE_DEBUG_TYPE DEBUG_TYPE "-verbose" | 
|  |  | 
|  | DEBUG_COUNTER(ManifestDBGCounter, "attributor-manifest", | 
|  | "Determine what attributes are manifested in the IR"); | 
|  |  | 
|  | STATISTIC(NumFnDeleted, "Number of function deleted"); | 
|  | STATISTIC(NumFnWithExactDefinition, | 
|  | "Number of functions with exact definitions"); | 
|  | STATISTIC(NumFnWithoutExactDefinition, | 
|  | "Number of functions without exact definitions"); | 
|  | STATISTIC(NumFnShallowWrappersCreated, "Number of shallow wrappers created"); | 
|  | STATISTIC(NumAttributesTimedOut, | 
|  | "Number of abstract attributes timed out before fixpoint"); | 
|  | STATISTIC(NumAttributesValidFixpoint, | 
|  | "Number of abstract attributes in a valid fixpoint state"); | 
|  | STATISTIC(NumAttributesManifested, | 
|  | "Number of abstract attributes manifested in IR"); | 
|  |  | 
|  | // TODO: Determine a good default value. | 
|  | // | 
|  | // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads | 
|  | // (when run with the first 5 abstract attributes). The results also indicate | 
|  | // that we never reach 32 iterations but always find a fixpoint sooner. | 
|  | // | 
|  | // This will become more evolved once we perform two interleaved fixpoint | 
|  | // iterations: bottom-up and top-down. | 
|  | static cl::opt<unsigned> | 
|  | SetFixpointIterations("attributor-max-iterations", cl::Hidden, | 
|  | cl::desc("Maximal number of fixpoint iterations."), | 
|  | cl::init(32)); | 
|  |  | 
|  | static cl::opt<unsigned> | 
|  | MaxSpecializationPerCB("attributor-max-specializations-per-call-base", | 
|  | cl::Hidden, | 
|  | cl::desc("Maximal number of callees specialized for " | 
|  | "a call base"), | 
|  | cl::init(UINT32_MAX)); | 
|  |  | 
|  | static cl::opt<unsigned, true> MaxInitializationChainLengthX( | 
|  | "attributor-max-initialization-chain-length", cl::Hidden, | 
|  | cl::desc( | 
|  | "Maximal number of chained initializations (to avoid stack overflows)"), | 
|  | cl::location(MaxInitializationChainLength), cl::init(1024)); | 
|  | unsigned llvm::MaxInitializationChainLength; | 
|  |  | 
|  | static cl::opt<bool> AnnotateDeclarationCallSites( | 
|  | "attributor-annotate-decl-cs", cl::Hidden, | 
|  | cl::desc("Annotate call sites of function declarations."), cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> EnableHeapToStack("enable-heap-to-stack-conversion", | 
|  | cl::init(true), cl::Hidden); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | AllowShallowWrappers("attributor-allow-shallow-wrappers", cl::Hidden, | 
|  | cl::desc("Allow the Attributor to create shallow " | 
|  | "wrappers for non-exact definitions."), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | AllowDeepWrapper("attributor-allow-deep-wrappers", cl::Hidden, | 
|  | cl::desc("Allow the Attributor to use IP information " | 
|  | "derived from non-exact functions via cloning"), | 
|  | cl::init(false)); | 
|  |  | 
|  | // These options can only used for debug builds. | 
|  | #ifndef NDEBUG | 
|  | static cl::list<std::string> | 
|  | SeedAllowList("attributor-seed-allow-list", cl::Hidden, | 
|  | cl::desc("Comma separated list of attribute names that are " | 
|  | "allowed to be seeded."), | 
|  | cl::CommaSeparated); | 
|  |  | 
|  | static cl::list<std::string> FunctionSeedAllowList( | 
|  | "attributor-function-seed-allow-list", cl::Hidden, | 
|  | cl::desc("Comma separated list of function names that are " | 
|  | "allowed to be seeded."), | 
|  | cl::CommaSeparated); | 
|  | #endif | 
|  |  | 
|  | static cl::opt<bool> | 
|  | DumpDepGraph("attributor-dump-dep-graph", cl::Hidden, | 
|  | cl::desc("Dump the dependency graph to dot files."), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<std::string> DepGraphDotFileNamePrefix( | 
|  | "attributor-depgraph-dot-filename-prefix", cl::Hidden, | 
|  | cl::desc("The prefix used for the CallGraph dot file names.")); | 
|  |  | 
|  | static cl::opt<bool> ViewDepGraph("attributor-view-dep-graph", cl::Hidden, | 
|  | cl::desc("View the dependency graph."), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> PrintDependencies("attributor-print-dep", cl::Hidden, | 
|  | cl::desc("Print attribute dependencies"), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> EnableCallSiteSpecific( | 
|  | "attributor-enable-call-site-specific-deduction", cl::Hidden, | 
|  | cl::desc("Allow the Attributor to do call site specific analysis"), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> | 
|  | PrintCallGraph("attributor-print-call-graph", cl::Hidden, | 
|  | cl::desc("Print Attributor's internal call graph"), | 
|  | cl::init(false)); | 
|  |  | 
|  | static cl::opt<bool> SimplifyAllLoads("attributor-simplify-all-loads", | 
|  | cl::Hidden, | 
|  | cl::desc("Try to simplify all loads."), | 
|  | cl::init(true)); | 
|  |  | 
|  | static cl::opt<bool> CloseWorldAssumption( | 
|  | "attributor-assume-closed-world", cl::Hidden, | 
|  | cl::desc("Should a closed world be assumed, or not. Default if not set.")); | 
|  |  | 
|  | /// Logic operators for the change status enum class. | 
|  | /// | 
|  | ///{ | 
|  | ChangeStatus llvm::operator|(ChangeStatus L, ChangeStatus R) { | 
|  | return L == ChangeStatus::CHANGED ? L : R; | 
|  | } | 
|  | ChangeStatus &llvm::operator|=(ChangeStatus &L, ChangeStatus R) { | 
|  | L = L | R; | 
|  | return L; | 
|  | } | 
|  | ChangeStatus llvm::operator&(ChangeStatus L, ChangeStatus R) { | 
|  | return L == ChangeStatus::UNCHANGED ? L : R; | 
|  | } | 
|  | ChangeStatus &llvm::operator&=(ChangeStatus &L, ChangeStatus R) { | 
|  | L = L & R; | 
|  | return L; | 
|  | } | 
|  | ///} | 
|  |  | 
|  | bool AA::isGPU(const Module &M) { | 
|  | Triple T(M.getTargetTriple()); | 
|  | return T.isGPU(); | 
|  | } | 
|  |  | 
|  | bool AA::isNoSyncInst(Attributor &A, const Instruction &I, | 
|  | const AbstractAttribute &QueryingAA) { | 
|  | // We are looking for volatile instructions or non-relaxed atomics. | 
|  | if (const auto *CB = dyn_cast<CallBase>(&I)) { | 
|  | if (CB->hasFnAttr(Attribute::NoSync)) | 
|  | return true; | 
|  |  | 
|  | // Non-convergent and readnone imply nosync. | 
|  | if (!CB->isConvergent() && !CB->mayReadOrWriteMemory()) | 
|  | return true; | 
|  |  | 
|  | if (AANoSync::isNoSyncIntrinsic(&I)) | 
|  | return true; | 
|  |  | 
|  | bool IsKnownNoSync; | 
|  | return AA::hasAssumedIRAttr<Attribute::NoSync>( | 
|  | A, &QueryingAA, IRPosition::callsite_function(*CB), | 
|  | DepClassTy::OPTIONAL, IsKnownNoSync); | 
|  | } | 
|  |  | 
|  | if (!I.mayReadOrWriteMemory()) | 
|  | return true; | 
|  |  | 
|  | return !I.isVolatile() && !AANoSync::isNonRelaxedAtomic(&I); | 
|  | } | 
|  |  | 
|  | bool AA::isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA, | 
|  | const Value &V, bool ForAnalysisOnly) { | 
|  | // TODO: See the AAInstanceInfo class comment. | 
|  | if (!ForAnalysisOnly) | 
|  | return false; | 
|  | auto *InstanceInfoAA = A.getAAFor<AAInstanceInfo>( | 
|  | QueryingAA, IRPosition::value(V), DepClassTy::OPTIONAL); | 
|  | return InstanceInfoAA && InstanceInfoAA->isAssumedUniqueForAnalysis(); | 
|  | } | 
|  |  | 
|  | Constant * | 
|  | AA::getInitialValueForObj(Attributor &A, const AbstractAttribute &QueryingAA, | 
|  | Value &Obj, Type &Ty, const TargetLibraryInfo *TLI, | 
|  | const DataLayout &DL, AA::RangeTy *RangePtr) { | 
|  | if (Constant *Init = getInitialValueOfAllocation(&Obj, TLI, &Ty)) | 
|  | return Init; | 
|  | auto *GV = dyn_cast<GlobalVariable>(&Obj); | 
|  | if (!GV) | 
|  | return nullptr; | 
|  |  | 
|  | bool UsedAssumedInformation = false; | 
|  | Constant *Initializer = nullptr; | 
|  | if (A.hasGlobalVariableSimplificationCallback(*GV)) { | 
|  | auto AssumedGV = A.getAssumedInitializerFromCallBack( | 
|  | *GV, &QueryingAA, UsedAssumedInformation); | 
|  | Initializer = *AssumedGV; | 
|  | if (!Initializer) | 
|  | return nullptr; | 
|  | } else { | 
|  | if (!GV->hasLocalLinkage()) { | 
|  | // Externally visible global that's either non-constant, | 
|  | // or a constant with an uncertain initializer. | 
|  | if (!GV->hasDefinitiveInitializer() || !GV->isConstant()) | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | // Globals with local linkage are always initialized. | 
|  | assert(!GV->hasLocalLinkage() || GV->hasInitializer()); | 
|  |  | 
|  | if (!Initializer) | 
|  | Initializer = GV->getInitializer(); | 
|  | } | 
|  |  | 
|  | if (RangePtr && !RangePtr->offsetOrSizeAreUnknown()) { | 
|  | APInt Offset = APInt(64, RangePtr->Offset); | 
|  | return ConstantFoldLoadFromConst(Initializer, &Ty, Offset, DL); | 
|  | } | 
|  |  | 
|  | return ConstantFoldLoadFromUniformValue(Initializer, &Ty, DL); | 
|  | } | 
|  |  | 
|  | bool AA::isValidInScope(const Value &V, const Function *Scope) { | 
|  | if (isa<Constant>(V)) | 
|  | return true; | 
|  | if (auto *I = dyn_cast<Instruction>(&V)) | 
|  | return I->getFunction() == Scope; | 
|  | if (auto *A = dyn_cast<Argument>(&V)) | 
|  | return A->getParent() == Scope; | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool AA::isValidAtPosition(const AA::ValueAndContext &VAC, | 
|  | InformationCache &InfoCache) { | 
|  | if (isa<Constant>(VAC.getValue()) || VAC.getValue() == VAC.getCtxI()) | 
|  | return true; | 
|  | const Function *Scope = nullptr; | 
|  | const Instruction *CtxI = VAC.getCtxI(); | 
|  | if (CtxI) | 
|  | Scope = CtxI->getFunction(); | 
|  | if (auto *A = dyn_cast<Argument>(VAC.getValue())) | 
|  | return A->getParent() == Scope; | 
|  | if (auto *I = dyn_cast<Instruction>(VAC.getValue())) { | 
|  | if (I->getFunction() == Scope) { | 
|  | if (const DominatorTree *DT = | 
|  | InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>( | 
|  | *Scope)) | 
|  | return DT->dominates(I, CtxI); | 
|  | // Local dominance check mostly for the old PM passes. | 
|  | if (CtxI && I->getParent() == CtxI->getParent()) | 
|  | return llvm::any_of( | 
|  | make_range(I->getIterator(), I->getParent()->end()), | 
|  | [&](const Instruction &AfterI) { return &AfterI == CtxI; }); | 
|  | } | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Value *AA::getWithType(Value &V, Type &Ty) { | 
|  | if (V.getType() == &Ty) | 
|  | return &V; | 
|  | if (isa<PoisonValue>(V)) | 
|  | return PoisonValue::get(&Ty); | 
|  | if (isa<UndefValue>(V)) | 
|  | return UndefValue::get(&Ty); | 
|  | if (auto *C = dyn_cast<Constant>(&V)) { | 
|  | if (C->isNullValue() && !Ty.isPtrOrPtrVectorTy()) | 
|  | return Constant::getNullValue(&Ty); | 
|  | if (C->getType()->isPointerTy() && Ty.isPointerTy()) | 
|  | return ConstantExpr::getPointerCast(C, &Ty); | 
|  | if (C->getType()->getPrimitiveSizeInBits() >= Ty.getPrimitiveSizeInBits()) { | 
|  | if (C->getType()->isIntegerTy() && Ty.isIntegerTy()) | 
|  | return ConstantExpr::getTrunc(C, &Ty, /* OnlyIfReduced */ true); | 
|  | if (C->getType()->isFloatingPointTy() && Ty.isFloatingPointTy()) | 
|  | return ConstantFoldCastInstruction(Instruction::FPTrunc, C, &Ty); | 
|  | } | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::optional<Value *> | 
|  | AA::combineOptionalValuesInAAValueLatice(const std::optional<Value *> &A, | 
|  | const std::optional<Value *> &B, | 
|  | Type *Ty) { | 
|  | if (A == B) | 
|  | return A; | 
|  | if (!B) | 
|  | return A; | 
|  | if (*B == nullptr) | 
|  | return nullptr; | 
|  | if (!A) | 
|  | return Ty ? getWithType(**B, *Ty) : nullptr; | 
|  | if (*A == nullptr) | 
|  | return nullptr; | 
|  | if (!Ty) | 
|  | Ty = (*A)->getType(); | 
|  | if (isa_and_nonnull<UndefValue>(*A)) | 
|  | return getWithType(**B, *Ty); | 
|  | if (isa<UndefValue>(*B)) | 
|  | return A; | 
|  | if (*A && *B && *A == getWithType(**B, *Ty)) | 
|  | return A; | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | template <bool IsLoad, typename Ty> | 
|  | static bool getPotentialCopiesOfMemoryValue( | 
|  | Attributor &A, Ty &I, SmallSetVector<Value *, 4> &PotentialCopies, | 
|  | SmallSetVector<Instruction *, 4> *PotentialValueOrigins, | 
|  | const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, | 
|  | bool OnlyExact) { | 
|  | LLVM_DEBUG(dbgs() << "Trying to determine the potential copies of " << I | 
|  | << " (only exact: " << OnlyExact << ")\n";); | 
|  |  | 
|  | Value &Ptr = *I.getPointerOperand(); | 
|  | // Containers to remember the pointer infos and new copies while we are not | 
|  | // sure that we can find all of them. If we abort we want to avoid spurious | 
|  | // dependences and potential copies in the provided container. | 
|  | SmallVector<const AAPointerInfo *> PIs; | 
|  | SmallSetVector<Value *, 8> NewCopies; | 
|  | SmallSetVector<Instruction *, 8> NewCopyOrigins; | 
|  |  | 
|  | const auto *TLI = | 
|  | A.getInfoCache().getTargetLibraryInfoForFunction(*I.getFunction()); | 
|  |  | 
|  | auto Pred = [&](Value &Obj) { | 
|  | LLVM_DEBUG(dbgs() << "Visit underlying object " << Obj << "\n"); | 
|  | if (isa<UndefValue>(&Obj)) | 
|  | return true; | 
|  | if (isa<ConstantPointerNull>(&Obj)) { | 
|  | // A null pointer access can be undefined but any offset from null may | 
|  | // be OK. We do not try to optimize the latter. | 
|  | if (!NullPointerIsDefined(I.getFunction(), | 
|  | Ptr.getType()->getPointerAddressSpace()) && | 
|  | A.getAssumedSimplified(Ptr, QueryingAA, UsedAssumedInformation, | 
|  | AA::Interprocedural) == &Obj) | 
|  | return true; | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "Underlying object is a valid nullptr, giving up.\n";); | 
|  | return false; | 
|  | } | 
|  | // TODO: Use assumed noalias return. | 
|  | if (!isa<AllocaInst>(&Obj) && !isa<GlobalVariable>(&Obj) && | 
|  | !(IsLoad ? isAllocationFn(&Obj, TLI) : isNoAliasCall(&Obj))) { | 
|  | LLVM_DEBUG(dbgs() << "Underlying object is not supported yet: " << Obj | 
|  | << "\n";); | 
|  | return false; | 
|  | } | 
|  | if (auto *GV = dyn_cast<GlobalVariable>(&Obj)) | 
|  | if (!GV->hasLocalLinkage() && | 
|  | !(GV->isConstant() && GV->hasInitializer())) { | 
|  | LLVM_DEBUG(dbgs() << "Underlying object is global with external " | 
|  | "linkage, not supported yet: " | 
|  | << Obj << "\n";); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool NullOnly = true; | 
|  | bool NullRequired = false; | 
|  | auto CheckForNullOnlyAndUndef = [&](std::optional<Value *> V, | 
|  | bool IsExact) { | 
|  | if (!V || *V == nullptr) | 
|  | NullOnly = false; | 
|  | else if (isa<UndefValue>(*V)) | 
|  | /* No op */; | 
|  | else if (isa<Constant>(*V) && cast<Constant>(*V)->isNullValue()) | 
|  | NullRequired = !IsExact; | 
|  | else | 
|  | NullOnly = false; | 
|  | }; | 
|  |  | 
|  | auto AdjustWrittenValueType = [&](const AAPointerInfo::Access &Acc, | 
|  | Value &V) { | 
|  | Value *AdjV = AA::getWithType(V, *I.getType()); | 
|  | if (!AdjV) { | 
|  | LLVM_DEBUG(dbgs() << "Underlying object written but stored value " | 
|  | "cannot be converted to read type: " | 
|  | << *Acc.getRemoteInst() << " : " << *I.getType() | 
|  | << "\n";); | 
|  | } | 
|  | return AdjV; | 
|  | }; | 
|  |  | 
|  | auto SkipCB = [&](const AAPointerInfo::Access &Acc) { | 
|  | if ((IsLoad && !Acc.isWriteOrAssumption()) || (!IsLoad && !Acc.isRead())) | 
|  | return true; | 
|  | if (IsLoad) { | 
|  | if (Acc.isWrittenValueYetUndetermined()) | 
|  | return true; | 
|  | if (PotentialValueOrigins && !isa<AssumeInst>(Acc.getRemoteInst())) | 
|  | return false; | 
|  | if (!Acc.isWrittenValueUnknown()) | 
|  | if (Value *V = AdjustWrittenValueType(Acc, *Acc.getWrittenValue())) | 
|  | if (NewCopies.count(V)) { | 
|  | NewCopyOrigins.insert(Acc.getRemoteInst()); | 
|  | return true; | 
|  | } | 
|  | if (auto *SI = dyn_cast<StoreInst>(Acc.getRemoteInst())) | 
|  | if (Value *V = AdjustWrittenValueType(Acc, *SI->getValueOperand())) | 
|  | if (NewCopies.count(V)) { | 
|  | NewCopyOrigins.insert(Acc.getRemoteInst()); | 
|  | return true; | 
|  | } | 
|  | } | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) { | 
|  | if ((IsLoad && !Acc.isWriteOrAssumption()) || (!IsLoad && !Acc.isRead())) | 
|  | return true; | 
|  | if (IsLoad && Acc.isWrittenValueYetUndetermined()) | 
|  | return true; | 
|  | CheckForNullOnlyAndUndef(Acc.getContent(), IsExact); | 
|  | if (OnlyExact && !IsExact && !NullOnly && | 
|  | !isa_and_nonnull<UndefValue>(Acc.getWrittenValue())) { | 
|  | LLVM_DEBUG(dbgs() << "Non exact access " << *Acc.getRemoteInst() | 
|  | << ", abort!\n"); | 
|  | return false; | 
|  | } | 
|  | if (NullRequired && !NullOnly) { | 
|  | LLVM_DEBUG(dbgs() << "Required all `null` accesses due to non exact " | 
|  | "one, however found non-null one: " | 
|  | << *Acc.getRemoteInst() << ", abort!\n"); | 
|  | return false; | 
|  | } | 
|  | if (IsLoad) { | 
|  | assert(isa<LoadInst>(I) && "Expected load or store instruction only!"); | 
|  | if (!Acc.isWrittenValueUnknown()) { | 
|  | Value *V = AdjustWrittenValueType(Acc, *Acc.getWrittenValue()); | 
|  | if (!V) | 
|  | return false; | 
|  | NewCopies.insert(V); | 
|  | if (PotentialValueOrigins) | 
|  | NewCopyOrigins.insert(Acc.getRemoteInst()); | 
|  | return true; | 
|  | } | 
|  | auto *SI = dyn_cast<StoreInst>(Acc.getRemoteInst()); | 
|  | if (!SI) { | 
|  | LLVM_DEBUG(dbgs() << "Underlying object written through a non-store " | 
|  | "instruction not supported yet: " | 
|  | << *Acc.getRemoteInst() << "\n";); | 
|  | return false; | 
|  | } | 
|  | Value *V = AdjustWrittenValueType(Acc, *SI->getValueOperand()); | 
|  | if (!V) | 
|  | return false; | 
|  | NewCopies.insert(V); | 
|  | if (PotentialValueOrigins) | 
|  | NewCopyOrigins.insert(SI); | 
|  | } else { | 
|  | assert(isa<StoreInst>(I) && "Expected load or store instruction only!"); | 
|  | auto *LI = dyn_cast<LoadInst>(Acc.getRemoteInst()); | 
|  | if (!LI && OnlyExact) { | 
|  | LLVM_DEBUG(dbgs() << "Underlying object read through a non-load " | 
|  | "instruction not supported yet: " | 
|  | << *Acc.getRemoteInst() << "\n";); | 
|  | return false; | 
|  | } | 
|  | NewCopies.insert(Acc.getRemoteInst()); | 
|  | } | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | // If the value has been written to we don't need the initial value of the | 
|  | // object. | 
|  | bool HasBeenWrittenTo = false; | 
|  |  | 
|  | AA::RangeTy Range; | 
|  | auto *PI = A.getAAFor<AAPointerInfo>(QueryingAA, IRPosition::value(Obj), | 
|  | DepClassTy::NONE); | 
|  | if (!PI || !PI->forallInterferingAccesses( | 
|  | A, QueryingAA, I, | 
|  | /* FindInterferingWrites */ IsLoad, | 
|  | /* FindInterferingReads */ !IsLoad, CheckAccess, | 
|  | HasBeenWrittenTo, Range, SkipCB)) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() | 
|  | << "Failed to verify all interfering accesses for underlying object: " | 
|  | << Obj << "\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | if (IsLoad && !HasBeenWrittenTo && !Range.isUnassigned()) { | 
|  | const DataLayout &DL = A.getDataLayout(); | 
|  | Value *InitialValue = AA::getInitialValueForObj( | 
|  | A, QueryingAA, Obj, *I.getType(), TLI, DL, &Range); | 
|  | if (!InitialValue) { | 
|  | LLVM_DEBUG(dbgs() << "Could not determine required initial value of " | 
|  | "underlying object, abort!\n"); | 
|  | return false; | 
|  | } | 
|  | CheckForNullOnlyAndUndef(InitialValue, /* IsExact */ true); | 
|  | if (NullRequired && !NullOnly) { | 
|  | LLVM_DEBUG(dbgs() << "Non exact access but initial value that is not " | 
|  | "null or undef, abort!\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | NewCopies.insert(InitialValue); | 
|  | if (PotentialValueOrigins) | 
|  | NewCopyOrigins.insert(nullptr); | 
|  | } | 
|  |  | 
|  | PIs.push_back(PI); | 
|  |  | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | const auto *AAUO = A.getAAFor<AAUnderlyingObjects>( | 
|  | QueryingAA, IRPosition::value(Ptr), DepClassTy::OPTIONAL); | 
|  | if (!AAUO || !AAUO->forallUnderlyingObjects(Pred)) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "Underlying objects stored into could not be determined\n";); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Only if we were successful collection all potential copies we record | 
|  | // dependences (on non-fix AAPointerInfo AAs). We also only then modify the | 
|  | // given PotentialCopies container. | 
|  | for (const auto *PI : PIs) { | 
|  | if (!PI->getState().isAtFixpoint()) | 
|  | UsedAssumedInformation = true; | 
|  | A.recordDependence(*PI, QueryingAA, DepClassTy::OPTIONAL); | 
|  | } | 
|  | PotentialCopies.insert_range(NewCopies); | 
|  | if (PotentialValueOrigins) | 
|  | PotentialValueOrigins->insert_range(NewCopyOrigins); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool AA::getPotentiallyLoadedValues( | 
|  | Attributor &A, LoadInst &LI, SmallSetVector<Value *, 4> &PotentialValues, | 
|  | SmallSetVector<Instruction *, 4> &PotentialValueOrigins, | 
|  | const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, | 
|  | bool OnlyExact) { | 
|  | return getPotentialCopiesOfMemoryValue</* IsLoad */ true>( | 
|  | A, LI, PotentialValues, &PotentialValueOrigins, QueryingAA, | 
|  | UsedAssumedInformation, OnlyExact); | 
|  | } | 
|  |  | 
|  | bool AA::getPotentialCopiesOfStoredValue( | 
|  | Attributor &A, StoreInst &SI, SmallSetVector<Value *, 4> &PotentialCopies, | 
|  | const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation, | 
|  | bool OnlyExact) { | 
|  | return getPotentialCopiesOfMemoryValue</* IsLoad */ false>( | 
|  | A, SI, PotentialCopies, nullptr, QueryingAA, UsedAssumedInformation, | 
|  | OnlyExact); | 
|  | } | 
|  |  | 
|  | static bool isAssumedReadOnlyOrReadNone(Attributor &A, const IRPosition &IRP, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | bool RequireReadNone, bool &IsKnown) { | 
|  | if (RequireReadNone) { | 
|  | if (AA::hasAssumedIRAttr<Attribute::ReadNone>( | 
|  | A, &QueryingAA, IRP, DepClassTy::OPTIONAL, IsKnown, | 
|  | /* IgnoreSubsumingPositions */ true)) | 
|  | return true; | 
|  | } else if (AA::hasAssumedIRAttr<Attribute::ReadOnly>( | 
|  | A, &QueryingAA, IRP, DepClassTy::OPTIONAL, IsKnown, | 
|  | /* IgnoreSubsumingPositions */ true)) | 
|  | return true; | 
|  |  | 
|  | IRPosition::Kind Kind = IRP.getPositionKind(); | 
|  | if (Kind == IRPosition::IRP_FUNCTION || Kind == IRPosition::IRP_CALL_SITE) { | 
|  | const auto *MemLocAA = | 
|  | A.getAAFor<AAMemoryLocation>(QueryingAA, IRP, DepClassTy::NONE); | 
|  | if (MemLocAA && MemLocAA->isAssumedReadNone()) { | 
|  | IsKnown = MemLocAA->isKnownReadNone(); | 
|  | if (!IsKnown) | 
|  | A.recordDependence(*MemLocAA, QueryingAA, DepClassTy::OPTIONAL); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | const auto *MemBehaviorAA = | 
|  | A.getAAFor<AAMemoryBehavior>(QueryingAA, IRP, DepClassTy::NONE); | 
|  | if (MemBehaviorAA && | 
|  | (MemBehaviorAA->isAssumedReadNone() || | 
|  | (!RequireReadNone && MemBehaviorAA->isAssumedReadOnly()))) { | 
|  | IsKnown = RequireReadNone ? MemBehaviorAA->isKnownReadNone() | 
|  | : MemBehaviorAA->isKnownReadOnly(); | 
|  | if (!IsKnown) | 
|  | A.recordDependence(*MemBehaviorAA, QueryingAA, DepClassTy::OPTIONAL); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool AA::isAssumedReadOnly(Attributor &A, const IRPosition &IRP, | 
|  | const AbstractAttribute &QueryingAA, bool &IsKnown) { | 
|  | return isAssumedReadOnlyOrReadNone(A, IRP, QueryingAA, | 
|  | /* RequireReadNone */ false, IsKnown); | 
|  | } | 
|  | bool AA::isAssumedReadNone(Attributor &A, const IRPosition &IRP, | 
|  | const AbstractAttribute &QueryingAA, bool &IsKnown) { | 
|  | return isAssumedReadOnlyOrReadNone(A, IRP, QueryingAA, | 
|  | /* RequireReadNone */ true, IsKnown); | 
|  | } | 
|  |  | 
|  | static bool | 
|  | isPotentiallyReachable(Attributor &A, const Instruction &FromI, | 
|  | const Instruction *ToI, const Function &ToFn, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | const AA::InstExclusionSetTy *ExclusionSet, | 
|  | std::function<bool(const Function &F)> GoBackwardsCB) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, { | 
|  | dbgs() << "[AA] isPotentiallyReachable @" << ToFn.getName() << " from " | 
|  | << FromI << " [GBCB: " << bool(GoBackwardsCB) << "][#ExS: " | 
|  | << (ExclusionSet ? std::to_string(ExclusionSet->size()) : "none") | 
|  | << "]\n"; | 
|  | if (ExclusionSet) | 
|  | for (auto *ES : *ExclusionSet) | 
|  | dbgs() << *ES << "\n"; | 
|  | }); | 
|  |  | 
|  | // We know kernels (generally) cannot be called from within the module. Thus, | 
|  | // for reachability we would need to step back from a kernel which would allow | 
|  | // us to reach anything anyway. Even if a kernel is invoked from another | 
|  | // kernel, values like allocas and shared memory are not accessible. We | 
|  | // implicitly check for this situation to avoid costly lookups. | 
|  | if (GoBackwardsCB && &ToFn != FromI.getFunction() && | 
|  | !GoBackwardsCB(*FromI.getFunction()) && A.getInfoCache().isKernel(ToFn) && | 
|  | A.getInfoCache().isKernel(*FromI.getFunction())) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] assume kernel cannot be reached from within the " | 
|  | "module; success\n";); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // If we can go arbitrarily backwards we will eventually reach an entry point | 
|  | // that can reach ToI. Only if a set of blocks through which we cannot go is | 
|  | // provided, or once we track internal functions not accessible from the | 
|  | // outside, it makes sense to perform backwards analysis in the absence of a | 
|  | // GoBackwardsCB. | 
|  | if (!GoBackwardsCB && !ExclusionSet) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI | 
|  | << " is not checked backwards and does not have an " | 
|  | "exclusion set, abort\n"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | SmallPtrSet<const Instruction *, 8> Visited; | 
|  | SmallVector<const Instruction *> Worklist; | 
|  | Worklist.push_back(&FromI); | 
|  |  | 
|  | while (!Worklist.empty()) { | 
|  | const Instruction *CurFromI = Worklist.pop_back_val(); | 
|  | if (!Visited.insert(CurFromI).second) | 
|  | continue; | 
|  |  | 
|  | const Function *FromFn = CurFromI->getFunction(); | 
|  | if (FromFn == &ToFn) { | 
|  | if (!ToI) | 
|  | return true; | 
|  | LLVM_DEBUG(dbgs() << "[AA] check " << *ToI << " from " << *CurFromI | 
|  | << " intraprocedurally\n"); | 
|  | const auto *ReachabilityAA = A.getAAFor<AAIntraFnReachability>( | 
|  | QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL); | 
|  | bool Result = !ReachabilityAA || ReachabilityAA->isAssumedReachable( | 
|  | A, *CurFromI, *ToI, ExclusionSet); | 
|  | LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " " | 
|  | << (Result ? "can potentially " : "cannot ") << "reach " | 
|  | << *ToI << " [Intra]\n"); | 
|  | if (Result) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Result = true; | 
|  | if (!ToFn.isDeclaration() && ToI) { | 
|  | const auto *ToReachabilityAA = A.getAAFor<AAIntraFnReachability>( | 
|  | QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL); | 
|  | const Instruction &EntryI = ToFn.getEntryBlock().front(); | 
|  | Result = !ToReachabilityAA || ToReachabilityAA->isAssumedReachable( | 
|  | A, EntryI, *ToI, ExclusionSet); | 
|  | LLVM_DEBUG(dbgs() << "[AA] Entry " << EntryI << " of @" << ToFn.getName() | 
|  | << " " << (Result ? "can potentially " : "cannot ") | 
|  | << "reach @" << *ToI << " [ToFn]\n"); | 
|  | } | 
|  |  | 
|  | if (Result) { | 
|  | // The entry of the ToFn can reach the instruction ToI. If the current | 
|  | // instruction is already known to reach the ToFn. | 
|  | const auto *FnReachabilityAA = A.getAAFor<AAInterFnReachability>( | 
|  | QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL); | 
|  | Result = !FnReachabilityAA || FnReachabilityAA->instructionCanReach( | 
|  | A, *CurFromI, ToFn, ExclusionSet); | 
|  | LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " in @" << FromFn->getName() | 
|  | << " " << (Result ? "can potentially " : "cannot ") | 
|  | << "reach @" << ToFn.getName() << " [FromFn]\n"); | 
|  | if (Result) | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // TODO: Check assumed nounwind. | 
|  | const auto *ReachabilityAA = A.getAAFor<AAIntraFnReachability>( | 
|  | QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL); | 
|  | auto ReturnInstCB = [&](Instruction &Ret) { | 
|  | bool Result = !ReachabilityAA || ReachabilityAA->isAssumedReachable( | 
|  | A, *CurFromI, Ret, ExclusionSet); | 
|  | LLVM_DEBUG(dbgs() << "[AA][Ret] " << *CurFromI << " " | 
|  | << (Result ? "can potentially " : "cannot ") << "reach " | 
|  | << Ret << " [Intra]\n"); | 
|  | return !Result; | 
|  | }; | 
|  |  | 
|  | // Check if we can reach returns. | 
|  | bool UsedAssumedInformation = false; | 
|  | if (A.checkForAllInstructions(ReturnInstCB, FromFn, &QueryingAA, | 
|  | {Instruction::Ret}, UsedAssumedInformation)) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] No return is reachable, done\n"); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (!GoBackwardsCB) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI | 
|  | << " is not checked backwards, abort\n"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // If we do not go backwards from the FromFn we are done here and so far we | 
|  | // could not find a way to reach ToFn/ToI. | 
|  | if (!GoBackwardsCB(*FromFn)) | 
|  | continue; | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "Stepping backwards to the call sites of @" | 
|  | << FromFn->getName() << "\n"); | 
|  |  | 
|  | auto CheckCallSite = [&](AbstractCallSite ACS) { | 
|  | CallBase *CB = ACS.getInstruction(); | 
|  | if (!CB) | 
|  | return false; | 
|  |  | 
|  | if (isa<InvokeInst>(CB)) | 
|  | return false; | 
|  |  | 
|  | Instruction *Inst = CB->getNextNode(); | 
|  | Worklist.push_back(Inst); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | Result = !A.checkForAllCallSites(CheckCallSite, *FromFn, | 
|  | /* RequireAllCallSites */ true, | 
|  | &QueryingAA, UsedAssumedInformation); | 
|  | if (Result) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] stepping back to call sites from " << *CurFromI | 
|  | << " in @" << FromFn->getName() | 
|  | << " failed, give up\n"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[AA] stepped back to call sites from " << *CurFromI | 
|  | << " in @" << FromFn->getName() | 
|  | << " worklist size is: " << Worklist.size() << "\n"); | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool AA::isPotentiallyReachable( | 
|  | Attributor &A, const Instruction &FromI, const Instruction &ToI, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | const AA::InstExclusionSetTy *ExclusionSet, | 
|  | std::function<bool(const Function &F)> GoBackwardsCB) { | 
|  | const Function *ToFn = ToI.getFunction(); | 
|  | return ::isPotentiallyReachable(A, FromI, &ToI, *ToFn, QueryingAA, | 
|  | ExclusionSet, GoBackwardsCB); | 
|  | } | 
|  |  | 
|  | bool AA::isPotentiallyReachable( | 
|  | Attributor &A, const Instruction &FromI, const Function &ToFn, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | const AA::InstExclusionSetTy *ExclusionSet, | 
|  | std::function<bool(const Function &F)> GoBackwardsCB) { | 
|  | return ::isPotentiallyReachable(A, FromI, /* ToI */ nullptr, ToFn, QueryingAA, | 
|  | ExclusionSet, GoBackwardsCB); | 
|  | } | 
|  |  | 
|  | bool AA::isAssumedThreadLocalObject(Attributor &A, Value &Obj, | 
|  | const AbstractAttribute &QueryingAA) { | 
|  | if (isa<UndefValue>(Obj)) | 
|  | return true; | 
|  | if (isa<AllocaInst>(Obj)) { | 
|  | InformationCache &InfoCache = A.getInfoCache(); | 
|  | if (!InfoCache.stackIsAccessibleByOtherThreads()) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "[AA] Object '" << Obj | 
|  | << "' is thread local; stack objects are thread local.\n"); | 
|  | return true; | 
|  | } | 
|  | bool IsKnownNoCapture; | 
|  | bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::Captures>( | 
|  | A, &QueryingAA, IRPosition::value(Obj), DepClassTy::OPTIONAL, | 
|  | IsKnownNoCapture); | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj << "' is " | 
|  | << (IsAssumedNoCapture ? "" : "not") << " thread local; " | 
|  | << (IsAssumedNoCapture ? "non-" : "") | 
|  | << "captured stack object.\n"); | 
|  | return IsAssumedNoCapture; | 
|  | } | 
|  | if (auto *GV = dyn_cast<GlobalVariable>(&Obj)) { | 
|  | if (GV->isConstant()) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj | 
|  | << "' is thread local; constant global\n"); | 
|  | return true; | 
|  | } | 
|  | if (GV->isThreadLocal()) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj | 
|  | << "' is thread local; thread local global\n"); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (A.getInfoCache().targetIsGPU()) { | 
|  | if (Obj.getType()->getPointerAddressSpace() == | 
|  | (int)AA::GPUAddressSpace::Local) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj | 
|  | << "' is thread local; GPU local memory\n"); | 
|  | return true; | 
|  | } | 
|  | if (Obj.getType()->getPointerAddressSpace() == | 
|  | (int)AA::GPUAddressSpace::Constant) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj | 
|  | << "' is thread local; GPU constant memory\n"); | 
|  | return true; | 
|  | } | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj << "' is not thread local\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool AA::isPotentiallyAffectedByBarrier(Attributor &A, const Instruction &I, | 
|  | const AbstractAttribute &QueryingAA) { | 
|  | if (!I.mayHaveSideEffects() && !I.mayReadFromMemory()) | 
|  | return false; | 
|  |  | 
|  | SmallSetVector<const Value *, 8> Ptrs; | 
|  |  | 
|  | auto AddLocationPtr = [&](std::optional<MemoryLocation> Loc) { | 
|  | if (!Loc || !Loc->Ptr) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "[AA] Access to unknown location; -> requires barriers\n"); | 
|  | return false; | 
|  | } | 
|  | Ptrs.insert(Loc->Ptr); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&I)) { | 
|  | if (!AddLocationPtr(MemoryLocation::getForDest(MI))) | 
|  | return true; | 
|  | if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(&I)) | 
|  | if (!AddLocationPtr(MemoryLocation::getForSource(MTI))) | 
|  | return true; | 
|  | } else if (!AddLocationPtr(MemoryLocation::getOrNone(&I))) | 
|  | return true; | 
|  |  | 
|  | return isPotentiallyAffectedByBarrier(A, Ptrs.getArrayRef(), QueryingAA, &I); | 
|  | } | 
|  |  | 
|  | bool AA::isPotentiallyAffectedByBarrier(Attributor &A, | 
|  | ArrayRef<const Value *> Ptrs, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | const Instruction *CtxI) { | 
|  | for (const Value *Ptr : Ptrs) { | 
|  | if (!Ptr) { | 
|  | LLVM_DEBUG(dbgs() << "[AA] nullptr; -> requires barriers\n"); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | auto Pred = [&](Value &Obj) { | 
|  | if (AA::isAssumedThreadLocalObject(A, Obj, QueryingAA)) | 
|  | return true; | 
|  | LLVM_DEBUG(dbgs() << "[AA] Access to '" << Obj << "' via '" << *Ptr | 
|  | << "'; -> requires barrier\n"); | 
|  | return false; | 
|  | }; | 
|  |  | 
|  | const auto *UnderlyingObjsAA = A.getAAFor<AAUnderlyingObjects>( | 
|  | QueryingAA, IRPosition::value(*Ptr), DepClassTy::OPTIONAL); | 
|  | if (!UnderlyingObjsAA || !UnderlyingObjsAA->forallUnderlyingObjects(Pred)) | 
|  | return true; | 
|  | } | 
|  | return false; | 
|  | } | 
|  |  | 
|  | /// Return true if \p New is equal or worse than \p Old. | 
|  | static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) { | 
|  | if (!Old.isIntAttribute()) | 
|  | return true; | 
|  |  | 
|  | return Old.getValueAsInt() >= New.getValueAsInt(); | 
|  | } | 
|  |  | 
|  | /// Return true if the information provided by \p Attr was added to the | 
|  | /// attribute set \p AttrSet. This is only the case if it was not already | 
|  | /// present in \p AttrSet. | 
|  | static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr, | 
|  | AttributeSet AttrSet, bool ForceReplace, | 
|  | AttrBuilder &AB) { | 
|  |  | 
|  | if (Attr.isEnumAttribute()) { | 
|  | Attribute::AttrKind Kind = Attr.getKindAsEnum(); | 
|  | if (AttrSet.hasAttribute(Kind)) | 
|  | return false; | 
|  | AB.addAttribute(Kind); | 
|  | return true; | 
|  | } | 
|  | if (Attr.isStringAttribute()) { | 
|  | StringRef Kind = Attr.getKindAsString(); | 
|  | if (AttrSet.hasAttribute(Kind)) { | 
|  | if (!ForceReplace) | 
|  | return false; | 
|  | } | 
|  | AB.addAttribute(Kind, Attr.getValueAsString()); | 
|  | return true; | 
|  | } | 
|  | if (Attr.isIntAttribute()) { | 
|  | Attribute::AttrKind Kind = Attr.getKindAsEnum(); | 
|  | if (!ForceReplace && Kind == Attribute::Memory) { | 
|  | MemoryEffects ME = Attr.getMemoryEffects() & AttrSet.getMemoryEffects(); | 
|  | if (ME == AttrSet.getMemoryEffects()) | 
|  | return false; | 
|  | AB.addMemoryAttr(ME); | 
|  | return true; | 
|  | } | 
|  | if (AttrSet.hasAttribute(Kind)) { | 
|  | if (!ForceReplace && isEqualOrWorse(Attr, AttrSet.getAttribute(Kind))) | 
|  | return false; | 
|  | } | 
|  | AB.addAttribute(Attr); | 
|  | return true; | 
|  | } | 
|  | if (Attr.isConstantRangeAttribute()) { | 
|  | Attribute::AttrKind Kind = Attr.getKindAsEnum(); | 
|  | if (!ForceReplace && AttrSet.hasAttribute(Kind)) | 
|  | return false; | 
|  | AB.addAttribute(Attr); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | llvm_unreachable("Expected enum or string attribute!"); | 
|  | } | 
|  |  | 
|  | Argument *IRPosition::getAssociatedArgument() const { | 
|  | if (getPositionKind() == IRP_ARGUMENT) | 
|  | return cast<Argument>(&getAnchorValue()); | 
|  |  | 
|  | // Not an Argument and no argument number means this is not a call site | 
|  | // argument, thus we cannot find a callback argument to return. | 
|  | int ArgNo = getCallSiteArgNo(); | 
|  | if (ArgNo < 0) | 
|  | return nullptr; | 
|  |  | 
|  | // Use abstract call sites to make the connection between the call site | 
|  | // values and the ones in callbacks. If a callback was found that makes use | 
|  | // of the underlying call site operand, we want the corresponding callback | 
|  | // callee argument and not the direct callee argument. | 
|  | std::optional<Argument *> CBCandidateArg; | 
|  | SmallVector<const Use *, 4> CallbackUses; | 
|  | const auto &CB = cast<CallBase>(getAnchorValue()); | 
|  | AbstractCallSite::getCallbackUses(CB, CallbackUses); | 
|  | for (const Use *U : CallbackUses) { | 
|  | AbstractCallSite ACS(U); | 
|  | assert(ACS && ACS.isCallbackCall()); | 
|  | if (!ACS.getCalledFunction()) | 
|  | continue; | 
|  |  | 
|  | for (unsigned u = 0, e = ACS.getNumArgOperands(); u < e; u++) { | 
|  |  | 
|  | // Test if the underlying call site operand is argument number u of the | 
|  | // callback callee. | 
|  | if (ACS.getCallArgOperandNo(u) != ArgNo) | 
|  | continue; | 
|  |  | 
|  | assert(ACS.getCalledFunction()->arg_size() > u && | 
|  | "ACS mapped into var-args arguments!"); | 
|  | if (CBCandidateArg) { | 
|  | CBCandidateArg = nullptr; | 
|  | break; | 
|  | } | 
|  | CBCandidateArg = ACS.getCalledFunction()->getArg(u); | 
|  | } | 
|  | } | 
|  |  | 
|  | // If we found a unique callback candidate argument, return it. | 
|  | if (CBCandidateArg && *CBCandidateArg) | 
|  | return *CBCandidateArg; | 
|  |  | 
|  | // If no callbacks were found, or none used the underlying call site operand | 
|  | // exclusively, use the direct callee argument if available. | 
|  | auto *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand()); | 
|  | if (Callee && Callee->arg_size() > unsigned(ArgNo)) | 
|  | return Callee->getArg(ArgNo); | 
|  |  | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | ChangeStatus AbstractAttribute::update(Attributor &A) { | 
|  | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
|  | if (getState().isAtFixpoint()) | 
|  | return HasChanged; | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n"); | 
|  |  | 
|  | HasChanged = updateImpl(A); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this | 
|  | << "\n"); | 
|  |  | 
|  | return HasChanged; | 
|  | } | 
|  |  | 
|  | Attributor::Attributor(SetVector<Function *> &Functions, | 
|  | InformationCache &InfoCache, | 
|  | AttributorConfig Configuration) | 
|  | : Allocator(InfoCache.Allocator), Functions(Functions), | 
|  | InfoCache(InfoCache), Configuration(Configuration) { | 
|  | if (!isClosedWorldModule()) | 
|  | return; | 
|  | for (Function *Fn : Functions) | 
|  | if (Fn->hasAddressTaken(/*PutOffender=*/nullptr, | 
|  | /*IgnoreCallbackUses=*/false, | 
|  | /*IgnoreAssumeLikeCalls=*/true, | 
|  | /*IgnoreLLVMUsed=*/true, | 
|  | /*IgnoreARCAttachedCall=*/false, | 
|  | /*IgnoreCastedDirectCall=*/true)) | 
|  | InfoCache.IndirectlyCallableFunctions.push_back(Fn); | 
|  | } | 
|  |  | 
|  | bool Attributor::getAttrsFromAssumes(const IRPosition &IRP, | 
|  | Attribute::AttrKind AK, | 
|  | SmallVectorImpl<Attribute> &Attrs) { | 
|  | assert(IRP.getPositionKind() != IRPosition::IRP_INVALID && | 
|  | "Did expect a valid position!"); | 
|  | MustBeExecutedContextExplorer *Explorer = | 
|  | getInfoCache().getMustBeExecutedContextExplorer(); | 
|  | if (!Explorer) | 
|  | return false; | 
|  |  | 
|  | Value &AssociatedValue = IRP.getAssociatedValue(); | 
|  |  | 
|  | const Assume2KnowledgeMap &A2K = | 
|  | getInfoCache().getKnowledgeMap().lookup({&AssociatedValue, AK}); | 
|  |  | 
|  | // Check if we found any potential assume use, if not we don't need to create | 
|  | // explorer iterators. | 
|  | if (A2K.empty()) | 
|  | return false; | 
|  |  | 
|  | LLVMContext &Ctx = AssociatedValue.getContext(); | 
|  | unsigned AttrsSize = Attrs.size(); | 
|  | auto EIt = Explorer->begin(IRP.getCtxI()), | 
|  | EEnd = Explorer->end(IRP.getCtxI()); | 
|  | for (const auto &It : A2K) | 
|  | if (Explorer->findInContextOf(It.first, EIt, EEnd)) | 
|  | Attrs.push_back(Attribute::get(Ctx, AK, It.second.Max)); | 
|  | return AttrsSize != Attrs.size(); | 
|  | } | 
|  |  | 
|  | template <typename DescTy> | 
|  | ChangeStatus | 
|  | Attributor::updateAttrMap(const IRPosition &IRP, ArrayRef<DescTy> AttrDescs, | 
|  | function_ref<bool(const DescTy &, AttributeSet, | 
|  | AttributeMask &, AttrBuilder &)> | 
|  | CB) { | 
|  | if (AttrDescs.empty()) | 
|  | return ChangeStatus::UNCHANGED; | 
|  | switch (IRP.getPositionKind()) { | 
|  | case IRPosition::IRP_FLOAT: | 
|  | case IRPosition::IRP_INVALID: | 
|  | return ChangeStatus::UNCHANGED; | 
|  | default: | 
|  | break; | 
|  | }; | 
|  |  | 
|  | AttributeList AL; | 
|  | Value *AttrListAnchor = IRP.getAttrListAnchor(); | 
|  | auto It = AttrsMap.find(AttrListAnchor); | 
|  | if (It == AttrsMap.end()) | 
|  | AL = IRP.getAttrList(); | 
|  | else | 
|  | AL = It->getSecond(); | 
|  |  | 
|  | LLVMContext &Ctx = IRP.getAnchorValue().getContext(); | 
|  | auto AttrIdx = IRP.getAttrIdx(); | 
|  | AttributeSet AS = AL.getAttributes(AttrIdx); | 
|  | AttributeMask AM; | 
|  | AttrBuilder AB(Ctx); | 
|  |  | 
|  | ChangeStatus HasChanged = ChangeStatus::UNCHANGED; | 
|  | for (const DescTy &AttrDesc : AttrDescs) | 
|  | if (CB(AttrDesc, AS, AM, AB)) | 
|  | HasChanged = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (HasChanged == ChangeStatus::UNCHANGED) | 
|  | return ChangeStatus::UNCHANGED; | 
|  |  | 
|  | AL = AL.removeAttributesAtIndex(Ctx, AttrIdx, AM); | 
|  | AL = AL.addAttributesAtIndex(Ctx, AttrIdx, AB); | 
|  | AttrsMap[AttrListAnchor] = AL; | 
|  | return ChangeStatus::CHANGED; | 
|  | } | 
|  |  | 
|  | bool Attributor::hasAttr(const IRPosition &IRP, | 
|  | ArrayRef<Attribute::AttrKind> AttrKinds, | 
|  | bool IgnoreSubsumingPositions, | 
|  | Attribute::AttrKind ImpliedAttributeKind) { | 
|  | bool Implied = false; | 
|  | bool HasAttr = false; | 
|  | auto HasAttrCB = [&](const Attribute::AttrKind &Kind, AttributeSet AttrSet, | 
|  | AttributeMask &, AttrBuilder &) { | 
|  | if (AttrSet.hasAttribute(Kind)) { | 
|  | Implied |= Kind != ImpliedAttributeKind; | 
|  | HasAttr = true; | 
|  | } | 
|  | return false; | 
|  | }; | 
|  | for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) { | 
|  | updateAttrMap<Attribute::AttrKind>(EquivIRP, AttrKinds, HasAttrCB); | 
|  | if (HasAttr) | 
|  | break; | 
|  | // The first position returned by the SubsumingPositionIterator is | 
|  | // always the position itself. If we ignore subsuming positions we | 
|  | // are done after the first iteration. | 
|  | if (IgnoreSubsumingPositions) | 
|  | break; | 
|  | Implied = true; | 
|  | } | 
|  | if (!HasAttr) { | 
|  | Implied = true; | 
|  | SmallVector<Attribute> Attrs; | 
|  | for (Attribute::AttrKind AK : AttrKinds) | 
|  | if (getAttrsFromAssumes(IRP, AK, Attrs)) { | 
|  | HasAttr = true; | 
|  | break; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Check if we should manifest the implied attribute kind at the IRP. | 
|  | if (ImpliedAttributeKind != Attribute::None && HasAttr && Implied) | 
|  | manifestAttrs(IRP, {Attribute::get(IRP.getAnchorValue().getContext(), | 
|  | ImpliedAttributeKind)}); | 
|  | return HasAttr; | 
|  | } | 
|  |  | 
|  | void Attributor::getAttrs(const IRPosition &IRP, | 
|  | ArrayRef<Attribute::AttrKind> AttrKinds, | 
|  | SmallVectorImpl<Attribute> &Attrs, | 
|  | bool IgnoreSubsumingPositions) { | 
|  | auto CollectAttrCB = [&](const Attribute::AttrKind &Kind, | 
|  | AttributeSet AttrSet, AttributeMask &, | 
|  | AttrBuilder &) { | 
|  | if (AttrSet.hasAttribute(Kind)) | 
|  | Attrs.push_back(AttrSet.getAttribute(Kind)); | 
|  | return false; | 
|  | }; | 
|  | for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) { | 
|  | updateAttrMap<Attribute::AttrKind>(EquivIRP, AttrKinds, CollectAttrCB); | 
|  | // The first position returned by the SubsumingPositionIterator is | 
|  | // always the position itself. If we ignore subsuming positions we | 
|  | // are done after the first iteration. | 
|  | if (IgnoreSubsumingPositions) | 
|  | break; | 
|  | } | 
|  | for (Attribute::AttrKind AK : AttrKinds) | 
|  | getAttrsFromAssumes(IRP, AK, Attrs); | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::removeAttrs(const IRPosition &IRP, | 
|  | ArrayRef<Attribute::AttrKind> AttrKinds) { | 
|  | auto RemoveAttrCB = [&](const Attribute::AttrKind &Kind, AttributeSet AttrSet, | 
|  | AttributeMask &AM, AttrBuilder &) { | 
|  | if (!AttrSet.hasAttribute(Kind)) | 
|  | return false; | 
|  | AM.addAttribute(Kind); | 
|  | return true; | 
|  | }; | 
|  | return updateAttrMap<Attribute::AttrKind>(IRP, AttrKinds, RemoveAttrCB); | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::removeAttrs(const IRPosition &IRP, | 
|  | ArrayRef<StringRef> Attrs) { | 
|  | auto RemoveAttrCB = [&](StringRef Attr, AttributeSet AttrSet, | 
|  | AttributeMask &AM, AttrBuilder &) -> bool { | 
|  | if (!AttrSet.hasAttribute(Attr)) | 
|  | return false; | 
|  | AM.addAttribute(Attr); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | return updateAttrMap<StringRef>(IRP, Attrs, RemoveAttrCB); | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::manifestAttrs(const IRPosition &IRP, | 
|  | ArrayRef<Attribute> Attrs, | 
|  | bool ForceReplace) { | 
|  | LLVMContext &Ctx = IRP.getAnchorValue().getContext(); | 
|  | auto AddAttrCB = [&](const Attribute &Attr, AttributeSet AttrSet, | 
|  | AttributeMask &, AttrBuilder &AB) { | 
|  | return addIfNotExistent(Ctx, Attr, AttrSet, ForceReplace, AB); | 
|  | }; | 
|  | return updateAttrMap<Attribute>(IRP, Attrs, AddAttrCB); | 
|  | } | 
|  |  | 
|  | const IRPosition IRPosition::EmptyKey(DenseMapInfo<void *>::getEmptyKey()); | 
|  | const IRPosition | 
|  | IRPosition::TombstoneKey(DenseMapInfo<void *>::getTombstoneKey()); | 
|  |  | 
|  | SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) { | 
|  | IRPositions.emplace_back(IRP); | 
|  |  | 
|  | // Helper to determine if operand bundles on a call site are benign or | 
|  | // potentially problematic. We handle only llvm.assume for now. | 
|  | auto CanIgnoreOperandBundles = [](const CallBase &CB) { | 
|  | return (isa<IntrinsicInst>(CB) && | 
|  | cast<IntrinsicInst>(CB).getIntrinsicID() == Intrinsic ::assume); | 
|  | }; | 
|  |  | 
|  | const auto *CB = dyn_cast<CallBase>(&IRP.getAnchorValue()); | 
|  | switch (IRP.getPositionKind()) { | 
|  | case IRPosition::IRP_INVALID: | 
|  | case IRPosition::IRP_FLOAT: | 
|  | case IRPosition::IRP_FUNCTION: | 
|  | return; | 
|  | case IRPosition::IRP_ARGUMENT: | 
|  | case IRPosition::IRP_RETURNED: | 
|  | IRPositions.emplace_back(IRPosition::function(*IRP.getAnchorScope())); | 
|  | return; | 
|  | case IRPosition::IRP_CALL_SITE: | 
|  | assert(CB && "Expected call site!"); | 
|  | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | //       in CallBase. | 
|  | if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) | 
|  | if (auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand())) | 
|  | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | return; | 
|  | case IRPosition::IRP_CALL_SITE_RETURNED: | 
|  | assert(CB && "Expected call site!"); | 
|  | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | //       in CallBase. | 
|  | if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) { | 
|  | if (auto *Callee = | 
|  | dyn_cast_if_present<Function>(CB->getCalledOperand())) { | 
|  | IRPositions.emplace_back(IRPosition::returned(*Callee)); | 
|  | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | for (const Argument &Arg : Callee->args()) | 
|  | if (Arg.hasReturnedAttr()) { | 
|  | IRPositions.emplace_back( | 
|  | IRPosition::callsite_argument(*CB, Arg.getArgNo())); | 
|  | IRPositions.emplace_back( | 
|  | IRPosition::value(*CB->getArgOperand(Arg.getArgNo()))); | 
|  | IRPositions.emplace_back(IRPosition::argument(Arg)); | 
|  | } | 
|  | } | 
|  | } | 
|  | IRPositions.emplace_back(IRPosition::callsite_function(*CB)); | 
|  | return; | 
|  | case IRPosition::IRP_CALL_SITE_ARGUMENT: { | 
|  | assert(CB && "Expected call site!"); | 
|  | // TODO: We need to look at the operand bundles similar to the redirection | 
|  | //       in CallBase. | 
|  | if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) { | 
|  | auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand()); | 
|  | if (Callee) { | 
|  | if (Argument *Arg = IRP.getAssociatedArgument()) | 
|  | IRPositions.emplace_back(IRPosition::argument(*Arg)); | 
|  | IRPositions.emplace_back(IRPosition::function(*Callee)); | 
|  | } | 
|  | } | 
|  | IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue())); | 
|  | return; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | void IRPosition::verify() { | 
|  | #ifdef EXPENSIVE_CHECKS | 
|  | switch (getPositionKind()) { | 
|  | case IRP_INVALID: | 
|  | assert((CBContext == nullptr) && | 
|  | "Invalid position must not have CallBaseContext!"); | 
|  | assert(!Enc.getOpaqueValue() && | 
|  | "Expected a nullptr for an invalid position!"); | 
|  | return; | 
|  | case IRP_FLOAT: | 
|  | assert((!isa<Argument>(&getAssociatedValue())) && | 
|  | "Expected specialized kind for argument values!"); | 
|  | return; | 
|  | case IRP_RETURNED: | 
|  | assert(isa<Function>(getAsValuePtr()) && | 
|  | "Expected function for a 'returned' position!"); | 
|  | assert(getAsValuePtr() == &getAssociatedValue() && | 
|  | "Associated value mismatch!"); | 
|  | return; | 
|  | case IRP_CALL_SITE_RETURNED: | 
|  | assert((CBContext == nullptr) && | 
|  | "'call site returned' position must not have CallBaseContext!"); | 
|  | assert((isa<CallBase>(getAsValuePtr())) && | 
|  | "Expected call base for 'call site returned' position!"); | 
|  | assert(getAsValuePtr() == &getAssociatedValue() && | 
|  | "Associated value mismatch!"); | 
|  | return; | 
|  | case IRP_CALL_SITE: | 
|  | assert((CBContext == nullptr) && | 
|  | "'call site function' position must not have CallBaseContext!"); | 
|  | assert((isa<CallBase>(getAsValuePtr())) && | 
|  | "Expected call base for 'call site function' position!"); | 
|  | assert(getAsValuePtr() == &getAssociatedValue() && | 
|  | "Associated value mismatch!"); | 
|  | return; | 
|  | case IRP_FUNCTION: | 
|  | assert(isa<Function>(getAsValuePtr()) && | 
|  | "Expected function for a 'function' position!"); | 
|  | assert(getAsValuePtr() == &getAssociatedValue() && | 
|  | "Associated value mismatch!"); | 
|  | return; | 
|  | case IRP_ARGUMENT: | 
|  | assert(isa<Argument>(getAsValuePtr()) && | 
|  | "Expected argument for a 'argument' position!"); | 
|  | assert(getAsValuePtr() == &getAssociatedValue() && | 
|  | "Associated value mismatch!"); | 
|  | return; | 
|  | case IRP_CALL_SITE_ARGUMENT: { | 
|  | assert((CBContext == nullptr) && | 
|  | "'call site argument' position must not have CallBaseContext!"); | 
|  | Use *U = getAsUsePtr(); | 
|  | (void)U; // Silence unused variable warning. | 
|  | assert(U && "Expected use for a 'call site argument' position!"); | 
|  | assert(isa<CallBase>(U->getUser()) && | 
|  | "Expected call base user for a 'call site argument' position!"); | 
|  | assert(cast<CallBase>(U->getUser())->isArgOperand(U) && | 
|  | "Expected call base argument operand for a 'call site argument' " | 
|  | "position"); | 
|  | assert(cast<CallBase>(U->getUser())->getArgOperandNo(U) == | 
|  | unsigned(getCallSiteArgNo()) && | 
|  | "Argument number mismatch!"); | 
|  | assert(U->get() == &getAssociatedValue() && "Associated value mismatch!"); | 
|  | return; | 
|  | } | 
|  | } | 
|  | #endif | 
|  | } | 
|  |  | 
|  | std::optional<Constant *> | 
|  | Attributor::getAssumedConstant(const IRPosition &IRP, | 
|  | const AbstractAttribute &AA, | 
|  | bool &UsedAssumedInformation) { | 
|  | // First check all callbacks provided by outside AAs. If any of them returns | 
|  | // a non-null value that is different from the associated value, or | 
|  | // std::nullopt, we assume it's simplified. | 
|  | for (auto &CB : SimplificationCallbacks.lookup(IRP)) { | 
|  | std::optional<Value *> SimplifiedV = CB(IRP, &AA, UsedAssumedInformation); | 
|  | if (!SimplifiedV) | 
|  | return std::nullopt; | 
|  | if (isa_and_nonnull<Constant>(*SimplifiedV)) | 
|  | return cast<Constant>(*SimplifiedV); | 
|  | return nullptr; | 
|  | } | 
|  | if (auto *C = dyn_cast<Constant>(&IRP.getAssociatedValue())) | 
|  | return C; | 
|  | SmallVector<AA::ValueAndContext> Values; | 
|  | if (getAssumedSimplifiedValues(IRP, &AA, Values, | 
|  | AA::ValueScope::Interprocedural, | 
|  | UsedAssumedInformation)) { | 
|  | if (Values.empty()) | 
|  | return std::nullopt; | 
|  | if (auto *C = dyn_cast_or_null<Constant>( | 
|  | AAPotentialValues::getSingleValue(*this, AA, IRP, Values))) | 
|  | return C; | 
|  | } | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | std::optional<Value *> Attributor::getAssumedSimplified( | 
|  | const IRPosition &IRP, const AbstractAttribute *AA, | 
|  | bool &UsedAssumedInformation, AA::ValueScope S) { | 
|  | // First check all callbacks provided by outside AAs. If any of them returns | 
|  | // a non-null value that is different from the associated value, or | 
|  | // std::nullopt, we assume it's simplified. | 
|  | for (auto &CB : SimplificationCallbacks.lookup(IRP)) | 
|  | return CB(IRP, AA, UsedAssumedInformation); | 
|  |  | 
|  | SmallVector<AA::ValueAndContext> Values; | 
|  | if (!getAssumedSimplifiedValues(IRP, AA, Values, S, UsedAssumedInformation)) | 
|  | return &IRP.getAssociatedValue(); | 
|  | if (Values.empty()) | 
|  | return std::nullopt; | 
|  | if (AA) | 
|  | if (Value *V = AAPotentialValues::getSingleValue(*this, *AA, IRP, Values)) | 
|  | return V; | 
|  | if (IRP.getPositionKind() == IRPosition::IRP_RETURNED || | 
|  | IRP.getPositionKind() == IRPosition::IRP_CALL_SITE_RETURNED) | 
|  | return nullptr; | 
|  | return &IRP.getAssociatedValue(); | 
|  | } | 
|  |  | 
|  | bool Attributor::getAssumedSimplifiedValues( | 
|  | const IRPosition &InitialIRP, const AbstractAttribute *AA, | 
|  | SmallVectorImpl<AA::ValueAndContext> &Values, AA::ValueScope S, | 
|  | bool &UsedAssumedInformation, bool RecurseForSelectAndPHI) { | 
|  | SmallPtrSet<Value *, 8> Seen; | 
|  | SmallVector<IRPosition, 8> Worklist; | 
|  | Worklist.push_back(InitialIRP); | 
|  | while (!Worklist.empty()) { | 
|  | const IRPosition &IRP = Worklist.pop_back_val(); | 
|  |  | 
|  | // First check all callbacks provided by outside AAs. If any of them returns | 
|  | // a non-null value that is different from the associated value, or | 
|  | // std::nullopt, we assume it's simplified. | 
|  | int NV = Values.size(); | 
|  | const auto &SimplificationCBs = SimplificationCallbacks.lookup(IRP); | 
|  | for (const auto &CB : SimplificationCBs) { | 
|  | std::optional<Value *> CBResult = CB(IRP, AA, UsedAssumedInformation); | 
|  | if (!CBResult.has_value()) | 
|  | continue; | 
|  | Value *V = *CBResult; | 
|  | if (!V) | 
|  | return false; | 
|  | if ((S & AA::ValueScope::Interprocedural) || | 
|  | AA::isValidInScope(*V, IRP.getAnchorScope())) | 
|  | Values.push_back(AA::ValueAndContext{*V, nullptr}); | 
|  | else | 
|  | return false; | 
|  | } | 
|  | if (SimplificationCBs.empty()) { | 
|  | // If no high-level/outside simplification occurred, use | 
|  | // AAPotentialValues. | 
|  | const auto *PotentialValuesAA = | 
|  | getOrCreateAAFor<AAPotentialValues>(IRP, AA, DepClassTy::OPTIONAL); | 
|  | if (PotentialValuesAA && | 
|  | PotentialValuesAA->getAssumedSimplifiedValues(*this, Values, S)) { | 
|  | UsedAssumedInformation |= !PotentialValuesAA->isAtFixpoint(); | 
|  | } else if (IRP.getPositionKind() != IRPosition::IRP_RETURNED) { | 
|  | Values.push_back({IRP.getAssociatedValue(), IRP.getCtxI()}); | 
|  | } else { | 
|  | // TODO: We could visit all returns and add the operands. | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (!RecurseForSelectAndPHI) | 
|  | break; | 
|  |  | 
|  | for (int I = NV, E = Values.size(); I < E; ++I) { | 
|  | Value *V = Values[I].getValue(); | 
|  | if (!isa<PHINode>(V) && !isa<SelectInst>(V)) | 
|  | continue; | 
|  | if (!Seen.insert(V).second) | 
|  | continue; | 
|  | // Move the last element to this slot. | 
|  | Values[I] = Values[E - 1]; | 
|  | // Eliminate the last slot, adjust the indices. | 
|  | Values.pop_back(); | 
|  | --E; | 
|  | --I; | 
|  | // Add a new value (select or phi) to the worklist. | 
|  | Worklist.push_back(IRPosition::value(*V)); | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | std::optional<Value *> Attributor::translateArgumentToCallSiteContent( | 
|  | std::optional<Value *> V, CallBase &CB, const AbstractAttribute &AA, | 
|  | bool &UsedAssumedInformation) { | 
|  | if (!V) | 
|  | return V; | 
|  | if (*V == nullptr || isa<Constant>(*V)) | 
|  | return V; | 
|  | if (auto *Arg = dyn_cast<Argument>(*V)) | 
|  | if (CB.getCalledOperand() == Arg->getParent() && | 
|  | CB.arg_size() > Arg->getArgNo()) | 
|  | if (!Arg->hasPointeeInMemoryValueAttr()) | 
|  | return getAssumedSimplified( | 
|  | IRPosition::callsite_argument(CB, Arg->getArgNo()), AA, | 
|  | UsedAssumedInformation, AA::Intraprocedural); | 
|  | return nullptr; | 
|  | } | 
|  |  | 
|  | Attributor::~Attributor() { | 
|  | // The abstract attributes are allocated via the BumpPtrAllocator Allocator, | 
|  | // thus we cannot delete them. We can, and want to, destruct them though. | 
|  | for (auto &It : AAMap) { | 
|  | AbstractAttribute *AA = It.getSecond(); | 
|  | AA->~AbstractAttribute(); | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Attributor::isAssumedDead(const AbstractAttribute &AA, | 
|  | const AAIsDead *FnLivenessAA, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, DepClassTy DepClass) { | 
|  | if (!Configuration.UseLiveness) | 
|  | return false; | 
|  | const IRPosition &IRP = AA.getIRPosition(); | 
|  | if (!Functions.count(IRP.getAnchorScope())) | 
|  | return false; | 
|  | return isAssumedDead(IRP, &AA, FnLivenessAA, UsedAssumedInformation, | 
|  | CheckBBLivenessOnly, DepClass); | 
|  | } | 
|  |  | 
|  | bool Attributor::isAssumedDead(const Use &U, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | const AAIsDead *FnLivenessAA, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, DepClassTy DepClass) { | 
|  | if (!Configuration.UseLiveness) | 
|  | return false; | 
|  | Instruction *UserI = dyn_cast<Instruction>(U.getUser()); | 
|  | if (!UserI) | 
|  | return isAssumedDead(IRPosition::value(*U.get()), QueryingAA, FnLivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, DepClass); | 
|  |  | 
|  | if (auto *CB = dyn_cast<CallBase>(UserI)) { | 
|  | // For call site argument uses we can check if the argument is | 
|  | // unused/dead. | 
|  | if (CB->isArgOperand(&U)) { | 
|  | const IRPosition &CSArgPos = | 
|  | IRPosition::callsite_argument(*CB, CB->getArgOperandNo(&U)); | 
|  | return isAssumedDead(CSArgPos, QueryingAA, FnLivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, | 
|  | DepClass); | 
|  | } | 
|  | } else if (ReturnInst *RI = dyn_cast<ReturnInst>(UserI)) { | 
|  | const IRPosition &RetPos = IRPosition::returned(*RI->getFunction()); | 
|  | return isAssumedDead(RetPos, QueryingAA, FnLivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, DepClass); | 
|  | } else if (PHINode *PHI = dyn_cast<PHINode>(UserI)) { | 
|  | BasicBlock *IncomingBB = PHI->getIncomingBlock(U); | 
|  | return isAssumedDead(*IncomingBB->getTerminator(), QueryingAA, FnLivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, DepClass); | 
|  | } else if (StoreInst *SI = dyn_cast<StoreInst>(UserI)) { | 
|  | if (!CheckBBLivenessOnly && SI->getPointerOperand() != U.get()) { | 
|  | const IRPosition IRP = IRPosition::inst(*SI); | 
|  | const AAIsDead *IsDeadAA = | 
|  | getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE); | 
|  | if (IsDeadAA && IsDeadAA->isRemovableStore()) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*IsDeadAA, *QueryingAA, DepClass); | 
|  | if (!IsDeadAA->isKnown(AAIsDead::IS_REMOVABLE)) | 
|  | UsedAssumedInformation = true; | 
|  | return true; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | return isAssumedDead(IRPosition::inst(*UserI), QueryingAA, FnLivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, DepClass); | 
|  | } | 
|  |  | 
|  | bool Attributor::isAssumedDead(const Instruction &I, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | const AAIsDead *FnLivenessAA, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, DepClassTy DepClass, | 
|  | bool CheckForDeadStore) { | 
|  | if (!Configuration.UseLiveness) | 
|  | return false; | 
|  | const IRPosition::CallBaseContext *CBCtx = | 
|  | QueryingAA ? QueryingAA->getCallBaseContext() : nullptr; | 
|  |  | 
|  | if (ManifestAddedBlocks.contains(I.getParent())) | 
|  | return false; | 
|  |  | 
|  | const Function &F = *I.getFunction(); | 
|  | if (!FnLivenessAA || FnLivenessAA->getAnchorScope() != &F) | 
|  | FnLivenessAA = getOrCreateAAFor<AAIsDead>(IRPosition::function(F, CBCtx), | 
|  | QueryingAA, DepClassTy::NONE); | 
|  |  | 
|  | // Don't use recursive reasoning. | 
|  | if (!FnLivenessAA || QueryingAA == FnLivenessAA) | 
|  | return false; | 
|  |  | 
|  | // If we have a context instruction and a liveness AA we use it. | 
|  | if (CheckBBLivenessOnly ? FnLivenessAA->isAssumedDead(I.getParent()) | 
|  | : FnLivenessAA->isAssumedDead(&I)) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*FnLivenessAA, *QueryingAA, DepClass); | 
|  | if (!FnLivenessAA->isKnownDead(&I)) | 
|  | UsedAssumedInformation = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (CheckBBLivenessOnly) | 
|  | return false; | 
|  |  | 
|  | const IRPosition IRP = IRPosition::inst(I, CBCtx); | 
|  | const AAIsDead *IsDeadAA = | 
|  | getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE); | 
|  |  | 
|  | // Don't use recursive reasoning. | 
|  | if (!IsDeadAA || QueryingAA == IsDeadAA) | 
|  | return false; | 
|  |  | 
|  | if (IsDeadAA->isAssumedDead()) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*IsDeadAA, *QueryingAA, DepClass); | 
|  | if (!IsDeadAA->isKnownDead()) | 
|  | UsedAssumedInformation = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | if (CheckForDeadStore && isa<StoreInst>(I) && IsDeadAA->isRemovableStore()) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*IsDeadAA, *QueryingAA, DepClass); | 
|  | if (!IsDeadAA->isKnownDead()) | 
|  | UsedAssumedInformation = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Attributor::isAssumedDead(const IRPosition &IRP, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | const AAIsDead *FnLivenessAA, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, DepClassTy DepClass) { | 
|  | if (!Configuration.UseLiveness) | 
|  | return false; | 
|  | // Don't check liveness for constants, e.g. functions, used as (floating) | 
|  | // values since the context instruction and such is here meaningless. | 
|  | if (IRP.getPositionKind() == IRPosition::IRP_FLOAT && | 
|  | isa<Constant>(IRP.getAssociatedValue())) { | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Instruction *CtxI = IRP.getCtxI(); | 
|  | if (CtxI && | 
|  | isAssumedDead(*CtxI, QueryingAA, FnLivenessAA, UsedAssumedInformation, | 
|  | /* CheckBBLivenessOnly */ true, | 
|  | CheckBBLivenessOnly ? DepClass : DepClassTy::OPTIONAL)) | 
|  | return true; | 
|  |  | 
|  | if (CheckBBLivenessOnly) | 
|  | return false; | 
|  |  | 
|  | // If we haven't succeeded we query the specific liveness info for the IRP. | 
|  | const AAIsDead *IsDeadAA; | 
|  | if (IRP.getPositionKind() == IRPosition::IRP_CALL_SITE) | 
|  | IsDeadAA = getOrCreateAAFor<AAIsDead>( | 
|  | IRPosition::callsite_returned(cast<CallBase>(IRP.getAssociatedValue())), | 
|  | QueryingAA, DepClassTy::NONE); | 
|  | else | 
|  | IsDeadAA = getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE); | 
|  |  | 
|  | // Don't use recursive reasoning. | 
|  | if (!IsDeadAA || QueryingAA == IsDeadAA) | 
|  | return false; | 
|  |  | 
|  | if (IsDeadAA->isAssumedDead()) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*IsDeadAA, *QueryingAA, DepClass); | 
|  | if (!IsDeadAA->isKnownDead()) | 
|  | UsedAssumedInformation = true; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Attributor::isAssumedDead(const BasicBlock &BB, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | const AAIsDead *FnLivenessAA, | 
|  | DepClassTy DepClass) { | 
|  | if (!Configuration.UseLiveness) | 
|  | return false; | 
|  | const Function &F = *BB.getParent(); | 
|  | if (!FnLivenessAA || FnLivenessAA->getAnchorScope() != &F) | 
|  | FnLivenessAA = getOrCreateAAFor<AAIsDead>(IRPosition::function(F), | 
|  | QueryingAA, DepClassTy::NONE); | 
|  |  | 
|  | // Don't use recursive reasoning. | 
|  | if (!FnLivenessAA || QueryingAA == FnLivenessAA) | 
|  | return false; | 
|  |  | 
|  | if (FnLivenessAA->isAssumedDead(&BB)) { | 
|  | if (QueryingAA) | 
|  | recordDependence(*FnLivenessAA, *QueryingAA, DepClass); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | return false; | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllCallees( | 
|  | function_ref<bool(ArrayRef<const Function *>)> Pred, | 
|  | const AbstractAttribute &QueryingAA, const CallBase &CB) { | 
|  | if (const Function *Callee = dyn_cast<Function>(CB.getCalledOperand())) | 
|  | return Pred(Callee); | 
|  |  | 
|  | const auto *CallEdgesAA = getAAFor<AACallEdges>( | 
|  | QueryingAA, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL); | 
|  | if (!CallEdgesAA || CallEdgesAA->hasUnknownCallee()) | 
|  | return false; | 
|  |  | 
|  | const auto &Callees = CallEdgesAA->getOptimisticEdges(); | 
|  | return Pred(Callees.getArrayRef()); | 
|  | } | 
|  |  | 
|  | bool canMarkAsVisited(const User *Usr) { | 
|  | return isa<PHINode>(Usr) || !isa<Instruction>(Usr); | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllUses( | 
|  | function_ref<bool(const Use &, bool &)> Pred, | 
|  | const AbstractAttribute &QueryingAA, const Value &V, | 
|  | bool CheckBBLivenessOnly, DepClassTy LivenessDepClass, | 
|  | bool IgnoreDroppableUses, | 
|  | function_ref<bool(const Use &OldU, const Use &NewU)> EquivalentUseCB) { | 
|  |  | 
|  | // Check virtual uses first. | 
|  | for (VirtualUseCallbackTy &CB : VirtualUseCallbacks.lookup(&V)) | 
|  | if (!CB(*this, &QueryingAA)) | 
|  | return false; | 
|  |  | 
|  | if (isa<ConstantData>(V)) | 
|  | return false; | 
|  |  | 
|  | // Check the trivial case first as it catches void values. | 
|  | if (V.use_empty()) | 
|  | return true; | 
|  |  | 
|  | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | SmallVector<const Use *, 16> Worklist; | 
|  | SmallPtrSet<const Use *, 16> Visited; | 
|  |  | 
|  | auto AddUsers = [&](const Value &V, const Use *OldUse) { | 
|  | for (const Use &UU : V.uses()) { | 
|  | if (OldUse && EquivalentUseCB && !EquivalentUseCB(*OldUse, UU)) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Potential copy was " | 
|  | "rejected by the equivalence call back: " | 
|  | << *UU << "!\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | Worklist.push_back(&UU); | 
|  | } | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | AddUsers(V, /* OldUse */ nullptr); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Got " << Worklist.size() | 
|  | << " initial uses to check\n"); | 
|  |  | 
|  | const Function *ScopeFn = IRP.getAnchorScope(); | 
|  | const auto *LivenessAA = | 
|  | ScopeFn ? getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*ScopeFn), | 
|  | DepClassTy::NONE) | 
|  | : nullptr; | 
|  |  | 
|  | while (!Worklist.empty()) { | 
|  | const Use *U = Worklist.pop_back_val(); | 
|  | if (canMarkAsVisited(U->getUser()) && !Visited.insert(U).second) | 
|  | continue; | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, { | 
|  | if (auto *Fn = dyn_cast<Function>(U->getUser())) | 
|  | dbgs() << "[Attributor] Check use: " << **U << " in " << Fn->getName() | 
|  | << "\n"; | 
|  | else | 
|  | dbgs() << "[Attributor] Check use: " << **U << " in " << *U->getUser() | 
|  | << "\n"; | 
|  | }); | 
|  | bool UsedAssumedInformation = false; | 
|  | if (isAssumedDead(*U, &QueryingAA, LivenessAA, UsedAssumedInformation, | 
|  | CheckBBLivenessOnly, LivenessDepClass)) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << "[Attributor] Dead use, skip!\n"); | 
|  | continue; | 
|  | } | 
|  | if (IgnoreDroppableUses && U->getUser()->isDroppable()) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << "[Attributor] Droppable user, skip!\n"); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (auto *SI = dyn_cast<StoreInst>(U->getUser())) { | 
|  | if (&SI->getOperandUse(0) == U) { | 
|  | if (!Visited.insert(U).second) | 
|  | continue; | 
|  | SmallSetVector<Value *, 4> PotentialCopies; | 
|  | if (AA::getPotentialCopiesOfStoredValue( | 
|  | *this, *SI, PotentialCopies, QueryingAA, UsedAssumedInformation, | 
|  | /* OnlyExact */ true)) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() | 
|  | << "[Attributor] Value is stored, continue with " | 
|  | << PotentialCopies.size() | 
|  | << " potential copies instead!\n"); | 
|  | for (Value *PotentialCopy : PotentialCopies) | 
|  | if (!AddUsers(*PotentialCopy, U)) | 
|  | return false; | 
|  | continue; | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | bool Follow = false; | 
|  | if (!Pred(*U, Follow)) | 
|  | return false; | 
|  | if (!Follow) | 
|  | continue; | 
|  |  | 
|  | User &Usr = *U->getUser(); | 
|  | AddUsers(Usr, /* OldUse */ nullptr); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | bool RequireAllCallSites, | 
|  | bool &UsedAssumedInformation) { | 
|  | // We can try to determine information from | 
|  | // the call sites. However, this is only possible all call sites are known, | 
|  | // hence the function has internal linkage. | 
|  | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
|  | if (!AssociatedFunction) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] No function associated with " << IRP | 
|  | << "\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return checkForAllCallSites(Pred, *AssociatedFunction, RequireAllCallSites, | 
|  | &QueryingAA, UsedAssumedInformation); | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred, | 
|  | const Function &Fn, | 
|  | bool RequireAllCallSites, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckPotentiallyDead) { | 
|  | if (RequireAllCallSites && !Fn.hasLocalLinkage()) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() | 
|  | << "[Attributor] Function " << Fn.getName() | 
|  | << " has no internal linkage, hence not all call sites are known\n"); | 
|  | return false; | 
|  | } | 
|  | // Check virtual uses first. | 
|  | for (VirtualUseCallbackTy &CB : VirtualUseCallbacks.lookup(&Fn)) | 
|  | if (!CB(*this, QueryingAA)) | 
|  | return false; | 
|  |  | 
|  | SmallVector<const Use *, 8> Uses(make_pointer_range(Fn.uses())); | 
|  | for (unsigned u = 0; u < Uses.size(); ++u) { | 
|  | const Use &U = *Uses[u]; | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, { | 
|  | if (auto *Fn = dyn_cast<Function>(U)) | 
|  | dbgs() << "[Attributor] Check use: " << Fn->getName() << " in " | 
|  | << *U.getUser() << "\n"; | 
|  | else | 
|  | dbgs() << "[Attributor] Check use: " << *U << " in " << *U.getUser() | 
|  | << "\n"; | 
|  | }); | 
|  | if (!CheckPotentiallyDead && | 
|  | isAssumedDead(U, QueryingAA, nullptr, UsedAssumedInformation, | 
|  | /* CheckBBLivenessOnly */ true)) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << "[Attributor] Dead use, skip!\n"); | 
|  | continue; | 
|  | } | 
|  | if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) { | 
|  | if (CE->isCast() && CE->getType()->isPointerTy()) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, { | 
|  | dbgs() << "[Attributor] Use, is constant cast expression, add " | 
|  | << CE->getNumUses() << " uses of that expression instead!\n"; | 
|  | }); | 
|  | for (const Use &CEU : CE->uses()) | 
|  | Uses.push_back(&CEU); | 
|  | continue; | 
|  | } | 
|  | } | 
|  |  | 
|  | AbstractCallSite ACS(&U); | 
|  | if (!ACS) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Function " << Fn.getName() | 
|  | << " has non call site use " << *U.get() << " in " | 
|  | << *U.getUser() << "\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | const Use *EffectiveUse = | 
|  | ACS.isCallbackCall() ? &ACS.getCalleeUseForCallback() : &U; | 
|  | if (!ACS.isCallee(EffectiveUse)) { | 
|  | if (!RequireAllCallSites) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] User " << *EffectiveUse->getUser() | 
|  | << " is not a call of " << Fn.getName() | 
|  | << ", skip use\n"); | 
|  | continue; | 
|  | } | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] User " << *EffectiveUse->getUser() | 
|  | << " is an invalid use of " << Fn.getName() << "\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Make sure the arguments that can be matched between the call site and the | 
|  | // callee argee on their type. It is unlikely they do not and it doesn't | 
|  | // make sense for all attributes to know/care about this. | 
|  | assert(&Fn == ACS.getCalledFunction() && "Expected known callee"); | 
|  | unsigned MinArgsParams = | 
|  | std::min(size_t(ACS.getNumArgOperands()), Fn.arg_size()); | 
|  | for (unsigned u = 0; u < MinArgsParams; ++u) { | 
|  | Value *CSArgOp = ACS.getCallArgOperand(u); | 
|  | if (CSArgOp && Fn.getArg(u)->getType() != CSArgOp->getType()) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "[Attributor] Call site / callee argument type mismatch [" | 
|  | << u << "@" << Fn.getName() << ": " | 
|  | << *Fn.getArg(u)->getType() << " vs. " | 
|  | << *ACS.getCallArgOperand(u)->getType() << "\n"); | 
|  | return false; | 
|  | } | 
|  | } | 
|  |  | 
|  | if (Pred(ACS)) | 
|  | continue; | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Call site callback failed for " | 
|  | << *ACS.getInstruction() << "\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::shouldPropagateCallBaseContext(const IRPosition &IRP) { | 
|  | // TODO: Maintain a cache of Values that are | 
|  | // on the pathway from a Argument to a Instruction that would effect the | 
|  | // liveness/return state etc. | 
|  | return EnableCallSiteSpecific; | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllReturnedValues(function_ref<bool(Value &)> Pred, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | AA::ValueScope S, | 
|  | bool RecurseForSelectAndPHI) { | 
|  |  | 
|  | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
|  | if (!AssociatedFunction) | 
|  | return false; | 
|  |  | 
|  | bool UsedAssumedInformation = false; | 
|  | SmallVector<AA::ValueAndContext> Values; | 
|  | if (!getAssumedSimplifiedValues( | 
|  | IRPosition::returned(*AssociatedFunction), &QueryingAA, Values, S, | 
|  | UsedAssumedInformation, RecurseForSelectAndPHI)) | 
|  | return false; | 
|  |  | 
|  | return llvm::all_of(Values, [&](const AA::ValueAndContext &VAC) { | 
|  | return Pred(*VAC.getValue()); | 
|  | }); | 
|  | } | 
|  |  | 
|  | static bool checkForAllInstructionsImpl( | 
|  | Attributor *A, InformationCache::OpcodeInstMapTy &OpcodeInstMap, | 
|  | function_ref<bool(Instruction &)> Pred, const AbstractAttribute *QueryingAA, | 
|  | const AAIsDead *LivenessAA, ArrayRef<unsigned> Opcodes, | 
|  | bool &UsedAssumedInformation, bool CheckBBLivenessOnly = false, | 
|  | bool CheckPotentiallyDead = false) { | 
|  | for (unsigned Opcode : Opcodes) { | 
|  | // Check if we have instructions with this opcode at all first. | 
|  | auto *Insts = OpcodeInstMap.lookup(Opcode); | 
|  | if (!Insts) | 
|  | continue; | 
|  |  | 
|  | for (Instruction *I : *Insts) { | 
|  | // Skip dead instructions. | 
|  | if (A && !CheckPotentiallyDead && | 
|  | A->isAssumedDead(IRPosition::inst(*I), QueryingAA, LivenessAA, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly)) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << "[Attributor] Instruction " << *I | 
|  | << " is potentially dead, skip!\n";); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | if (!Pred(*I)) | 
|  | return false; | 
|  | } | 
|  | } | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllInstructions(function_ref<bool(Instruction &)> Pred, | 
|  | const Function *Fn, | 
|  | const AbstractAttribute *QueryingAA, | 
|  | ArrayRef<unsigned> Opcodes, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, | 
|  | bool CheckPotentiallyDead) { | 
|  | // Since we need to provide instructions we have to have an exact definition. | 
|  | if (!Fn || Fn->isDeclaration()) | 
|  | return false; | 
|  |  | 
|  | const IRPosition &QueryIRP = IRPosition::function(*Fn); | 
|  | const auto *LivenessAA = | 
|  | CheckPotentiallyDead && QueryingAA | 
|  | ? (getAAFor<AAIsDead>(*QueryingAA, QueryIRP, DepClassTy::NONE)) | 
|  | : nullptr; | 
|  |  | 
|  | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn); | 
|  | if (!checkForAllInstructionsImpl(this, OpcodeInstMap, Pred, QueryingAA, | 
|  | LivenessAA, Opcodes, UsedAssumedInformation, | 
|  | CheckBBLivenessOnly, CheckPotentiallyDead)) | 
|  | return false; | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllInstructions(function_ref<bool(Instruction &)> Pred, | 
|  | const AbstractAttribute &QueryingAA, | 
|  | ArrayRef<unsigned> Opcodes, | 
|  | bool &UsedAssumedInformation, | 
|  | bool CheckBBLivenessOnly, | 
|  | bool CheckPotentiallyDead) { | 
|  | const IRPosition &IRP = QueryingAA.getIRPosition(); | 
|  | const Function *AssociatedFunction = IRP.getAssociatedFunction(); | 
|  | return checkForAllInstructions(Pred, AssociatedFunction, &QueryingAA, Opcodes, | 
|  | UsedAssumedInformation, CheckBBLivenessOnly, | 
|  | CheckPotentiallyDead); | 
|  | } | 
|  |  | 
|  | bool Attributor::checkForAllReadWriteInstructions( | 
|  | function_ref<bool(Instruction &)> Pred, AbstractAttribute &QueryingAA, | 
|  | bool &UsedAssumedInformation) { | 
|  | TimeTraceScope TS("checkForAllReadWriteInstructions"); | 
|  |  | 
|  | const Function *AssociatedFunction = | 
|  | QueryingAA.getIRPosition().getAssociatedFunction(); | 
|  | if (!AssociatedFunction) | 
|  | return false; | 
|  |  | 
|  | const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction); | 
|  | const auto *LivenessAA = | 
|  | getAAFor<AAIsDead>(QueryingAA, QueryIRP, DepClassTy::NONE); | 
|  |  | 
|  | for (Instruction *I : | 
|  | InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) { | 
|  | // Skip dead instructions. | 
|  | if (isAssumedDead(IRPosition::inst(*I), &QueryingAA, LivenessAA, | 
|  | UsedAssumedInformation)) | 
|  | continue; | 
|  |  | 
|  | if (!Pred(*I)) | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | void Attributor::runTillFixpoint() { | 
|  | TimeTraceScope TimeScope("Attributor::runTillFixpoint"); | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized " | 
|  | << DG.SyntheticRoot.Deps.size() | 
|  | << " abstract attributes.\n"); | 
|  |  | 
|  | // Now that all abstract attributes are collected and initialized we start | 
|  | // the abstract analysis. | 
|  |  | 
|  | unsigned IterationCounter = 1; | 
|  | unsigned MaxIterations = | 
|  | Configuration.MaxFixpointIterations.value_or(SetFixpointIterations); | 
|  |  | 
|  | SmallVector<AbstractAttribute *, 32> ChangedAAs; | 
|  | SetVector<AbstractAttribute *> Worklist, InvalidAAs; | 
|  | Worklist.insert_range(DG.SyntheticRoot); | 
|  |  | 
|  | do { | 
|  | // Remember the size to determine new attributes. | 
|  | size_t NumAAs = DG.SyntheticRoot.Deps.size(); | 
|  | LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter | 
|  | << ", Worklist size: " << Worklist.size() << "\n"); | 
|  |  | 
|  | // For invalid AAs we can fix dependent AAs that have a required dependence, | 
|  | // thereby folding long dependence chains in a single step without the need | 
|  | // to run updates. | 
|  | for (unsigned u = 0; u < InvalidAAs.size(); ++u) { | 
|  | AbstractAttribute *InvalidAA = InvalidAAs[u]; | 
|  |  | 
|  | // Check the dependences to fast track invalidation. | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << "[Attributor] InvalidAA: " << *InvalidAA | 
|  | << " has " << InvalidAA->Deps.size() | 
|  | << " required & optional dependences\n"); | 
|  | for (auto &DepIt : InvalidAA->Deps) { | 
|  | AbstractAttribute *DepAA = cast<AbstractAttribute>(DepIt.getPointer()); | 
|  | if (DepIt.getInt() == unsigned(DepClassTy::OPTIONAL)) { | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, | 
|  | dbgs() << " - recompute: " << *DepAA); | 
|  | Worklist.insert(DepAA); | 
|  | continue; | 
|  | } | 
|  | DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, dbgs() | 
|  | << " - invalidate: " << *DepAA); | 
|  | DepAA->getState().indicatePessimisticFixpoint(); | 
|  | assert(DepAA->getState().isAtFixpoint() && "Expected fixpoint state!"); | 
|  | if (!DepAA->getState().isValidState()) | 
|  | InvalidAAs.insert(DepAA); | 
|  | else | 
|  | ChangedAAs.push_back(DepAA); | 
|  | } | 
|  | InvalidAA->Deps.clear(); | 
|  | } | 
|  |  | 
|  | // Add all abstract attributes that are potentially dependent on one that | 
|  | // changed to the work list. | 
|  | for (AbstractAttribute *ChangedAA : ChangedAAs) { | 
|  | for (auto &DepIt : ChangedAA->Deps) | 
|  | Worklist.insert(cast<AbstractAttribute>(DepIt.getPointer())); | 
|  | ChangedAA->Deps.clear(); | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] #Iteration: " << IterationCounter | 
|  | << ", Worklist+Dependent size: " << Worklist.size() | 
|  | << "\n"); | 
|  |  | 
|  | // Reset the changed and invalid set. | 
|  | ChangedAAs.clear(); | 
|  | InvalidAAs.clear(); | 
|  |  | 
|  | // Update all abstract attribute in the work list and record the ones that | 
|  | // changed. | 
|  | for (AbstractAttribute *AA : Worklist) { | 
|  | const auto &AAState = AA->getState(); | 
|  | if (!AAState.isAtFixpoint()) | 
|  | if (updateAA(*AA) == ChangeStatus::CHANGED) | 
|  | ChangedAAs.push_back(AA); | 
|  |  | 
|  | // Use the InvalidAAs vector to propagate invalid states fast transitively | 
|  | // without requiring updates. | 
|  | if (!AAState.isValidState()) | 
|  | InvalidAAs.insert(AA); | 
|  | } | 
|  |  | 
|  | // Add attributes to the changed set if they have been created in the last | 
|  | // iteration. | 
|  | ChangedAAs.append(DG.SyntheticRoot.begin() + NumAAs, | 
|  | DG.SyntheticRoot.end()); | 
|  |  | 
|  | // Reset the work list and repopulate with the changed abstract attributes. | 
|  | // Note that dependent ones are added above. | 
|  | Worklist.clear(); | 
|  | Worklist.insert_range(ChangedAAs); | 
|  | Worklist.insert_range(QueryAAsAwaitingUpdate); | 
|  | QueryAAsAwaitingUpdate.clear(); | 
|  |  | 
|  | } while (!Worklist.empty() && (IterationCounter++ < MaxIterations)); | 
|  |  | 
|  | if (IterationCounter > MaxIterations && !Functions.empty()) { | 
|  | auto Remark = [&](OptimizationRemarkMissed ORM) { | 
|  | return ORM << "Attributor did not reach a fixpoint after " | 
|  | << ore::NV("Iterations", MaxIterations) << " iterations."; | 
|  | }; | 
|  | Function *F = Functions.front(); | 
|  | emitRemark<OptimizationRemarkMissed>(F, "FixedPoint", Remark); | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: " | 
|  | << IterationCounter << "/" << MaxIterations | 
|  | << " iterations\n"); | 
|  |  | 
|  | // Reset abstract arguments not settled in a sound fixpoint by now. This | 
|  | // happens when we stopped the fixpoint iteration early. Note that only the | 
|  | // ones marked as "changed" *and* the ones transitively depending on them | 
|  | // need to be reverted to a pessimistic state. Others might not be in a | 
|  | // fixpoint state but we can use the optimistic results for them anyway. | 
|  | SmallPtrSet<AbstractAttribute *, 32> Visited; | 
|  | for (unsigned u = 0; u < ChangedAAs.size(); u++) { | 
|  | AbstractAttribute *ChangedAA = ChangedAAs[u]; | 
|  | if (!Visited.insert(ChangedAA).second) | 
|  | continue; | 
|  |  | 
|  | AbstractState &State = ChangedAA->getState(); | 
|  | if (!State.isAtFixpoint()) { | 
|  | State.indicatePessimisticFixpoint(); | 
|  |  | 
|  | NumAttributesTimedOut++; | 
|  | } | 
|  |  | 
|  | for (auto &DepIt : ChangedAA->Deps) | 
|  | ChangedAAs.push_back(cast<AbstractAttribute>(DepIt.getPointer())); | 
|  | ChangedAA->Deps.clear(); | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG({ | 
|  | if (!Visited.empty()) | 
|  | dbgs() << "\n[Attributor] Finalized " << Visited.size() | 
|  | << " abstract attributes.\n"; | 
|  | }); | 
|  | } | 
|  |  | 
|  | void Attributor::registerForUpdate(AbstractAttribute &AA) { | 
|  | assert(AA.isQueryAA() && | 
|  | "Non-query AAs should not be required to register for updates!"); | 
|  | QueryAAsAwaitingUpdate.insert(&AA); | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::manifestAttributes() { | 
|  | TimeTraceScope TimeScope("Attributor::manifestAttributes"); | 
|  | size_t NumFinalAAs = DG.SyntheticRoot.Deps.size(); | 
|  |  | 
|  | unsigned NumManifested = 0; | 
|  | unsigned NumAtFixpoint = 0; | 
|  | ChangeStatus ManifestChange = ChangeStatus::UNCHANGED; | 
|  | for (auto &DepAA : DG.SyntheticRoot.Deps) { | 
|  | AbstractAttribute *AA = cast<AbstractAttribute>(DepAA.getPointer()); | 
|  | AbstractState &State = AA->getState(); | 
|  |  | 
|  | // If there is not already a fixpoint reached, we can now take the | 
|  | // optimistic state. This is correct because we enforced a pessimistic one | 
|  | // on abstract attributes that were transitively dependent on a changed one | 
|  | // already above. | 
|  | if (!State.isAtFixpoint()) | 
|  | State.indicateOptimisticFixpoint(); | 
|  |  | 
|  | // We must not manifest Attributes that use Callbase info. | 
|  | if (AA->hasCallBaseContext()) | 
|  | continue; | 
|  | // If the state is invalid, we do not try to manifest it. | 
|  | if (!State.isValidState()) | 
|  | continue; | 
|  |  | 
|  | if (AA->getCtxI() && !isRunOn(*AA->getAnchorScope())) | 
|  | continue; | 
|  |  | 
|  | // Skip dead code. | 
|  | bool UsedAssumedInformation = false; | 
|  | if (isAssumedDead(*AA, nullptr, UsedAssumedInformation, | 
|  | /* CheckBBLivenessOnly */ true)) | 
|  | continue; | 
|  | // Check if the manifest debug counter that allows skipping manifestation of | 
|  | // AAs | 
|  | if (!DebugCounter::shouldExecute(ManifestDBGCounter)) | 
|  | continue; | 
|  | // Manifest the state and record if we changed the IR. | 
|  | ChangeStatus LocalChange = AA->manifest(*this); | 
|  | if (LocalChange == ChangeStatus::CHANGED && AreStatisticsEnabled()) | 
|  | AA->trackStatistics(); | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Manifest " << LocalChange << " : " << *AA | 
|  | << "\n"); | 
|  |  | 
|  | ManifestChange = ManifestChange | LocalChange; | 
|  |  | 
|  | NumAtFixpoint++; | 
|  | NumManifested += (LocalChange == ChangeStatus::CHANGED); | 
|  | } | 
|  |  | 
|  | (void)NumManifested; | 
|  | (void)NumAtFixpoint; | 
|  | LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested | 
|  | << " arguments while " << NumAtFixpoint | 
|  | << " were in a valid fixpoint state\n"); | 
|  |  | 
|  | NumAttributesManifested += NumManifested; | 
|  | NumAttributesValidFixpoint += NumAtFixpoint; | 
|  |  | 
|  | (void)NumFinalAAs; | 
|  | if (NumFinalAAs != DG.SyntheticRoot.Deps.size()) { | 
|  | auto DepIt = DG.SyntheticRoot.Deps.begin(); | 
|  | for (unsigned u = 0; u < NumFinalAAs; ++u) | 
|  | ++DepIt; | 
|  | for (unsigned u = NumFinalAAs; u < DG.SyntheticRoot.Deps.size(); | 
|  | ++u, ++DepIt) { | 
|  | errs() << "Unexpected abstract attribute: " | 
|  | << cast<AbstractAttribute>(DepIt->getPointer()) << " :: " | 
|  | << cast<AbstractAttribute>(DepIt->getPointer()) | 
|  | ->getIRPosition() | 
|  | .getAssociatedValue() | 
|  | << "\n"; | 
|  | } | 
|  | llvm_unreachable("Expected the final number of abstract attributes to " | 
|  | "remain unchanged!"); | 
|  | } | 
|  |  | 
|  | for (auto &It : AttrsMap) { | 
|  | AttributeList &AL = It.getSecond(); | 
|  | const IRPosition &IRP = | 
|  | isa<Function>(It.getFirst()) | 
|  | ? IRPosition::function(*cast<Function>(It.getFirst())) | 
|  | : IRPosition::callsite_function(*cast<CallBase>(It.getFirst())); | 
|  | IRP.setAttrList(AL); | 
|  | } | 
|  |  | 
|  | return ManifestChange; | 
|  | } | 
|  |  | 
|  | void Attributor::identifyDeadInternalFunctions() { | 
|  | // Early exit if we don't intend to delete functions. | 
|  | if (!Configuration.DeleteFns) | 
|  | return; | 
|  |  | 
|  | // To avoid triggering an assertion in the lazy call graph we will not delete | 
|  | // any internal library functions. We should modify the assertion though and | 
|  | // allow internals to be deleted. | 
|  | const auto *TLI = | 
|  | isModulePass() | 
|  | ? nullptr | 
|  | : getInfoCache().getTargetLibraryInfoForFunction(*Functions.back()); | 
|  | LibFunc LF; | 
|  |  | 
|  | // Identify dead internal functions and delete them. This happens outside | 
|  | // the other fixpoint analysis as we might treat potentially dead functions | 
|  | // as live to lower the number of iterations. If they happen to be dead, the | 
|  | // below fixpoint loop will identify and eliminate them. | 
|  |  | 
|  | SmallVector<Function *, 8> InternalFns; | 
|  | for (Function *F : Functions) | 
|  | if (F->hasLocalLinkage() && (isModulePass() || !TLI->getLibFunc(*F, LF))) | 
|  | InternalFns.push_back(F); | 
|  |  | 
|  | SmallPtrSet<Function *, 8> LiveInternalFns; | 
|  | bool FoundLiveInternal = true; | 
|  | while (FoundLiveInternal) { | 
|  | FoundLiveInternal = false; | 
|  | for (Function *&F : InternalFns) { | 
|  | if (!F) | 
|  | continue; | 
|  |  | 
|  | bool UsedAssumedInformation = false; | 
|  | if (checkForAllCallSites( | 
|  | [&](AbstractCallSite ACS) { | 
|  | Function *Callee = ACS.getInstruction()->getFunction(); | 
|  | return ToBeDeletedFunctions.count(Callee) || | 
|  | (Functions.count(Callee) && Callee->hasLocalLinkage() && | 
|  | !LiveInternalFns.count(Callee)); | 
|  | }, | 
|  | *F, true, nullptr, UsedAssumedInformation)) { | 
|  | continue; | 
|  | } | 
|  |  | 
|  | LiveInternalFns.insert(F); | 
|  | F = nullptr; | 
|  | FoundLiveInternal = true; | 
|  | } | 
|  | } | 
|  |  | 
|  | for (Function *F : InternalFns) | 
|  | if (F) | 
|  | ToBeDeletedFunctions.insert(F); | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::cleanupIR() { | 
|  | TimeTraceScope TimeScope("Attributor::cleanupIR"); | 
|  | // Delete stuff at the end to avoid invalid references and a nice order. | 
|  | LLVM_DEBUG(dbgs() << "\n[Attributor] Delete/replace at least " | 
|  | << ToBeDeletedFunctions.size() << " functions and " | 
|  | << ToBeDeletedBlocks.size() << " blocks and " | 
|  | << ToBeDeletedInsts.size() << " instructions and " | 
|  | << ToBeChangedValues.size() << " values and " | 
|  | << ToBeChangedUses.size() << " uses. To insert " | 
|  | << ToBeChangedToUnreachableInsts.size() | 
|  | << " unreachables.\n" | 
|  | << "Preserve manifest added " << ManifestAddedBlocks.size() | 
|  | << " blocks\n"); | 
|  |  | 
|  | SmallVector<WeakTrackingVH, 32> DeadInsts; | 
|  | SmallVector<Instruction *, 32> TerminatorsToFold; | 
|  |  | 
|  | auto ReplaceUse = [&](Use *U, Value *NewV) { | 
|  | Value *OldV = U->get(); | 
|  |  | 
|  | // If we plan to replace NewV we need to update it at this point. | 
|  | do { | 
|  | const auto &Entry = ToBeChangedValues.lookup(NewV); | 
|  | if (!get<0>(Entry)) | 
|  | break; | 
|  | NewV = get<0>(Entry); | 
|  | } while (true); | 
|  |  | 
|  | Instruction *I = dyn_cast<Instruction>(U->getUser()); | 
|  | assert((!I || isRunOn(*I->getFunction())) && | 
|  | "Cannot replace an instruction outside the current SCC!"); | 
|  |  | 
|  | // Do not replace uses in returns if the value is a must-tail call we will | 
|  | // not delete. | 
|  | if (auto *RI = dyn_cast_or_null<ReturnInst>(I)) { | 
|  | if (auto *CI = dyn_cast<CallInst>(OldV->stripPointerCasts())) | 
|  | if (CI->isMustTailCall() && !ToBeDeletedInsts.count(CI)) | 
|  | return; | 
|  | // If we rewrite a return and the new value is not an argument, strip the | 
|  | // `returned` attribute as it is wrong now. | 
|  | if (!isa<Argument>(NewV)) | 
|  | for (auto &Arg : RI->getFunction()->args()) | 
|  | Arg.removeAttr(Attribute::Returned); | 
|  | } | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "Use " << *NewV << " in " << *U->getUser() | 
|  | << " instead of " << *OldV << "\n"); | 
|  | U->set(NewV); | 
|  |  | 
|  | if (Instruction *I = dyn_cast<Instruction>(OldV)) { | 
|  | CGModifiedFunctions.insert(I->getFunction()); | 
|  | if (!isa<PHINode>(I) && !ToBeDeletedInsts.count(I) && | 
|  | isInstructionTriviallyDead(I)) | 
|  | DeadInsts.push_back(I); | 
|  | } | 
|  | if (isa<UndefValue>(NewV) && isa<CallBase>(U->getUser())) { | 
|  | auto *CB = cast<CallBase>(U->getUser()); | 
|  | if (CB->isArgOperand(U)) { | 
|  | unsigned Idx = CB->getArgOperandNo(U); | 
|  | CB->removeParamAttr(Idx, Attribute::NoUndef); | 
|  | auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand()); | 
|  | if (Callee && Callee->arg_size() > Idx) | 
|  | Callee->removeParamAttr(Idx, Attribute::NoUndef); | 
|  | } | 
|  | } | 
|  | if (isa<Constant>(NewV) && isa<BranchInst>(U->getUser())) { | 
|  | Instruction *UserI = cast<Instruction>(U->getUser()); | 
|  | if (isa<UndefValue>(NewV)) { | 
|  | ToBeChangedToUnreachableInsts.insert(UserI); | 
|  | } else { | 
|  | TerminatorsToFold.push_back(UserI); | 
|  | } | 
|  | } | 
|  | }; | 
|  |  | 
|  | for (auto &It : ToBeChangedUses) { | 
|  | Use *U = It.first; | 
|  | Value *NewV = It.second; | 
|  | ReplaceUse(U, NewV); | 
|  | } | 
|  |  | 
|  | SmallVector<Use *, 4> Uses; | 
|  | for (auto &It : ToBeChangedValues) { | 
|  | Value *OldV = It.first; | 
|  | auto [NewV, Done] = It.second; | 
|  | Uses.clear(); | 
|  | for (auto &U : OldV->uses()) | 
|  | if (Done || !U.getUser()->isDroppable()) | 
|  | Uses.push_back(&U); | 
|  | for (Use *U : Uses) { | 
|  | if (auto *I = dyn_cast<Instruction>(U->getUser())) | 
|  | if (!isRunOn(*I->getFunction())) | 
|  | continue; | 
|  | ReplaceUse(U, NewV); | 
|  | } | 
|  | } | 
|  |  | 
|  | for (const auto &V : InvokeWithDeadSuccessor) | 
|  | if (InvokeInst *II = dyn_cast_or_null<InvokeInst>(V)) { | 
|  | assert(isRunOn(*II->getFunction()) && | 
|  | "Cannot replace an invoke outside the current SCC!"); | 
|  | bool UnwindBBIsDead = II->hasFnAttr(Attribute::NoUnwind); | 
|  | bool NormalBBIsDead = II->hasFnAttr(Attribute::NoReturn); | 
|  | bool Invoke2CallAllowed = | 
|  | !AAIsDead::mayCatchAsynchronousExceptions(*II->getFunction()); | 
|  | assert((UnwindBBIsDead || NormalBBIsDead) && | 
|  | "Invoke does not have dead successors!"); | 
|  | BasicBlock *BB = II->getParent(); | 
|  | BasicBlock *NormalDestBB = II->getNormalDest(); | 
|  | if (UnwindBBIsDead) { | 
|  | Instruction *NormalNextIP = &NormalDestBB->front(); | 
|  | if (Invoke2CallAllowed) { | 
|  | changeToCall(II); | 
|  | NormalNextIP = BB->getTerminator(); | 
|  | } | 
|  | if (NormalBBIsDead) | 
|  | ToBeChangedToUnreachableInsts.insert(NormalNextIP); | 
|  | } else { | 
|  | assert(NormalBBIsDead && "Broken invariant!"); | 
|  | if (!NormalDestBB->getUniquePredecessor()) | 
|  | NormalDestBB = SplitBlockPredecessors(NormalDestBB, {BB}, ".dead"); | 
|  | ToBeChangedToUnreachableInsts.insert(&NormalDestBB->front()); | 
|  | } | 
|  | } | 
|  | for (Instruction *I : TerminatorsToFold) { | 
|  | assert(isRunOn(*I->getFunction()) && | 
|  | "Cannot replace a terminator outside the current SCC!"); | 
|  | CGModifiedFunctions.insert(I->getFunction()); | 
|  | ConstantFoldTerminator(I->getParent()); | 
|  | } | 
|  | for (const auto &V : ToBeChangedToUnreachableInsts) | 
|  | if (Instruction *I = dyn_cast_or_null<Instruction>(V)) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Change to unreachable: " << *I | 
|  | << "\n"); | 
|  | assert(isRunOn(*I->getFunction()) && | 
|  | "Cannot replace an instruction outside the current SCC!"); | 
|  | CGModifiedFunctions.insert(I->getFunction()); | 
|  | changeToUnreachable(I); | 
|  | } | 
|  |  | 
|  | for (const auto &V : ToBeDeletedInsts) { | 
|  | if (Instruction *I = dyn_cast_or_null<Instruction>(V)) { | 
|  | assert((!isa<CallBase>(I) || isa<IntrinsicInst>(I) || | 
|  | isRunOn(*I->getFunction())) && | 
|  | "Cannot delete an instruction outside the current SCC!"); | 
|  | I->dropDroppableUses(); | 
|  | CGModifiedFunctions.insert(I->getFunction()); | 
|  | if (!I->getType()->isVoidTy()) | 
|  | I->replaceAllUsesWith(UndefValue::get(I->getType())); | 
|  | if (!isa<PHINode>(I) && isInstructionTriviallyDead(I)) | 
|  | DeadInsts.push_back(I); | 
|  | else | 
|  | I->eraseFromParent(); | 
|  | } | 
|  | } | 
|  |  | 
|  | llvm::erase_if(DeadInsts, [&](WeakTrackingVH I) { return !I; }); | 
|  |  | 
|  | LLVM_DEBUG({ | 
|  | dbgs() << "[Attributor] DeadInsts size: " << DeadInsts.size() << "\n"; | 
|  | for (auto &I : DeadInsts) | 
|  | if (I) | 
|  | dbgs() << "  - " << *I << "\n"; | 
|  | }); | 
|  |  | 
|  | RecursivelyDeleteTriviallyDeadInstructions(DeadInsts); | 
|  |  | 
|  | if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) { | 
|  | SmallVector<BasicBlock *, 8> ToBeDeletedBBs; | 
|  | ToBeDeletedBBs.reserve(NumDeadBlocks); | 
|  | for (BasicBlock *BB : ToBeDeletedBlocks) { | 
|  | assert(isRunOn(*BB->getParent()) && | 
|  | "Cannot delete a block outside the current SCC!"); | 
|  | CGModifiedFunctions.insert(BB->getParent()); | 
|  | // Do not delete BBs added during manifests of AAs. | 
|  | if (ManifestAddedBlocks.contains(BB)) | 
|  | continue; | 
|  | ToBeDeletedBBs.push_back(BB); | 
|  | } | 
|  | // Actually we do not delete the blocks but squash them into a single | 
|  | // unreachable but untangling branches that jump here is something we need | 
|  | // to do in a more generic way. | 
|  | detachDeadBlocks(ToBeDeletedBBs, nullptr); | 
|  | } | 
|  |  | 
|  | identifyDeadInternalFunctions(); | 
|  |  | 
|  | // Rewrite the functions as requested during manifest. | 
|  | ChangeStatus ManifestChange = rewriteFunctionSignatures(CGModifiedFunctions); | 
|  |  | 
|  | for (Function *Fn : CGModifiedFunctions) | 
|  | if (!ToBeDeletedFunctions.count(Fn) && Functions.count(Fn)) | 
|  | Configuration.CGUpdater.reanalyzeFunction(*Fn); | 
|  |  | 
|  | for (Function *Fn : ToBeDeletedFunctions) { | 
|  | if (!Functions.count(Fn)) | 
|  | continue; | 
|  | Configuration.CGUpdater.removeFunction(*Fn); | 
|  | } | 
|  |  | 
|  | if (!ToBeChangedUses.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!ToBeChangedToUnreachableInsts.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!ToBeDeletedFunctions.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!ToBeDeletedBlocks.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!ToBeDeletedInsts.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!InvokeWithDeadSuccessor.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | if (!DeadInsts.empty()) | 
|  | ManifestChange = ChangeStatus::CHANGED; | 
|  |  | 
|  | NumFnDeleted += ToBeDeletedFunctions.size(); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Deleted " << ToBeDeletedFunctions.size() | 
|  | << " functions after manifest.\n"); | 
|  |  | 
|  | #ifdef EXPENSIVE_CHECKS | 
|  | for (Function *F : Functions) { | 
|  | if (ToBeDeletedFunctions.count(F)) | 
|  | continue; | 
|  | assert(!verifyFunction(*F, &errs()) && "Module verification failed!"); | 
|  | } | 
|  | #endif | 
|  |  | 
|  | return ManifestChange; | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::run() { | 
|  | TimeTraceScope TimeScope("Attributor::run"); | 
|  | AttributorCallGraph ACallGraph(*this); | 
|  |  | 
|  | if (PrintCallGraph) | 
|  | ACallGraph.populateAll(); | 
|  |  | 
|  | Phase = AttributorPhase::UPDATE; | 
|  | runTillFixpoint(); | 
|  |  | 
|  | // dump graphs on demand | 
|  | if (DumpDepGraph) | 
|  | DG.dumpGraph(); | 
|  |  | 
|  | if (ViewDepGraph) | 
|  | DG.viewGraph(); | 
|  |  | 
|  | if (PrintDependencies) | 
|  | DG.print(); | 
|  |  | 
|  | Phase = AttributorPhase::MANIFEST; | 
|  | ChangeStatus ManifestChange = manifestAttributes(); | 
|  |  | 
|  | Phase = AttributorPhase::CLEANUP; | 
|  | ChangeStatus CleanupChange = cleanupIR(); | 
|  |  | 
|  | if (PrintCallGraph) | 
|  | ACallGraph.print(); | 
|  |  | 
|  | return ManifestChange | CleanupChange; | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::updateAA(AbstractAttribute &AA) { | 
|  | TimeTraceScope TimeScope("updateAA", [&]() { | 
|  | return AA.getName().str() + | 
|  | std::to_string(AA.getIRPosition().getPositionKind()); | 
|  | }); | 
|  | assert(Phase == AttributorPhase::UPDATE && | 
|  | "We can update AA only in the update stage!"); | 
|  |  | 
|  | // Use a new dependence vector for this update. | 
|  | DependenceVector DV; | 
|  | DependenceStack.push_back(&DV); | 
|  |  | 
|  | auto &AAState = AA.getState(); | 
|  | ChangeStatus CS = ChangeStatus::UNCHANGED; | 
|  | bool UsedAssumedInformation = false; | 
|  | if (!isAssumedDead(AA, nullptr, UsedAssumedInformation, | 
|  | /* CheckBBLivenessOnly */ true)) | 
|  | CS = AA.update(*this); | 
|  |  | 
|  | if (!AA.isQueryAA() && DV.empty() && !AA.getState().isAtFixpoint()) { | 
|  | // If the AA did not rely on outside information but changed, we run it | 
|  | // again to see if it found a fixpoint. Most AAs do but we don't require | 
|  | // them to. Hence, it might take the AA multiple iterations to get to a | 
|  | // fixpoint even if it does not rely on outside information, which is fine. | 
|  | ChangeStatus RerunCS = ChangeStatus::UNCHANGED; | 
|  | if (CS == ChangeStatus::CHANGED) | 
|  | RerunCS = AA.update(*this); | 
|  |  | 
|  | // If the attribute did not change during the run or rerun, and it still did | 
|  | // not query any non-fix information, the state will not change and we can | 
|  | // indicate that right at this point. | 
|  | if (RerunCS == ChangeStatus::UNCHANGED && !AA.isQueryAA() && DV.empty()) | 
|  | AAState.indicateOptimisticFixpoint(); | 
|  | } | 
|  |  | 
|  | if (!AAState.isAtFixpoint()) | 
|  | rememberDependences(); | 
|  |  | 
|  | // Verify the stack was used properly, that is we pop the dependence vector we | 
|  | // put there earlier. | 
|  | DependenceVector *PoppedDV = DependenceStack.pop_back_val(); | 
|  | (void)PoppedDV; | 
|  | assert(PoppedDV == &DV && "Inconsistent usage of the dependence stack!"); | 
|  |  | 
|  | return CS; | 
|  | } | 
|  |  | 
|  | void Attributor::createShallowWrapper(Function &F) { | 
|  | assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!"); | 
|  |  | 
|  | Module &M = *F.getParent(); | 
|  | LLVMContext &Ctx = M.getContext(); | 
|  | FunctionType *FnTy = F.getFunctionType(); | 
|  |  | 
|  | Function *Wrapper = | 
|  | Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), F.getName()); | 
|  | F.setName(""); // set the inside function anonymous | 
|  | M.getFunctionList().insert(F.getIterator(), Wrapper); | 
|  |  | 
|  | F.setLinkage(GlobalValue::InternalLinkage); | 
|  |  | 
|  | F.replaceAllUsesWith(Wrapper); | 
|  | assert(F.use_empty() && "Uses remained after wrapper was created!"); | 
|  |  | 
|  | // Move the COMDAT section to the wrapper. | 
|  | // TODO: Check if we need to keep it for F as well. | 
|  | Wrapper->setComdat(F.getComdat()); | 
|  | F.setComdat(nullptr); | 
|  |  | 
|  | // Copy all metadata and attributes but keep them on F as well. | 
|  | SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; | 
|  | F.getAllMetadata(MDs); | 
|  | for (auto MDIt : MDs) | 
|  | Wrapper->addMetadata(MDIt.first, *MDIt.second); | 
|  | Wrapper->setAttributes(F.getAttributes()); | 
|  |  | 
|  | // Create the call in the wrapper. | 
|  | BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper); | 
|  |  | 
|  | SmallVector<Value *, 8> Args; | 
|  | Argument *FArgIt = F.arg_begin(); | 
|  | for (Argument &Arg : Wrapper->args()) { | 
|  | Args.push_back(&Arg); | 
|  | Arg.setName((FArgIt++)->getName()); | 
|  | } | 
|  |  | 
|  | CallInst *CI = CallInst::Create(&F, Args, "", EntryBB); | 
|  | CI->setTailCall(true); | 
|  | CI->addFnAttr(Attribute::NoInline); | 
|  | ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB); | 
|  |  | 
|  | NumFnShallowWrappersCreated++; | 
|  | } | 
|  |  | 
|  | bool Attributor::isInternalizable(Function &F) { | 
|  | if (F.isDeclaration() || F.hasLocalLinkage() || | 
|  | GlobalValue::isInterposableLinkage(F.getLinkage())) | 
|  | return false; | 
|  | return true; | 
|  | } | 
|  |  | 
|  | Function *Attributor::internalizeFunction(Function &F, bool Force) { | 
|  | if (!AllowDeepWrapper && !Force) | 
|  | return nullptr; | 
|  | if (!isInternalizable(F)) | 
|  | return nullptr; | 
|  |  | 
|  | SmallPtrSet<Function *, 2> FnSet = {&F}; | 
|  | DenseMap<Function *, Function *> InternalizedFns; | 
|  | internalizeFunctions(FnSet, InternalizedFns); | 
|  |  | 
|  | return InternalizedFns[&F]; | 
|  | } | 
|  |  | 
|  | bool Attributor::internalizeFunctions(SmallPtrSetImpl<Function *> &FnSet, | 
|  | DenseMap<Function *, Function *> &FnMap) { | 
|  | for (Function *F : FnSet) | 
|  | if (!Attributor::isInternalizable(*F)) | 
|  | return false; | 
|  |  | 
|  | FnMap.clear(); | 
|  | // Generate the internalized version of each function. | 
|  | for (Function *F : FnSet) { | 
|  | Module &M = *F->getParent(); | 
|  | FunctionType *FnTy = F->getFunctionType(); | 
|  |  | 
|  | // Create a copy of the current function | 
|  | Function *Copied = | 
|  | Function::Create(FnTy, F->getLinkage(), F->getAddressSpace(), | 
|  | F->getName() + ".internalized"); | 
|  | ValueToValueMapTy VMap; | 
|  | auto *NewFArgIt = Copied->arg_begin(); | 
|  | for (auto &Arg : F->args()) { | 
|  | auto ArgName = Arg.getName(); | 
|  | NewFArgIt->setName(ArgName); | 
|  | VMap[&Arg] = &(*NewFArgIt++); | 
|  | } | 
|  | SmallVector<ReturnInst *, 8> Returns; | 
|  |  | 
|  | // Copy the body of the original function to the new one | 
|  | CloneFunctionInto(Copied, F, VMap, | 
|  | CloneFunctionChangeType::LocalChangesOnly, Returns); | 
|  |  | 
|  | // Set the linakage and visibility late as CloneFunctionInto has some | 
|  | // implicit requirements. | 
|  | Copied->setVisibility(GlobalValue::DefaultVisibility); | 
|  | Copied->setLinkage(GlobalValue::PrivateLinkage); | 
|  |  | 
|  | // Copy metadata | 
|  | SmallVector<std::pair<unsigned, MDNode *>, 1> MDs; | 
|  | F->getAllMetadata(MDs); | 
|  | for (auto MDIt : MDs) | 
|  | if (!Copied->hasMetadata()) | 
|  | Copied->addMetadata(MDIt.first, *MDIt.second); | 
|  |  | 
|  | M.getFunctionList().insert(F->getIterator(), Copied); | 
|  | Copied->setDSOLocal(true); | 
|  | FnMap[F] = Copied; | 
|  | } | 
|  |  | 
|  | // Replace all uses of the old function with the new internalized function | 
|  | // unless the caller is a function that was just internalized. | 
|  | for (Function *F : FnSet) { | 
|  | auto &InternalizedFn = FnMap[F]; | 
|  | auto IsNotInternalized = [&](Use &U) -> bool { | 
|  | if (auto *CB = dyn_cast<CallBase>(U.getUser())) | 
|  | return !FnMap.lookup(CB->getCaller()); | 
|  | return false; | 
|  | }; | 
|  | F->replaceUsesWithIf(InternalizedFn, IsNotInternalized); | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::isValidFunctionSignatureRewrite( | 
|  | Argument &Arg, ArrayRef<Type *> ReplacementTypes) { | 
|  |  | 
|  | if (!Configuration.RewriteSignatures) | 
|  | return false; | 
|  |  | 
|  | Function *Fn = Arg.getParent(); | 
|  | auto CallSiteCanBeChanged = [Fn](AbstractCallSite ACS) { | 
|  | // Forbid the call site to cast the function return type. If we need to | 
|  | // rewrite these functions we need to re-create a cast for the new call site | 
|  | // (if the old had uses). | 
|  | if (!ACS.getCalledFunction() || | 
|  | ACS.getInstruction()->getType() != | 
|  | ACS.getCalledFunction()->getReturnType()) | 
|  | return false; | 
|  | if (cast<CallBase>(ACS.getInstruction())->getCalledOperand()->getType() != | 
|  | Fn->getType()) | 
|  | return false; | 
|  | if (ACS.getNumArgOperands() != Fn->arg_size()) | 
|  | return false; | 
|  | // Forbid must-tail calls for now. | 
|  | return !ACS.isCallbackCall() && !ACS.getInstruction()->isMustTailCall(); | 
|  | }; | 
|  |  | 
|  | // Avoid var-arg functions for now. | 
|  | if (Fn->isVarArg()) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite var-args functions\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Avoid functions with complicated argument passing semantics. | 
|  | AttributeList FnAttributeList = Fn->getAttributes(); | 
|  | if (FnAttributeList.hasAttrSomewhere(Attribute::Nest) || | 
|  | FnAttributeList.hasAttrSomewhere(Attribute::StructRet) || | 
|  | FnAttributeList.hasAttrSomewhere(Attribute::InAlloca) || | 
|  | FnAttributeList.hasAttrSomewhere(Attribute::Preallocated)) { | 
|  | LLVM_DEBUG( | 
|  | dbgs() << "[Attributor] Cannot rewrite due to complex attribute\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // Avoid callbacks for now. | 
|  | bool UsedAssumedInformation = false; | 
|  | if (!checkForAllCallSites(CallSiteCanBeChanged, *Fn, true, nullptr, | 
|  | UsedAssumedInformation, | 
|  | /* CheckPotentiallyDead */ true)) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite all call sites\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | auto InstPred = [](Instruction &I) { | 
|  | if (auto *CI = dyn_cast<CallInst>(&I)) | 
|  | return !CI->isMustTailCall(); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | // Forbid must-tail calls for now. | 
|  | // TODO: | 
|  | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn); | 
|  | if (!checkForAllInstructionsImpl(nullptr, OpcodeInstMap, InstPred, nullptr, | 
|  | nullptr, {Instruction::Call}, | 
|  | UsedAssumedInformation)) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite due to instructions\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::registerFunctionSignatureRewrite( | 
|  | Argument &Arg, ArrayRef<Type *> ReplacementTypes, | 
|  | ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB, | 
|  | ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in " | 
|  | << Arg.getParent()->getName() << " with " | 
|  | << ReplacementTypes.size() << " replacements\n"); | 
|  | assert(isValidFunctionSignatureRewrite(Arg, ReplacementTypes) && | 
|  | "Cannot register an invalid rewrite"); | 
|  |  | 
|  | Function *Fn = Arg.getParent(); | 
|  | SmallVectorImpl<std::unique_ptr<ArgumentReplacementInfo>> &ARIs = | 
|  | ArgumentReplacementMap[Fn]; | 
|  | if (ARIs.empty()) | 
|  | ARIs.resize(Fn->arg_size()); | 
|  |  | 
|  | // If we have a replacement already with less than or equal new arguments, | 
|  | // ignore this request. | 
|  | std::unique_ptr<ArgumentReplacementInfo> &ARI = ARIs[Arg.getArgNo()]; | 
|  | if (ARI && ARI->getNumReplacementArgs() <= ReplacementTypes.size()) { | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Existing rewrite is preferred\n"); | 
|  | return false; | 
|  | } | 
|  |  | 
|  | // If we have a replacement already but we like the new one better, delete | 
|  | // the old. | 
|  | ARI.reset(); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in " | 
|  | << Arg.getParent()->getName() << " with " | 
|  | << ReplacementTypes.size() << " replacements\n"); | 
|  |  | 
|  | // Remember the replacement. | 
|  | ARI.reset(new ArgumentReplacementInfo(*this, Arg, ReplacementTypes, | 
|  | std::move(CalleeRepairCB), | 
|  | std::move(ACSRepairCB))); | 
|  |  | 
|  | return true; | 
|  | } | 
|  |  | 
|  | bool Attributor::shouldSeedAttribute(AbstractAttribute &AA) { | 
|  | bool Result = true; | 
|  | #ifndef NDEBUG | 
|  | if (SeedAllowList.size() != 0) | 
|  | Result = llvm::is_contained(SeedAllowList, AA.getName()); | 
|  | Function *Fn = AA.getAnchorScope(); | 
|  | if (FunctionSeedAllowList.size() != 0 && Fn) | 
|  | Result &= llvm::is_contained(FunctionSeedAllowList, Fn->getName()); | 
|  | #endif | 
|  | return Result; | 
|  | } | 
|  |  | 
|  | ChangeStatus Attributor::rewriteFunctionSignatures( | 
|  | SmallSetVector<Function *, 8> &ModifiedFns) { | 
|  | ChangeStatus Changed = ChangeStatus::UNCHANGED; | 
|  |  | 
|  | for (auto &It : ArgumentReplacementMap) { | 
|  | Function *OldFn = It.getFirst(); | 
|  |  | 
|  | // Deleted functions do not require rewrites. | 
|  | if (!Functions.count(OldFn) || ToBeDeletedFunctions.count(OldFn)) | 
|  | continue; | 
|  |  | 
|  | const SmallVectorImpl<std::unique_ptr<ArgumentReplacementInfo>> &ARIs = | 
|  | It.getSecond(); | 
|  | assert(ARIs.size() == OldFn->arg_size() && "Inconsistent state!"); | 
|  |  | 
|  | SmallVector<Type *, 16> NewArgumentTypes; | 
|  | SmallVector<AttributeSet, 16> NewArgumentAttributes; | 
|  |  | 
|  | // Collect replacement argument types and copy over existing attributes. | 
|  | AttributeList OldFnAttributeList = OldFn->getAttributes(); | 
|  | for (Argument &Arg : OldFn->args()) { | 
|  | if (const std::unique_ptr<ArgumentReplacementInfo> &ARI = | 
|  | ARIs[Arg.getArgNo()]) { | 
|  | NewArgumentTypes.append(ARI->ReplacementTypes.begin(), | 
|  | ARI->ReplacementTypes.end()); | 
|  | NewArgumentAttributes.append(ARI->getNumReplacementArgs(), | 
|  | AttributeSet()); | 
|  | } else { | 
|  | NewArgumentTypes.push_back(Arg.getType()); | 
|  | NewArgumentAttributes.push_back( | 
|  | OldFnAttributeList.getParamAttrs(Arg.getArgNo())); | 
|  | } | 
|  | } | 
|  |  | 
|  | uint64_t LargestVectorWidth = 0; | 
|  | for (auto *I : NewArgumentTypes) | 
|  | if (auto *VT = dyn_cast<llvm::VectorType>(I)) | 
|  | LargestVectorWidth = | 
|  | std::max(LargestVectorWidth, | 
|  | VT->getPrimitiveSizeInBits().getKnownMinValue()); | 
|  |  | 
|  | FunctionType *OldFnTy = OldFn->getFunctionType(); | 
|  | Type *RetTy = OldFnTy->getReturnType(); | 
|  |  | 
|  | // Construct the new function type using the new arguments types. | 
|  | FunctionType *NewFnTy = | 
|  | FunctionType::get(RetTy, NewArgumentTypes, OldFnTy->isVarArg()); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Function rewrite '" << OldFn->getName() | 
|  | << "' from " << *OldFn->getFunctionType() << " to " | 
|  | << *NewFnTy << "\n"); | 
|  |  | 
|  | // Create the new function body and insert it into the module. | 
|  | Function *NewFn = Function::Create(NewFnTy, OldFn->getLinkage(), | 
|  | OldFn->getAddressSpace(), ""); | 
|  | Functions.insert(NewFn); | 
|  | OldFn->getParent()->getFunctionList().insert(OldFn->getIterator(), NewFn); | 
|  | NewFn->takeName(OldFn); | 
|  | NewFn->copyAttributesFrom(OldFn); | 
|  |  | 
|  | // Patch the pointer to LLVM function in debug info descriptor. | 
|  | NewFn->setSubprogram(OldFn->getSubprogram()); | 
|  | OldFn->setSubprogram(nullptr); | 
|  |  | 
|  | // Recompute the parameter attributes list based on the new arguments for | 
|  | // the function. | 
|  | LLVMContext &Ctx = OldFn->getContext(); | 
|  | NewFn->setAttributes(AttributeList::get( | 
|  | Ctx, OldFnAttributeList.getFnAttrs(), OldFnAttributeList.getRetAttrs(), | 
|  | NewArgumentAttributes)); | 
|  | AttributeFuncs::updateMinLegalVectorWidthAttr(*NewFn, LargestVectorWidth); | 
|  |  | 
|  | // Remove argmem from the memory effects if we have no more pointer | 
|  | // arguments, or they are readnone. | 
|  | MemoryEffects ME = NewFn->getMemoryEffects(); | 
|  | int ArgNo = -1; | 
|  | if (ME.doesAccessArgPointees() && all_of(NewArgumentTypes, [&](Type *T) { | 
|  | ++ArgNo; | 
|  | return !T->isPtrOrPtrVectorTy() || | 
|  | NewFn->hasParamAttribute(ArgNo, Attribute::ReadNone); | 
|  | })) { | 
|  | NewFn->setMemoryEffects(ME - MemoryEffects::argMemOnly()); | 
|  | } | 
|  |  | 
|  | // Since we have now created the new function, splice the body of the old | 
|  | // function right into the new function, leaving the old rotting hulk of the | 
|  | // function empty. | 
|  | NewFn->splice(NewFn->begin(), OldFn); | 
|  |  | 
|  | // Set of all "call-like" instructions that invoke the old function mapped | 
|  | // to their new replacements. | 
|  | SmallVector<std::pair<CallBase *, CallBase *>, 8> CallSitePairs; | 
|  |  | 
|  | // Callback to create a new "call-like" instruction for a given one. | 
|  | auto CallSiteReplacementCreator = [&](AbstractCallSite ACS) { | 
|  | CallBase *OldCB = cast<CallBase>(ACS.getInstruction()); | 
|  | const AttributeList &OldCallAttributeList = OldCB->getAttributes(); | 
|  |  | 
|  | // Collect the new argument operands for the replacement call site. | 
|  | SmallVector<Value *, 16> NewArgOperands; | 
|  | SmallVector<AttributeSet, 16> NewArgOperandAttributes; | 
|  | for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); ++OldArgNum) { | 
|  | unsigned NewFirstArgNum = NewArgOperands.size(); | 
|  | (void)NewFirstArgNum; // only used inside assert. | 
|  | if (const std::unique_ptr<ArgumentReplacementInfo> &ARI = | 
|  | ARIs[OldArgNum]) { | 
|  | if (ARI->ACSRepairCB) | 
|  | ARI->ACSRepairCB(*ARI, ACS, NewArgOperands); | 
|  | assert(ARI->getNumReplacementArgs() + NewFirstArgNum == | 
|  | NewArgOperands.size() && | 
|  | "ACS repair callback did not provide as many operand as new " | 
|  | "types were registered!"); | 
|  | // TODO: Exose the attribute set to the ACS repair callback | 
|  | NewArgOperandAttributes.append(ARI->ReplacementTypes.size(), | 
|  | AttributeSet()); | 
|  | } else { | 
|  | NewArgOperands.push_back(ACS.getCallArgOperand(OldArgNum)); | 
|  | NewArgOperandAttributes.push_back( | 
|  | OldCallAttributeList.getParamAttrs(OldArgNum)); | 
|  | } | 
|  | } | 
|  |  | 
|  | assert(NewArgOperands.size() == NewArgOperandAttributes.size() && | 
|  | "Mismatch # argument operands vs. # argument operand attributes!"); | 
|  | assert(NewArgOperands.size() == NewFn->arg_size() && | 
|  | "Mismatch # argument operands vs. # function arguments!"); | 
|  |  | 
|  | SmallVector<OperandBundleDef, 4> OperandBundleDefs; | 
|  | OldCB->getOperandBundlesAsDefs(OperandBundleDefs); | 
|  |  | 
|  | // Create a new call or invoke instruction to replace the old one. | 
|  | CallBase *NewCB; | 
|  | if (InvokeInst *II = dyn_cast<InvokeInst>(OldCB)) { | 
|  | NewCB = InvokeInst::Create(NewFn, II->getNormalDest(), | 
|  | II->getUnwindDest(), NewArgOperands, | 
|  | OperandBundleDefs, "", OldCB->getIterator()); | 
|  | } else { | 
|  | auto *NewCI = CallInst::Create(NewFn, NewArgOperands, OperandBundleDefs, | 
|  | "", OldCB->getIterator()); | 
|  | NewCI->setTailCallKind(cast<CallInst>(OldCB)->getTailCallKind()); | 
|  | NewCB = NewCI; | 
|  | } | 
|  |  | 
|  | // Copy over various properties and the new attributes. | 
|  | NewCB->copyMetadata(*OldCB, {LLVMContext::MD_prof, LLVMContext::MD_dbg}); | 
|  | NewCB->setCallingConv(OldCB->getCallingConv()); | 
|  | NewCB->takeName(OldCB); | 
|  | NewCB->setAttributes(AttributeList::get( | 
|  | Ctx, OldCallAttributeList.getFnAttrs(), | 
|  | OldCallAttributeList.getRetAttrs(), NewArgOperandAttributes)); | 
|  |  | 
|  | AttributeFuncs::updateMinLegalVectorWidthAttr(*NewCB->getCaller(), | 
|  | LargestVectorWidth); | 
|  |  | 
|  | CallSitePairs.push_back({OldCB, NewCB}); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | // Use the CallSiteReplacementCreator to create replacement call sites. | 
|  | bool UsedAssumedInformation = false; | 
|  | bool Success = checkForAllCallSites(CallSiteReplacementCreator, *OldFn, | 
|  | true, nullptr, UsedAssumedInformation, | 
|  | /* CheckPotentiallyDead */ true); | 
|  | (void)Success; | 
|  | assert(Success && "Assumed call site replacement to succeed!"); | 
|  |  | 
|  | // Rewire the arguments. | 
|  | Argument *OldFnArgIt = OldFn->arg_begin(); | 
|  | Argument *NewFnArgIt = NewFn->arg_begin(); | 
|  | for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); | 
|  | ++OldArgNum, ++OldFnArgIt) { | 
|  | if (const std::unique_ptr<ArgumentReplacementInfo> &ARI = | 
|  | ARIs[OldArgNum]) { | 
|  | if (ARI->CalleeRepairCB) | 
|  | ARI->CalleeRepairCB(*ARI, *NewFn, NewFnArgIt); | 
|  | if (ARI->ReplacementTypes.empty()) | 
|  | OldFnArgIt->replaceAllUsesWith( | 
|  | PoisonValue::get(OldFnArgIt->getType())); | 
|  | NewFnArgIt += ARI->ReplacementTypes.size(); | 
|  | } else { | 
|  | NewFnArgIt->takeName(&*OldFnArgIt); | 
|  | OldFnArgIt->replaceAllUsesWith(&*NewFnArgIt); | 
|  | ++NewFnArgIt; | 
|  | } | 
|  | } | 
|  |  | 
|  | // Eliminate the instructions *after* we visited all of them. | 
|  | for (auto &CallSitePair : CallSitePairs) { | 
|  | CallBase &OldCB = *CallSitePair.first; | 
|  | CallBase &NewCB = *CallSitePair.second; | 
|  | assert(OldCB.getType() == NewCB.getType() && | 
|  | "Cannot handle call sites with different types!"); | 
|  | ModifiedFns.insert(OldCB.getFunction()); | 
|  | OldCB.replaceAllUsesWith(&NewCB); | 
|  | OldCB.eraseFromParent(); | 
|  | } | 
|  |  | 
|  | // Replace the function in the call graph (if any). | 
|  | Configuration.CGUpdater.replaceFunctionWith(*OldFn, *NewFn); | 
|  |  | 
|  | // If the old function was modified and needed to be reanalyzed, the new one | 
|  | // does now. | 
|  | if (ModifiedFns.remove(OldFn)) | 
|  | ModifiedFns.insert(NewFn); | 
|  |  | 
|  | Changed = ChangeStatus::CHANGED; | 
|  | } | 
|  |  | 
|  | return Changed; | 
|  | } | 
|  |  | 
|  | void InformationCache::initializeInformationCache(const Function &CF, | 
|  | FunctionInfo &FI) { | 
|  | // As we do not modify the function here we can remove the const | 
|  | // withouth breaking implicit assumptions. At the end of the day, we could | 
|  | // initialize the cache eagerly which would look the same to the users. | 
|  | Function &F = const_cast<Function &>(CF); | 
|  |  | 
|  | FI.IsKernel = F.hasFnAttribute("kernel"); | 
|  |  | 
|  | // Walk all instructions to find interesting instructions that might be | 
|  | // queried by abstract attributes during their initialization or update. | 
|  | // This has to happen before we create attributes. | 
|  |  | 
|  | DenseMap<const Value *, std::optional<short>> AssumeUsesMap; | 
|  |  | 
|  | // Add \p V to the assume uses map which track the number of uses outside of | 
|  | // "visited" assumes. If no outside uses are left the value is added to the | 
|  | // assume only use vector. | 
|  | auto AddToAssumeUsesMap = [&](const Value &V) -> void { | 
|  | SmallVector<const Instruction *> Worklist; | 
|  | if (auto *I = dyn_cast<Instruction>(&V)) | 
|  | Worklist.push_back(I); | 
|  | while (!Worklist.empty()) { | 
|  | const Instruction *I = Worklist.pop_back_val(); | 
|  | std::optional<short> &NumUses = AssumeUsesMap[I]; | 
|  | if (!NumUses) | 
|  | NumUses = I->getNumUses(); | 
|  | NumUses = *NumUses - /* this assume */ 1; | 
|  | if (*NumUses != 0) | 
|  | continue; | 
|  | AssumeOnlyValues.insert(I); | 
|  | for (const Value *Op : I->operands()) | 
|  | if (auto *OpI = dyn_cast<Instruction>(Op)) | 
|  | Worklist.push_back(OpI); | 
|  | } | 
|  | }; | 
|  |  | 
|  | for (Instruction &I : instructions(&F)) { | 
|  | bool IsInterestingOpcode = false; | 
|  |  | 
|  | // To allow easy access to all instructions in a function with a given | 
|  | // opcode we store them in the InfoCache. As not all opcodes are interesting | 
|  | // to concrete attributes we only cache the ones that are as identified in | 
|  | // the following switch. | 
|  | // Note: There are no concrete attributes now so this is initially empty. | 
|  | switch (I.getOpcode()) { | 
|  | default: | 
|  | assert(!isa<CallBase>(&I) && | 
|  | "New call base instruction type needs to be known in the " | 
|  | "Attributor."); | 
|  | break; | 
|  | case Instruction::Call: | 
|  | // 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 (auto *Assume = dyn_cast<AssumeInst>(&I)) { | 
|  | AssumeOnlyValues.insert(Assume); | 
|  | fillMapFromAssume(*Assume, KnowledgeMap); | 
|  | AddToAssumeUsesMap(*Assume->getArgOperand(0)); | 
|  | } else if (cast<CallInst>(I).isMustTailCall()) { | 
|  | FI.ContainsMustTailCall = true; | 
|  | if (auto *Callee = dyn_cast_if_present<Function>( | 
|  | cast<CallInst>(I).getCalledOperand())) | 
|  | getFunctionInfo(*Callee).CalledViaMustTail = true; | 
|  | } | 
|  | [[fallthrough]]; | 
|  | case Instruction::CallBr: | 
|  | case Instruction::Invoke: | 
|  | case Instruction::CleanupRet: | 
|  | case Instruction::CatchSwitch: | 
|  | case Instruction::AtomicRMW: | 
|  | case Instruction::AtomicCmpXchg: | 
|  | 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. | 
|  | case Instruction::Alloca: | 
|  | case Instruction::AddrSpaceCast: | 
|  | IsInterestingOpcode = true; | 
|  | } | 
|  | if (IsInterestingOpcode) { | 
|  | auto *&Insts = FI.OpcodeInstMap[I.getOpcode()]; | 
|  | if (!Insts) | 
|  | Insts = new (Allocator) InstructionVectorTy(); | 
|  | Insts->push_back(&I); | 
|  | } | 
|  | if (I.mayReadOrWriteMemory()) | 
|  | FI.RWInsts.push_back(&I); | 
|  | } | 
|  |  | 
|  | if (F.hasFnAttribute(Attribute::AlwaysInline) && | 
|  | isInlineViable(F).isSuccess()) | 
|  | InlineableFunctions.insert(&F); | 
|  | } | 
|  |  | 
|  | InformationCache::FunctionInfo::~FunctionInfo() { | 
|  | // The instruction vectors are allocated using a BumpPtrAllocator, we need to | 
|  | // manually destroy them. | 
|  | for (auto &It : OpcodeInstMap) | 
|  | It.getSecond()->~InstructionVectorTy(); | 
|  | } | 
|  |  | 
|  | ArrayRef<Function *> | 
|  | InformationCache::getIndirectlyCallableFunctions(Attributor &A) const { | 
|  | assert(A.isClosedWorldModule() && "Cannot see all indirect callees!"); | 
|  | return IndirectlyCallableFunctions; | 
|  | } | 
|  |  | 
|  | std::optional<unsigned> InformationCache::getFlatAddressSpace() const { | 
|  | if (TargetTriple.isGPU()) | 
|  | return 0; | 
|  | return std::nullopt; | 
|  | } | 
|  |  | 
|  | void Attributor::recordDependence(const AbstractAttribute &FromAA, | 
|  | const AbstractAttribute &ToAA, | 
|  | DepClassTy DepClass) { | 
|  | if (DepClass == DepClassTy::NONE) | 
|  | return; | 
|  | // If we are outside of an update, thus before the actual fixpoint iteration | 
|  | // started (= when we create AAs), we do not track dependences because we will | 
|  | // put all AAs into the initial worklist anyway. | 
|  | if (DependenceStack.empty()) | 
|  | return; | 
|  | if (FromAA.getState().isAtFixpoint()) | 
|  | return; | 
|  | DependenceStack.back()->push_back({&FromAA, &ToAA, DepClass}); | 
|  | } | 
|  |  | 
|  | void Attributor::rememberDependences() { | 
|  | assert(!DependenceStack.empty() && "No dependences to remember!"); | 
|  |  | 
|  | for (DepInfo &DI : *DependenceStack.back()) { | 
|  | assert((DI.DepClass == DepClassTy::REQUIRED || | 
|  | DI.DepClass == DepClassTy::OPTIONAL) && | 
|  | "Expected required or optional dependence (1 bit)!"); | 
|  | auto &DepAAs = const_cast<AbstractAttribute &>(*DI.FromAA).Deps; | 
|  | DepAAs.insert(AbstractAttribute::DepTy( | 
|  | const_cast<AbstractAttribute *>(DI.ToAA), unsigned(DI.DepClass))); | 
|  | } | 
|  | } | 
|  |  | 
|  | template <Attribute::AttrKind AK, typename AAType> | 
|  | void Attributor::checkAndQueryIRAttr(const IRPosition &IRP, AttributeSet Attrs, | 
|  | bool SkipHasAttrCheck) { | 
|  | bool IsKnown; | 
|  | if (SkipHasAttrCheck || !Attrs.hasAttribute(AK)) | 
|  | if (!Configuration.Allowed || Configuration.Allowed->count(&AAType::ID)) | 
|  | if (!AA::hasAssumedIRAttr<AK>(*this, nullptr, IRP, DepClassTy::NONE, | 
|  | IsKnown)) | 
|  | getOrCreateAAFor<AAType>(IRP); | 
|  | } | 
|  |  | 
|  | void Attributor::identifyDefaultAbstractAttributes(Function &F) { | 
|  | if (!VisitedFunctions.insert(&F).second) | 
|  | return; | 
|  | 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. | 
|  | InformationCache::FunctionInfo &FI = InfoCache.getFunctionInfo(F); | 
|  | if (!isModulePass() && !FI.CalledViaMustTail) { | 
|  | for (const Use &U : F.uses()) | 
|  | if (const auto *CB = dyn_cast<CallBase>(U.getUser())) | 
|  | if (CB->isCallee(&U) && CB->isMustTailCall()) | 
|  | FI.CalledViaMustTail = true; | 
|  | } | 
|  |  | 
|  | IRPosition FPos = IRPosition::function(F); | 
|  | bool IsIPOAmendable = isFunctionIPOAmendable(F); | 
|  | auto Attrs = F.getAttributes(); | 
|  | auto FnAttrs = Attrs.getFnAttrs(); | 
|  |  | 
|  | // Check for dead BasicBlocks in every function. | 
|  | // We need dead instruction detection because we do not want to deal with | 
|  | // broken IR in which SSA rules do not apply. | 
|  | getOrCreateAAFor<AAIsDead>(FPos); | 
|  |  | 
|  | // Every function might contain instructions that cause "undefined | 
|  | // behavior". | 
|  | getOrCreateAAFor<AAUndefinedBehavior>(FPos); | 
|  |  | 
|  | // Every function might be applicable for Heap-To-Stack conversion. | 
|  | if (EnableHeapToStack) | 
|  | getOrCreateAAFor<AAHeapToStack>(FPos); | 
|  |  | 
|  | // Every function might be "must-progress". | 
|  | checkAndQueryIRAttr<Attribute::MustProgress, AAMustProgress>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function might be "no-free". | 
|  | checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function might be "will-return". | 
|  | checkAndQueryIRAttr<Attribute::WillReturn, AAWillReturn>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function might be marked "nosync" | 
|  | checkAndQueryIRAttr<Attribute::NoSync, AANoSync>(FPos, FnAttrs); | 
|  |  | 
|  | // Everything that is visible from the outside (=function, argument, return | 
|  | // positions), cannot be changed if the function is not IPO amendable. We can | 
|  | // however analyse the code inside. | 
|  | if (IsIPOAmendable) { | 
|  |  | 
|  | // Every function can be nounwind. | 
|  | checkAndQueryIRAttr<Attribute::NoUnwind, AANoUnwind>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function might be "no-return". | 
|  | checkAndQueryIRAttr<Attribute::NoReturn, AANoReturn>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function might be "no-recurse". | 
|  | checkAndQueryIRAttr<Attribute::NoRecurse, AANoRecurse>(FPos, FnAttrs); | 
|  |  | 
|  | // Every function can be "non-convergent". | 
|  | if (Attrs.hasFnAttr(Attribute::Convergent)) | 
|  | getOrCreateAAFor<AANonConvergent>(FPos); | 
|  |  | 
|  | // Every function might be "readnone/readonly/writeonly/...". | 
|  | getOrCreateAAFor<AAMemoryBehavior>(FPos); | 
|  |  | 
|  | // Every function can be "readnone/argmemonly/inaccessiblememonly/...". | 
|  | getOrCreateAAFor<AAMemoryLocation>(FPos); | 
|  |  | 
|  | // Every function can track active assumptions. | 
|  | getOrCreateAAFor<AAAssumptionInfo>(FPos); | 
|  |  | 
|  | // If we're not using a dynamic mode for float, there's nothing worthwhile | 
|  | // to infer. This misses the edge case denormal-fp-math="dynamic" and | 
|  | // denormal-fp-math-f32=something, but that likely has no real world use. | 
|  | DenormalMode Mode = F.getDenormalMode(APFloat::IEEEsingle()); | 
|  | if (Mode.Input == DenormalMode::Dynamic || | 
|  | Mode.Output == DenormalMode::Dynamic) | 
|  | getOrCreateAAFor<AADenormalFPMath>(FPos); | 
|  |  | 
|  | // Return attributes are only appropriate if the return type is non void. | 
|  | Type *ReturnType = F.getReturnType(); | 
|  | if (!ReturnType->isVoidTy()) { | 
|  | IRPosition RetPos = IRPosition::returned(F); | 
|  | AttributeSet RetAttrs = Attrs.getRetAttrs(); | 
|  |  | 
|  | // Every returned value might be dead. | 
|  | getOrCreateAAFor<AAIsDead>(RetPos); | 
|  |  | 
|  | // Every function might be simplified. | 
|  | bool UsedAssumedInformation = false; | 
|  | getAssumedSimplified(RetPos, nullptr, UsedAssumedInformation, | 
|  | AA::Intraprocedural); | 
|  |  | 
|  | // Every returned value might be marked noundef. | 
|  | checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(RetPos, RetAttrs); | 
|  |  | 
|  | if (ReturnType->isPointerTy()) { | 
|  |  | 
|  | // Every function with pointer return type might be marked align. | 
|  | getOrCreateAAFor<AAAlign>(RetPos); | 
|  |  | 
|  | // Every function with pointer return type might be marked nonnull. | 
|  | checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(RetPos, RetAttrs); | 
|  |  | 
|  | // Every function with pointer return type might be marked noalias. | 
|  | checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(RetPos, RetAttrs); | 
|  |  | 
|  | // Every function with pointer return type might be marked | 
|  | // dereferenceable. | 
|  | getOrCreateAAFor<AADereferenceable>(RetPos); | 
|  | } else if (AttributeFuncs::isNoFPClassCompatibleType(ReturnType)) { | 
|  | getOrCreateAAFor<AANoFPClass>(RetPos); | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (Argument &Arg : F.args()) { | 
|  | IRPosition ArgPos = IRPosition::argument(Arg); | 
|  | auto ArgNo = Arg.getArgNo(); | 
|  | AttributeSet ArgAttrs = Attrs.getParamAttrs(ArgNo); | 
|  |  | 
|  | if (!IsIPOAmendable) { | 
|  | if (Arg.getType()->isPointerTy()) | 
|  | // Every argument with pointer type might be marked nofree. | 
|  | checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(ArgPos, ArgAttrs); | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Every argument might be simplified. We have to go through the | 
|  | // Attributor interface though as outside AAs can register custom | 
|  | // simplification callbacks. | 
|  | bool UsedAssumedInformation = false; | 
|  | getAssumedSimplified(ArgPos, /* AA */ nullptr, UsedAssumedInformation, | 
|  | AA::Intraprocedural); | 
|  |  | 
|  | // Every argument might be dead. | 
|  | getOrCreateAAFor<AAIsDead>(ArgPos); | 
|  |  | 
|  | // Every argument might be marked noundef. | 
|  | checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(ArgPos, ArgAttrs); | 
|  |  | 
|  | if (Arg.getType()->isPointerTy()) { | 
|  | // Every argument with pointer type might be marked nonnull. | 
|  | checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(ArgPos, ArgAttrs); | 
|  |  | 
|  | // Every argument with pointer type might be marked noalias. | 
|  | checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(ArgPos, ArgAttrs); | 
|  |  | 
|  | // Every argument with pointer type might be marked dereferenceable. | 
|  | getOrCreateAAFor<AADereferenceable>(ArgPos); | 
|  |  | 
|  | // Every argument with pointer type might be marked align. | 
|  | getOrCreateAAFor<AAAlign>(ArgPos); | 
|  |  | 
|  | // Every argument with pointer type might be marked nocapture. | 
|  | checkAndQueryIRAttr<Attribute::Captures, AANoCapture>( | 
|  | ArgPos, ArgAttrs, /*SkipHasAttrCheck=*/true); | 
|  |  | 
|  | // Every argument with pointer type might be marked | 
|  | // "readnone/readonly/writeonly/..." | 
|  | getOrCreateAAFor<AAMemoryBehavior>(ArgPos); | 
|  |  | 
|  | // Every argument with pointer type might be marked nofree. | 
|  | checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(ArgPos, ArgAttrs); | 
|  |  | 
|  | // Every argument with pointer type might be privatizable (or | 
|  | // promotable) | 
|  | getOrCreateAAFor<AAPrivatizablePtr>(ArgPos); | 
|  | } else if (AttributeFuncs::isNoFPClassCompatibleType(Arg.getType())) { | 
|  | getOrCreateAAFor<AANoFPClass>(ArgPos); | 
|  | } | 
|  | } | 
|  |  | 
|  | auto CallSitePred = [&](Instruction &I) -> bool { | 
|  | auto &CB = cast<CallBase>(I); | 
|  | IRPosition CBInstPos = IRPosition::inst(CB); | 
|  | IRPosition CBFnPos = IRPosition::callsite_function(CB); | 
|  |  | 
|  | // Call sites might be dead if they do not have side effects and no live | 
|  | // users. The return value might be dead if there are no live users. | 
|  | getOrCreateAAFor<AAIsDead>(CBInstPos); | 
|  |  | 
|  | Function *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand()); | 
|  | // TODO: Even if the callee is not known now we might be able to simplify | 
|  | //       the call/callee. | 
|  | if (!Callee) { | 
|  | getOrCreateAAFor<AAIndirectCallInfo>(CBFnPos); | 
|  | return true; | 
|  | } | 
|  |  | 
|  | // Every call site can track active assumptions. | 
|  | getOrCreateAAFor<AAAssumptionInfo>(CBFnPos); | 
|  |  | 
|  | // Skip declarations except if annotations on their call sites were | 
|  | // explicitly requested. | 
|  | if (!AnnotateDeclarationCallSites && Callee->isDeclaration() && | 
|  | !Callee->hasMetadata(LLVMContext::MD_callback)) | 
|  | return true; | 
|  |  | 
|  | if (!Callee->getReturnType()->isVoidTy() && !CB.use_empty()) { | 
|  | IRPosition CBRetPos = IRPosition::callsite_returned(CB); | 
|  | bool UsedAssumedInformation = false; | 
|  | getAssumedSimplified(CBRetPos, nullptr, UsedAssumedInformation, | 
|  | AA::Intraprocedural); | 
|  |  | 
|  | if (AttributeFuncs::isNoFPClassCompatibleType(Callee->getReturnType())) | 
|  | getOrCreateAAFor<AANoFPClass>(CBInstPos); | 
|  | } | 
|  |  | 
|  | const AttributeList &CBAttrs = CBFnPos.getAttrList(); | 
|  | for (int I = 0, E = CB.arg_size(); I < E; ++I) { | 
|  |  | 
|  | IRPosition CBArgPos = IRPosition::callsite_argument(CB, I); | 
|  | AttributeSet CBArgAttrs = CBAttrs.getParamAttrs(I); | 
|  |  | 
|  | // Every call site argument might be dead. | 
|  | getOrCreateAAFor<AAIsDead>(CBArgPos); | 
|  |  | 
|  | // Call site argument might be simplified. We have to go through the | 
|  | // Attributor interface though as outside AAs can register custom | 
|  | // simplification callbacks. | 
|  | bool UsedAssumedInformation = false; | 
|  | getAssumedSimplified(CBArgPos, /* AA */ nullptr, UsedAssumedInformation, | 
|  | AA::Intraprocedural); | 
|  |  | 
|  | // Every call site argument might be marked "noundef". | 
|  | checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(CBArgPos, CBArgAttrs); | 
|  |  | 
|  | Type *ArgTy = CB.getArgOperand(I)->getType(); | 
|  |  | 
|  | if (!ArgTy->isPointerTy()) { | 
|  | if (AttributeFuncs::isNoFPClassCompatibleType(ArgTy)) | 
|  | getOrCreateAAFor<AANoFPClass>(CBArgPos); | 
|  |  | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Call site argument attribute "non-null". | 
|  | checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(CBArgPos, CBArgAttrs); | 
|  |  | 
|  | // Call site argument attribute "captures(none)". | 
|  | checkAndQueryIRAttr<Attribute::Captures, AANoCapture>( | 
|  | CBArgPos, CBArgAttrs, /*SkipHasAttrCheck=*/true); | 
|  |  | 
|  | // Call site argument attribute "no-alias". | 
|  | checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(CBArgPos, CBArgAttrs); | 
|  |  | 
|  | // Call site argument attribute "dereferenceable". | 
|  | getOrCreateAAFor<AADereferenceable>(CBArgPos); | 
|  |  | 
|  | // Call site argument attribute "align". | 
|  | getOrCreateAAFor<AAAlign>(CBArgPos); | 
|  |  | 
|  | // Call site argument attribute | 
|  | // "readnone/readonly/writeonly/..." | 
|  | if (!CBAttrs.hasParamAttr(I, Attribute::ReadNone)) | 
|  | getOrCreateAAFor<AAMemoryBehavior>(CBArgPos); | 
|  |  | 
|  | // Call site argument attribute "nofree". | 
|  | checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(CBArgPos, CBArgAttrs); | 
|  | } | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F); | 
|  | [[maybe_unused]] bool Success; | 
|  | bool UsedAssumedInformation = false; | 
|  | Success = checkForAllInstructionsImpl( | 
|  | nullptr, OpcodeInstMap, CallSitePred, nullptr, nullptr, | 
|  | {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr, | 
|  | (unsigned)Instruction::Call}, | 
|  | UsedAssumedInformation); | 
|  | assert(Success && "Expected the check call to be successful!"); | 
|  |  | 
|  | auto LoadStorePred = [&](Instruction &I) -> bool { | 
|  | if (auto *LI = dyn_cast<LoadInst>(&I)) { | 
|  | getOrCreateAAFor<AAAlign>(IRPosition::value(*LI->getPointerOperand())); | 
|  | if (SimplifyAllLoads) | 
|  | getAssumedSimplified(IRPosition::value(I), nullptr, | 
|  | UsedAssumedInformation, AA::Intraprocedural); | 
|  | getOrCreateAAFor<AAInvariantLoadPointer>( | 
|  | IRPosition::value(*LI->getPointerOperand())); | 
|  | getOrCreateAAFor<AAAddressSpace>( | 
|  | IRPosition::value(*LI->getPointerOperand())); | 
|  | } else { | 
|  | auto &SI = cast<StoreInst>(I); | 
|  | getOrCreateAAFor<AAIsDead>(IRPosition::inst(I)); | 
|  | getAssumedSimplified(IRPosition::value(*SI.getValueOperand()), nullptr, | 
|  | UsedAssumedInformation, AA::Intraprocedural); | 
|  | getOrCreateAAFor<AAAlign>(IRPosition::value(*SI.getPointerOperand())); | 
|  | getOrCreateAAFor<AAAddressSpace>( | 
|  | IRPosition::value(*SI.getPointerOperand())); | 
|  | } | 
|  | return true; | 
|  | }; | 
|  | Success = checkForAllInstructionsImpl( | 
|  | nullptr, OpcodeInstMap, LoadStorePred, nullptr, nullptr, | 
|  | {(unsigned)Instruction::Load, (unsigned)Instruction::Store}, | 
|  | UsedAssumedInformation); | 
|  | assert(Success && "Expected the check call to be successful!"); | 
|  |  | 
|  | // AllocaInstPredicate | 
|  | auto AAAllocationInfoPred = [&](Instruction &I) -> bool { | 
|  | getOrCreateAAFor<AAAllocationInfo>(IRPosition::value(I)); | 
|  | return true; | 
|  | }; | 
|  |  | 
|  | Success = checkForAllInstructionsImpl( | 
|  | nullptr, OpcodeInstMap, AAAllocationInfoPred, nullptr, nullptr, | 
|  | {(unsigned)Instruction::Alloca}, UsedAssumedInformation); | 
|  | assert(Success && "Expected the check call to be successful!"); | 
|  | } | 
|  |  | 
|  | bool Attributor::isClosedWorldModule() const { | 
|  | if (CloseWorldAssumption.getNumOccurrences()) | 
|  | return CloseWorldAssumption; | 
|  | return isModulePass() && Configuration.IsClosedWorldModule; | 
|  | } | 
|  |  | 
|  | /// Helpers to ease debugging through output streams and print calls. | 
|  | /// | 
|  | ///{ | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) { | 
|  | return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged"); | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) { | 
|  | switch (AP) { | 
|  | case IRPosition::IRP_INVALID: | 
|  | return OS << "inv"; | 
|  | case IRPosition::IRP_FLOAT: | 
|  | return OS << "flt"; | 
|  | case IRPosition::IRP_RETURNED: | 
|  | return OS << "fn_ret"; | 
|  | case IRPosition::IRP_CALL_SITE_RETURNED: | 
|  | return OS << "cs_ret"; | 
|  | case IRPosition::IRP_FUNCTION: | 
|  | return OS << "fn"; | 
|  | case IRPosition::IRP_CALL_SITE: | 
|  | return OS << "cs"; | 
|  | case IRPosition::IRP_ARGUMENT: | 
|  | return OS << "arg"; | 
|  | case IRPosition::IRP_CALL_SITE_ARGUMENT: | 
|  | return OS << "cs_arg"; | 
|  | } | 
|  | llvm_unreachable("Unknown attribute position!"); | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) { | 
|  | const Value &AV = Pos.getAssociatedValue(); | 
|  | OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " [" | 
|  | << Pos.getAnchorValue().getName() << "@" << Pos.getCallSiteArgNo() << "]"; | 
|  |  | 
|  | if (Pos.hasCallBaseContext()) | 
|  | OS << "[cb_context:" << *Pos.getCallBaseContext() << "]"; | 
|  | return OS << "}"; | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) { | 
|  | OS << "range-state(" << S.getBitWidth() << ")<"; | 
|  | S.getKnown().print(OS); | 
|  | OS << " / "; | 
|  | S.getAssumed().print(OS); | 
|  | OS << ">"; | 
|  |  | 
|  | return OS << static_cast<const AbstractState &>(S); | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) { | 
|  | return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : "")); | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) { | 
|  | AA.print(OS); | 
|  | return OS; | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, | 
|  | const PotentialConstantIntValuesState &S) { | 
|  | OS << "set-state(< {"; | 
|  | if (!S.isValidState()) | 
|  | OS << "full-set"; | 
|  | else { | 
|  | for (const auto &It : S.getAssumedSet()) | 
|  | OS << It << ", "; | 
|  | if (S.undefIsContained()) | 
|  | OS << "undef "; | 
|  | } | 
|  | OS << "} >)"; | 
|  |  | 
|  | return OS; | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, | 
|  | const PotentialLLVMValuesState &S) { | 
|  | OS << "set-state(< {"; | 
|  | if (!S.isValidState()) | 
|  | OS << "full-set"; | 
|  | else { | 
|  | for (const auto &It : S.getAssumedSet()) { | 
|  | if (auto *F = dyn_cast<Function>(It.first.getValue())) | 
|  | OS << "@" << F->getName() << "[" << int(It.second) << "], "; | 
|  | else | 
|  | OS << *It.first.getValue() << "[" << int(It.second) << "], "; | 
|  | } | 
|  | if (S.undefIsContained()) | 
|  | OS << "undef "; | 
|  | } | 
|  | OS << "} >)"; | 
|  |  | 
|  | return OS; | 
|  | } | 
|  |  | 
|  | void AbstractAttribute::print(Attributor *A, raw_ostream &OS) const { | 
|  | OS << "["; | 
|  | OS << getName(); | 
|  | OS << "] for CtxI "; | 
|  |  | 
|  | if (auto *I = getCtxI()) { | 
|  | OS << "'"; | 
|  | I->print(OS); | 
|  | OS << "'"; | 
|  | } else | 
|  | OS << "<<null inst>>"; | 
|  |  | 
|  | OS << " at position " << getIRPosition() << " with state " << getAsStr(A) | 
|  | << '\n'; | 
|  | } | 
|  |  | 
|  | void AbstractAttribute::printWithDeps(raw_ostream &OS) const { | 
|  | print(OS); | 
|  |  | 
|  | for (const auto &DepAA : Deps) { | 
|  | auto *AA = DepAA.getPointer(); | 
|  | OS << "  updates "; | 
|  | AA->print(OS); | 
|  | } | 
|  |  | 
|  | OS << '\n'; | 
|  | } | 
|  |  | 
|  | raw_ostream &llvm::operator<<(raw_ostream &OS, | 
|  | const AAPointerInfo::Access &Acc) { | 
|  | OS << " [" << Acc.getKind() << "] " << *Acc.getRemoteInst(); | 
|  | if (Acc.getLocalInst() != Acc.getRemoteInst()) | 
|  | OS << " via " << *Acc.getLocalInst(); | 
|  | if (Acc.getContent()) { | 
|  | if (*Acc.getContent()) | 
|  | OS << " [" << **Acc.getContent() << "]"; | 
|  | else | 
|  | OS << " [ <unknown> ]"; | 
|  | } | 
|  | return OS; | 
|  | } | 
|  | ///} | 
|  |  | 
|  | /// ---------------------------------------------------------------------------- | 
|  | ///                       Pass (Manager) Boilerplate | 
|  | /// ---------------------------------------------------------------------------- | 
|  |  | 
|  | static bool runAttributorOnFunctions(InformationCache &InfoCache, | 
|  | SetVector<Function *> &Functions, | 
|  | AnalysisGetter &AG, | 
|  | CallGraphUpdater &CGUpdater, | 
|  | bool DeleteFns, bool IsModulePass) { | 
|  | if (Functions.empty()) | 
|  | return false; | 
|  |  | 
|  | LLVM_DEBUG({ | 
|  | dbgs() << "[Attributor] Run on module with " << Functions.size() | 
|  | << " functions:\n"; | 
|  | for (Function *Fn : Functions) | 
|  | dbgs() << "  - " << Fn->getName() << "\n"; | 
|  | }); | 
|  |  | 
|  | // Create an Attributor and initially empty information cache that is filled | 
|  | // while we identify default attribute opportunities. | 
|  | AttributorConfig AC(CGUpdater); | 
|  | AC.IsModulePass = IsModulePass; | 
|  | AC.DeleteFns = DeleteFns; | 
|  |  | 
|  | /// Tracking callback for specialization of indirect calls. | 
|  | DenseMap<CallBase *, std::unique_ptr<SmallPtrSet<Function *, 8>>> | 
|  | IndirectCalleeTrackingMap; | 
|  | if (MaxSpecializationPerCB.getNumOccurrences()) { | 
|  | AC.IndirectCalleeSpecializationCallback = | 
|  | [&](Attributor &, const AbstractAttribute &AA, CallBase &CB, | 
|  | Function &Callee, unsigned) { | 
|  | if (MaxSpecializationPerCB == 0) | 
|  | return false; | 
|  | auto &Set = IndirectCalleeTrackingMap[&CB]; | 
|  | if (!Set) | 
|  | Set = std::make_unique<SmallPtrSet<Function *, 8>>(); | 
|  | if (Set->size() >= MaxSpecializationPerCB) | 
|  | return Set->contains(&Callee); | 
|  | Set->insert(&Callee); | 
|  | return true; | 
|  | }; | 
|  | } | 
|  |  | 
|  | Attributor A(Functions, InfoCache, AC); | 
|  |  | 
|  | // Create shallow wrappers for all functions that are not IPO amendable | 
|  | if (AllowShallowWrappers) | 
|  | for (Function *F : Functions) | 
|  | if (!A.isFunctionIPOAmendable(*F)) | 
|  | Attributor::createShallowWrapper(*F); | 
|  |  | 
|  | // Internalize non-exact functions | 
|  | // TODO: for now we eagerly internalize functions without calculating the | 
|  | //       cost, we need a cost interface to determine whether internalizing | 
|  | //       a function is "beneficial" | 
|  | if (AllowDeepWrapper) { | 
|  | unsigned FunSize = Functions.size(); | 
|  | for (unsigned u = 0; u < FunSize; u++) { | 
|  | Function *F = Functions[u]; | 
|  | if (!F->isDeclaration() && !F->isDefinitionExact() && !F->use_empty() && | 
|  | !GlobalValue::isInterposableLinkage(F->getLinkage())) { | 
|  | Function *NewF = Attributor::internalizeFunction(*F); | 
|  | assert(NewF && "Could not internalize function."); | 
|  | Functions.insert(NewF); | 
|  |  | 
|  | // Update call graph | 
|  | CGUpdater.replaceFunctionWith(*F, *NewF); | 
|  | for (const Use &U : NewF->uses()) | 
|  | if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) { | 
|  | auto *CallerF = CB->getCaller(); | 
|  | CGUpdater.reanalyzeFunction(*CallerF); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  |  | 
|  | for (Function *F : Functions) { | 
|  | if (F->hasExactDefinition()) | 
|  | NumFnWithExactDefinition++; | 
|  | else | 
|  | NumFnWithoutExactDefinition++; | 
|  |  | 
|  | // We look at internal functions only on-demand but if any use is not a | 
|  | // direct call or outside the current set of analyzed functions, we have | 
|  | // to do it eagerly. | 
|  | if (F->hasLocalLinkage()) { | 
|  | if (llvm::all_of(F->uses(), [&Functions](const Use &U) { | 
|  | const auto *CB = dyn_cast<CallBase>(U.getUser()); | 
|  | return CB && CB->isCallee(&U) && | 
|  | Functions.count(const_cast<Function *>(CB->getCaller())); | 
|  | })) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Populate the Attributor with abstract attribute opportunities in the | 
|  | // function and the information cache with IR information. | 
|  | A.identifyDefaultAbstractAttributes(*F); | 
|  | } | 
|  |  | 
|  | ChangeStatus Changed = A.run(); | 
|  |  | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() | 
|  | << " functions, result: " << Changed << ".\n"); | 
|  | return Changed == ChangeStatus::CHANGED; | 
|  | } | 
|  |  | 
|  | static bool runAttributorLightOnFunctions(InformationCache &InfoCache, | 
|  | SetVector<Function *> &Functions, | 
|  | AnalysisGetter &AG, | 
|  | CallGraphUpdater &CGUpdater, | 
|  | FunctionAnalysisManager &FAM, | 
|  | bool IsModulePass) { | 
|  | if (Functions.empty()) | 
|  | return false; | 
|  |  | 
|  | LLVM_DEBUG({ | 
|  | dbgs() << "[AttributorLight] Run on module with " << Functions.size() | 
|  | << " functions:\n"; | 
|  | for (Function *Fn : Functions) | 
|  | dbgs() << "  - " << Fn->getName() << "\n"; | 
|  | }); | 
|  |  | 
|  | // Create an Attributor and initially empty information cache that is filled | 
|  | // while we identify default attribute opportunities. | 
|  | AttributorConfig AC(CGUpdater); | 
|  | AC.IsModulePass = IsModulePass; | 
|  | AC.DeleteFns = false; | 
|  | DenseSet<const char *> Allowed( | 
|  | {&AAWillReturn::ID, &AANoUnwind::ID, &AANoRecurse::ID, &AANoSync::ID, | 
|  | &AANoFree::ID, &AANoReturn::ID, &AAMemoryLocation::ID, | 
|  | &AAMemoryBehavior::ID, &AAUnderlyingObjects::ID, &AANoCapture::ID, | 
|  | &AAInterFnReachability::ID, &AAIntraFnReachability::ID, &AACallEdges::ID, | 
|  | &AANoFPClass::ID, &AAMustProgress::ID, &AANonNull::ID}); | 
|  | AC.Allowed = &Allowed; | 
|  | AC.UseLiveness = false; | 
|  |  | 
|  | Attributor A(Functions, InfoCache, AC); | 
|  |  | 
|  | for (Function *F : Functions) { | 
|  | if (F->hasExactDefinition()) | 
|  | NumFnWithExactDefinition++; | 
|  | else | 
|  | NumFnWithoutExactDefinition++; | 
|  |  | 
|  | // We look at internal functions only on-demand but if any use is not a | 
|  | // direct call or outside the current set of analyzed functions, we have | 
|  | // to do it eagerly. | 
|  | if (AC.UseLiveness && F->hasLocalLinkage()) { | 
|  | if (llvm::all_of(F->uses(), [&Functions](const Use &U) { | 
|  | const auto *CB = dyn_cast<CallBase>(U.getUser()); | 
|  | return CB && CB->isCallee(&U) && | 
|  | Functions.count(const_cast<Function *>(CB->getCaller())); | 
|  | })) | 
|  | continue; | 
|  | } | 
|  |  | 
|  | // Populate the Attributor with abstract attribute opportunities in the | 
|  | // function and the information cache with IR information. | 
|  | A.identifyDefaultAbstractAttributes(*F); | 
|  | } | 
|  |  | 
|  | ChangeStatus Changed = A.run(); | 
|  |  | 
|  | if (Changed == ChangeStatus::CHANGED) { | 
|  | // Invalidate analyses for modified functions so that we don't have to | 
|  | // invalidate all analyses for all functions in this SCC. | 
|  | PreservedAnalyses FuncPA; | 
|  | // We haven't changed the CFG for modified functions. | 
|  | FuncPA.preserveSet<CFGAnalyses>(); | 
|  | for (Function *Changed : A.getModifiedFunctions()) { | 
|  | FAM.invalidate(*Changed, FuncPA); | 
|  | // Also invalidate any direct callers of changed functions since analyses | 
|  | // may care about attributes of direct callees. For example, MemorySSA | 
|  | // cares about whether or not a call's callee modifies memory and queries | 
|  | // that through function attributes. | 
|  | for (auto *U : Changed->users()) { | 
|  | if (auto *Call = dyn_cast<CallBase>(U)) { | 
|  | if (Call->getCalledFunction() == Changed) | 
|  | FAM.invalidate(*Call->getFunction(), FuncPA); | 
|  | } | 
|  | } | 
|  | } | 
|  | } | 
|  | LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size() | 
|  | << " functions, result: " << Changed << ".\n"); | 
|  | return Changed == ChangeStatus::CHANGED; | 
|  | } | 
|  |  | 
|  | void AADepGraph::viewGraph() { llvm::ViewGraph(this, "Dependency Graph"); } | 
|  |  | 
|  | void AADepGraph::dumpGraph() { | 
|  | static std::atomic<int> CallTimes; | 
|  | std::string Prefix; | 
|  |  | 
|  | if (!DepGraphDotFileNamePrefix.empty()) | 
|  | Prefix = DepGraphDotFileNamePrefix; | 
|  | else | 
|  | Prefix = "dep_graph"; | 
|  | std::string Filename = | 
|  | Prefix + "_" + std::to_string(CallTimes.load()) + ".dot"; | 
|  |  | 
|  | outs() << "Dependency graph dump to " << Filename << ".\n"; | 
|  |  | 
|  | std::error_code EC; | 
|  |  | 
|  | raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF); | 
|  | if (!EC) | 
|  | llvm::WriteGraph(File, this); | 
|  |  | 
|  | CallTimes++; | 
|  | } | 
|  |  | 
|  | void AADepGraph::print() { | 
|  | for (auto DepAA : SyntheticRoot.Deps) | 
|  | cast<AbstractAttribute>(DepAA.getPointer())->printWithDeps(outs()); | 
|  | } | 
|  |  | 
|  | PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) { | 
|  | FunctionAnalysisManager &FAM = | 
|  | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | 
|  | AnalysisGetter AG(FAM); | 
|  |  | 
|  | SetVector<Function *> Functions; | 
|  | for (Function &F : M) | 
|  | Functions.insert(&F); | 
|  |  | 
|  | CallGraphUpdater CGUpdater; | 
|  | BumpPtrAllocator Allocator; | 
|  | InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr); | 
|  | if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, | 
|  | /* DeleteFns */ true, /* IsModulePass */ true)) { | 
|  | // FIXME: Think about passes we will preserve and add them here. | 
|  | return PreservedAnalyses::none(); | 
|  | } | 
|  | return PreservedAnalyses::all(); | 
|  | } | 
|  |  | 
|  | PreservedAnalyses AttributorCGSCCPass::run(LazyCallGraph::SCC &C, | 
|  | CGSCCAnalysisManager &AM, | 
|  | LazyCallGraph &CG, | 
|  | CGSCCUpdateResult &UR) { | 
|  | FunctionAnalysisManager &FAM = | 
|  | AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); | 
|  | AnalysisGetter AG(FAM); | 
|  |  | 
|  | SetVector<Function *> Functions; | 
|  | for (LazyCallGraph::Node &N : C) | 
|  | Functions.insert(&N.getFunction()); | 
|  |  | 
|  | if (Functions.empty()) | 
|  | return PreservedAnalyses::all(); | 
|  |  | 
|  | Module &M = *Functions.back()->getParent(); | 
|  | CallGraphUpdater CGUpdater; | 
|  | CGUpdater.initialize(CG, C, AM, UR); | 
|  | BumpPtrAllocator Allocator; | 
|  | InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions); | 
|  | if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater, | 
|  | /* DeleteFns */ false, | 
|  | /* IsModulePass */ false)) { | 
|  | // FIXME: Think about passes we will preserve and add them here. | 
|  | PreservedAnalyses PA; | 
|  | PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); | 
|  | return PA; | 
|  | } | 
|  | return PreservedAnalyses::all(); | 
|  | } | 
|  |  | 
|  | PreservedAnalyses AttributorLightPass::run(Module &M, | 
|  | ModuleAnalysisManager &AM) { | 
|  | FunctionAnalysisManager &FAM = | 
|  | AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager(); | 
|  | AnalysisGetter AG(FAM, /* CachedOnly */ true); | 
|  |  | 
|  | SetVector<Function *> Functions; | 
|  | for (Function &F : M) | 
|  | Functions.insert(&F); | 
|  |  | 
|  | CallGraphUpdater CGUpdater; | 
|  | BumpPtrAllocator Allocator; | 
|  | InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr); | 
|  | if (runAttributorLightOnFunctions(InfoCache, Functions, AG, CGUpdater, FAM, | 
|  | /* IsModulePass */ true)) { | 
|  | PreservedAnalyses PA; | 
|  | // We have not added or removed functions. | 
|  | PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); | 
|  | // We already invalidated all relevant function analyses above. | 
|  | PA.preserveSet<AllAnalysesOn<Function>>(); | 
|  | return PA; | 
|  | } | 
|  | return PreservedAnalyses::all(); | 
|  | } | 
|  |  | 
|  | PreservedAnalyses AttributorLightCGSCCPass::run(LazyCallGraph::SCC &C, | 
|  | CGSCCAnalysisManager &AM, | 
|  | LazyCallGraph &CG, | 
|  | CGSCCUpdateResult &UR) { | 
|  | FunctionAnalysisManager &FAM = | 
|  | AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager(); | 
|  | AnalysisGetter AG(FAM); | 
|  |  | 
|  | SetVector<Function *> Functions; | 
|  | for (LazyCallGraph::Node &N : C) | 
|  | Functions.insert(&N.getFunction()); | 
|  |  | 
|  | if (Functions.empty()) | 
|  | return PreservedAnalyses::all(); | 
|  |  | 
|  | Module &M = *Functions.back()->getParent(); | 
|  | CallGraphUpdater CGUpdater; | 
|  | CGUpdater.initialize(CG, C, AM, UR); | 
|  | BumpPtrAllocator Allocator; | 
|  | InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions); | 
|  | if (runAttributorLightOnFunctions(InfoCache, Functions, AG, CGUpdater, FAM, | 
|  | /* IsModulePass */ false)) { | 
|  | PreservedAnalyses PA; | 
|  | // We have not added or removed functions. | 
|  | PA.preserve<FunctionAnalysisManagerCGSCCProxy>(); | 
|  | // We already invalidated all relevant function analyses above. | 
|  | PA.preserveSet<AllAnalysesOn<Function>>(); | 
|  | return PA; | 
|  | } | 
|  | return PreservedAnalyses::all(); | 
|  | } | 
|  | namespace llvm { | 
|  |  | 
|  | template <> struct GraphTraits<AADepGraphNode *> { | 
|  | using NodeRef = AADepGraphNode *; | 
|  | using DepTy = PointerIntPair<AADepGraphNode *, 1>; | 
|  | using EdgeRef = PointerIntPair<AADepGraphNode *, 1>; | 
|  |  | 
|  | static NodeRef getEntryNode(AADepGraphNode *DGN) { return DGN; } | 
|  | static NodeRef DepGetVal(const DepTy &DT) { return DT.getPointer(); } | 
|  |  | 
|  | using ChildIteratorType = | 
|  | mapped_iterator<AADepGraphNode::DepSetTy::iterator, decltype(&DepGetVal)>; | 
|  | using ChildEdgeIteratorType = AADepGraphNode::DepSetTy::iterator; | 
|  |  | 
|  | static ChildIteratorType child_begin(NodeRef N) { return N->child_begin(); } | 
|  |  | 
|  | static ChildIteratorType child_end(NodeRef N) { return N->child_end(); } | 
|  | }; | 
|  |  | 
|  | template <> | 
|  | struct GraphTraits<AADepGraph *> : public GraphTraits<AADepGraphNode *> { | 
|  | static NodeRef getEntryNode(AADepGraph *DG) { return DG->GetEntryNode(); } | 
|  |  | 
|  | using nodes_iterator = | 
|  | mapped_iterator<AADepGraphNode::DepSetTy::iterator, decltype(&DepGetVal)>; | 
|  |  | 
|  | static nodes_iterator nodes_begin(AADepGraph *DG) { return DG->begin(); } | 
|  |  | 
|  | static nodes_iterator nodes_end(AADepGraph *DG) { return DG->end(); } | 
|  | }; | 
|  |  | 
|  | template <> struct DOTGraphTraits<AADepGraph *> : public DefaultDOTGraphTraits { | 
|  | DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {} | 
|  |  | 
|  | static std::string getNodeLabel(const AADepGraphNode *Node, | 
|  | const AADepGraph *DG) { | 
|  | std::string AAString; | 
|  | raw_string_ostream O(AAString); | 
|  | Node->print(O); | 
|  | return AAString; | 
|  | } | 
|  | }; | 
|  |  | 
|  | } // end namespace llvm |