10b57cec5SDimitry Andric //===- Attributor.cpp - Module-wide attribute deduction -------------------===//
20b57cec5SDimitry Andric //
30b57cec5SDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
40b57cec5SDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
50b57cec5SDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
60b57cec5SDimitry Andric //
70b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
80b57cec5SDimitry Andric //
95ffd83dbSDimitry Andric // This file implements an interprocedural pass that deduces and/or propagates
100b57cec5SDimitry Andric // attributes. This is done in an abstract interpretation style fixpoint
110b57cec5SDimitry Andric // iteration. See the Attributor.h file comment and the class descriptions in
120b57cec5SDimitry Andric // that file for more information.
130b57cec5SDimitry Andric //
140b57cec5SDimitry Andric //===----------------------------------------------------------------------===//
150b57cec5SDimitry Andric
160b57cec5SDimitry Andric #include "llvm/Transforms/IPO/Attributor.h"
170b57cec5SDimitry Andric
1806c3fb27SDimitry Andric #include "llvm/ADT/ArrayRef.h"
19e8d8bef9SDimitry Andric #include "llvm/ADT/PointerIntPair.h"
20fe6060f1SDimitry Andric #include "llvm/ADT/STLExtras.h"
215f757f3fSDimitry Andric #include "llvm/ADT/SmallPtrSet.h"
220b57cec5SDimitry Andric #include "llvm/ADT/Statistic.h"
2381ad6265SDimitry Andric #include "llvm/Analysis/AliasAnalysis.h"
2481ad6265SDimitry Andric #include "llvm/Analysis/CallGraph.h"
2581ad6265SDimitry Andric #include "llvm/Analysis/CallGraphSCCPass.h"
26e8d8bef9SDimitry Andric #include "llvm/Analysis/InlineCost.h"
2704eeddc0SDimitry Andric #include "llvm/Analysis/MemoryBuiltins.h"
285ffd83dbSDimitry Andric #include "llvm/Analysis/MustExecute.h"
2906c3fb27SDimitry Andric #include "llvm/IR/AttributeMask.h"
30fe6060f1SDimitry Andric #include "llvm/IR/Attributes.h"
31fe6060f1SDimitry Andric #include "llvm/IR/Constant.h"
32bdd1243dSDimitry Andric #include "llvm/IR/ConstantFold.h"
33fe6060f1SDimitry Andric #include "llvm/IR/Constants.h"
34bdd1243dSDimitry Andric #include "llvm/IR/DataLayout.h"
35e8d8bef9SDimitry Andric #include "llvm/IR/GlobalValue.h"
36fe6060f1SDimitry Andric #include "llvm/IR/GlobalVariable.h"
37fe6060f1SDimitry Andric #include "llvm/IR/Instruction.h"
386e75b2fbSDimitry Andric #include "llvm/IR/Instructions.h"
39fe6060f1SDimitry Andric #include "llvm/IR/IntrinsicInst.h"
4006c3fb27SDimitry Andric #include "llvm/IR/LLVMContext.h"
41fe6060f1SDimitry Andric #include "llvm/IR/ValueHandle.h"
425ffd83dbSDimitry Andric #include "llvm/Support/Casting.h"
430b57cec5SDimitry Andric #include "llvm/Support/CommandLine.h"
44e8d8bef9SDimitry Andric #include "llvm/Support/Debug.h"
45e8d8bef9SDimitry Andric #include "llvm/Support/DebugCounter.h"
46e8d8bef9SDimitry Andric #include "llvm/Support/FileSystem.h"
47e8d8bef9SDimitry Andric #include "llvm/Support/GraphWriter.h"
4806c3fb27SDimitry Andric #include "llvm/Support/ModRef.h"
49e8d8bef9SDimitry Andric #include "llvm/Support/raw_ostream.h"
508bcb0991SDimitry Andric #include "llvm/Transforms/Utils/BasicBlockUtils.h"
51e8d8bef9SDimitry Andric #include "llvm/Transforms/Utils/Cloning.h"
528bcb0991SDimitry Andric #include "llvm/Transforms/Utils/Local.h"
53bdd1243dSDimitry Andric #include <cstdint>
545f757f3fSDimitry Andric #include <memory>
558bcb0991SDimitry Andric
5681ad6265SDimitry Andric #ifdef EXPENSIVE_CHECKS
5781ad6265SDimitry Andric #include "llvm/IR/Verifier.h"
5881ad6265SDimitry Andric #endif
5981ad6265SDimitry Andric
600b57cec5SDimitry Andric #include <cassert>
61bdd1243dSDimitry Andric #include <optional>
62e8d8bef9SDimitry Andric #include <string>
630b57cec5SDimitry Andric
640b57cec5SDimitry Andric using namespace llvm;
650b57cec5SDimitry Andric
660b57cec5SDimitry Andric #define DEBUG_TYPE "attributor"
67bdd1243dSDimitry Andric #define VERBOSE_DEBUG_TYPE DEBUG_TYPE "-verbose"
680b57cec5SDimitry Andric
69e8d8bef9SDimitry Andric DEBUG_COUNTER(ManifestDBGCounter, "attributor-manifest",
70e8d8bef9SDimitry Andric "Determine what attributes are manifested in the IR");
71e8d8bef9SDimitry Andric
725ffd83dbSDimitry Andric STATISTIC(NumFnDeleted, "Number of function deleted");
730b57cec5SDimitry Andric STATISTIC(NumFnWithExactDefinition,
745ffd83dbSDimitry Andric "Number of functions with exact definitions");
750b57cec5SDimitry Andric STATISTIC(NumFnWithoutExactDefinition,
765ffd83dbSDimitry Andric "Number of functions without exact definitions");
77e8d8bef9SDimitry Andric STATISTIC(NumFnShallowWrappersCreated, "Number of shallow wrappers created");
780b57cec5SDimitry Andric STATISTIC(NumAttributesTimedOut,
790b57cec5SDimitry Andric "Number of abstract attributes timed out before fixpoint");
800b57cec5SDimitry Andric STATISTIC(NumAttributesValidFixpoint,
810b57cec5SDimitry Andric "Number of abstract attributes in a valid fixpoint state");
820b57cec5SDimitry Andric STATISTIC(NumAttributesManifested,
830b57cec5SDimitry Andric "Number of abstract attributes manifested in IR");
840b57cec5SDimitry Andric
850b57cec5SDimitry Andric // TODO: Determine a good default value.
860b57cec5SDimitry Andric //
870b57cec5SDimitry Andric // In the LLVM-TS and SPEC2006, 32 seems to not induce compile time overheads
880b57cec5SDimitry Andric // (when run with the first 5 abstract attributes). The results also indicate
890b57cec5SDimitry Andric // that we never reach 32 iterations but always find a fixpoint sooner.
900b57cec5SDimitry Andric //
910b57cec5SDimitry Andric // This will become more evolved once we perform two interleaved fixpoint
920b57cec5SDimitry Andric // iterations: bottom-up and top-down.
930b57cec5SDimitry Andric static cl::opt<unsigned>
94fe6060f1SDimitry Andric SetFixpointIterations("attributor-max-iterations", cl::Hidden,
950b57cec5SDimitry Andric cl::desc("Maximal number of fixpoint iterations."),
960b57cec5SDimitry Andric cl::init(32));
97e8d8bef9SDimitry Andric
985f757f3fSDimitry Andric static cl::opt<unsigned>
995f757f3fSDimitry Andric MaxSpecializationPerCB("attributor-max-specializations-per-call-base",
1005f757f3fSDimitry Andric cl::Hidden,
1015f757f3fSDimitry Andric cl::desc("Maximal number of callees specialized for "
1025f757f3fSDimitry Andric "a call base"),
1035f757f3fSDimitry Andric cl::init(UINT32_MAX));
1045f757f3fSDimitry Andric
105e8d8bef9SDimitry Andric static cl::opt<unsigned, true> MaxInitializationChainLengthX(
106e8d8bef9SDimitry Andric "attributor-max-initialization-chain-length", cl::Hidden,
107e8d8bef9SDimitry Andric cl::desc(
108e8d8bef9SDimitry Andric "Maximal number of chained initializations (to avoid stack overflows)"),
109e8d8bef9SDimitry Andric cl::location(MaxInitializationChainLength), cl::init(1024));
110e8d8bef9SDimitry Andric unsigned llvm::MaxInitializationChainLength;
111e8d8bef9SDimitry Andric
112480093f4SDimitry Andric static cl::opt<bool> AnnotateDeclarationCallSites(
113480093f4SDimitry Andric "attributor-annotate-decl-cs", cl::Hidden,
114480093f4SDimitry Andric cl::desc("Annotate call sites of function declarations."), cl::init(false));
115480093f4SDimitry Andric
1168bcb0991SDimitry Andric static cl::opt<bool> EnableHeapToStack("enable-heap-to-stack-conversion",
1178bcb0991SDimitry Andric cl::init(true), cl::Hidden);
1188bcb0991SDimitry Andric
1195ffd83dbSDimitry Andric static cl::opt<bool>
1205ffd83dbSDimitry Andric AllowShallowWrappers("attributor-allow-shallow-wrappers", cl::Hidden,
1215ffd83dbSDimitry Andric cl::desc("Allow the Attributor to create shallow "
1225ffd83dbSDimitry Andric "wrappers for non-exact definitions."),
1235ffd83dbSDimitry Andric cl::init(false));
1245ffd83dbSDimitry Andric
125e8d8bef9SDimitry Andric static cl::opt<bool>
126e8d8bef9SDimitry Andric AllowDeepWrapper("attributor-allow-deep-wrappers", cl::Hidden,
127e8d8bef9SDimitry Andric cl::desc("Allow the Attributor to use IP information "
128e8d8bef9SDimitry Andric "derived from non-exact functions via cloning"),
129e8d8bef9SDimitry Andric cl::init(false));
130e8d8bef9SDimitry Andric
131e8d8bef9SDimitry Andric // These options can only used for debug builds.
132e8d8bef9SDimitry Andric #ifndef NDEBUG
1335ffd83dbSDimitry Andric static cl::list<std::string>
1345ffd83dbSDimitry Andric SeedAllowList("attributor-seed-allow-list", cl::Hidden,
135*0fca6ea1SDimitry Andric cl::desc("Comma separated list of attribute names that are "
1365ffd83dbSDimitry Andric "allowed to be seeded."),
13781ad6265SDimitry Andric cl::CommaSeparated);
1388bcb0991SDimitry Andric
139e8d8bef9SDimitry Andric static cl::list<std::string> FunctionSeedAllowList(
140e8d8bef9SDimitry Andric "attributor-function-seed-allow-list", cl::Hidden,
141*0fca6ea1SDimitry Andric cl::desc("Comma separated list of function names that are "
142e8d8bef9SDimitry Andric "allowed to be seeded."),
14381ad6265SDimitry Andric cl::CommaSeparated);
144e8d8bef9SDimitry Andric #endif
145e8d8bef9SDimitry Andric
146e8d8bef9SDimitry Andric static cl::opt<bool>
147e8d8bef9SDimitry Andric DumpDepGraph("attributor-dump-dep-graph", cl::Hidden,
148e8d8bef9SDimitry Andric cl::desc("Dump the dependency graph to dot files."),
149e8d8bef9SDimitry Andric cl::init(false));
150e8d8bef9SDimitry Andric
151e8d8bef9SDimitry Andric static cl::opt<std::string> DepGraphDotFileNamePrefix(
152e8d8bef9SDimitry Andric "attributor-depgraph-dot-filename-prefix", cl::Hidden,
153e8d8bef9SDimitry Andric cl::desc("The prefix used for the CallGraph dot file names."));
154e8d8bef9SDimitry Andric
155e8d8bef9SDimitry Andric static cl::opt<bool> ViewDepGraph("attributor-view-dep-graph", cl::Hidden,
156e8d8bef9SDimitry Andric cl::desc("View the dependency graph."),
157e8d8bef9SDimitry Andric cl::init(false));
158e8d8bef9SDimitry Andric
159e8d8bef9SDimitry Andric static cl::opt<bool> PrintDependencies("attributor-print-dep", cl::Hidden,
160e8d8bef9SDimitry Andric cl::desc("Print attribute dependencies"),
161e8d8bef9SDimitry Andric cl::init(false));
162e8d8bef9SDimitry Andric
163fe6060f1SDimitry Andric static cl::opt<bool> EnableCallSiteSpecific(
164fe6060f1SDimitry Andric "attributor-enable-call-site-specific-deduction", cl::Hidden,
165fe6060f1SDimitry Andric cl::desc("Allow the Attributor to do call site specific analysis"),
166fe6060f1SDimitry Andric cl::init(false));
167fe6060f1SDimitry Andric
168fe6060f1SDimitry Andric static cl::opt<bool>
169fe6060f1SDimitry Andric PrintCallGraph("attributor-print-call-graph", cl::Hidden,
170fe6060f1SDimitry Andric cl::desc("Print Attributor's internal call graph"),
171fe6060f1SDimitry Andric cl::init(false));
172fe6060f1SDimitry Andric
173fe6060f1SDimitry Andric static cl::opt<bool> SimplifyAllLoads("attributor-simplify-all-loads",
174fe6060f1SDimitry Andric cl::Hidden,
175fe6060f1SDimitry Andric cl::desc("Try to simplify all loads."),
176fe6060f1SDimitry Andric cl::init(true));
177fe6060f1SDimitry Andric
1785f757f3fSDimitry Andric static cl::opt<bool> CloseWorldAssumption(
1795f757f3fSDimitry Andric "attributor-assume-closed-world", cl::Hidden,
1805f757f3fSDimitry Andric cl::desc("Should a closed world be assumed, or not. Default if not set."));
1815f757f3fSDimitry Andric
1820b57cec5SDimitry Andric /// Logic operators for the change status enum class.
1830b57cec5SDimitry Andric ///
1840b57cec5SDimitry Andric ///{
operator |(ChangeStatus L,ChangeStatus R)185e8d8bef9SDimitry Andric ChangeStatus llvm::operator|(ChangeStatus L, ChangeStatus R) {
186e8d8bef9SDimitry Andric return L == ChangeStatus::CHANGED ? L : R;
1870b57cec5SDimitry Andric }
operator |=(ChangeStatus & L,ChangeStatus R)188fe6060f1SDimitry Andric ChangeStatus &llvm::operator|=(ChangeStatus &L, ChangeStatus R) {
189fe6060f1SDimitry Andric L = L | R;
190fe6060f1SDimitry Andric return L;
191fe6060f1SDimitry Andric }
operator &(ChangeStatus L,ChangeStatus R)192e8d8bef9SDimitry Andric ChangeStatus llvm::operator&(ChangeStatus L, ChangeStatus R) {
193e8d8bef9SDimitry Andric return L == ChangeStatus::UNCHANGED ? L : R;
1940b57cec5SDimitry Andric }
operator &=(ChangeStatus & L,ChangeStatus R)195fe6060f1SDimitry Andric ChangeStatus &llvm::operator&=(ChangeStatus &L, ChangeStatus R) {
196fe6060f1SDimitry Andric L = L & R;
197fe6060f1SDimitry Andric return L;
198fe6060f1SDimitry Andric }
1990b57cec5SDimitry Andric ///}
2000b57cec5SDimitry Andric
isGPU(const Module & M)20106c3fb27SDimitry Andric bool AA::isGPU(const Module &M) {
20206c3fb27SDimitry Andric Triple T(M.getTargetTriple());
20306c3fb27SDimitry Andric return T.isAMDGPU() || T.isNVPTX();
20406c3fb27SDimitry Andric }
20506c3fb27SDimitry Andric
isNoSyncInst(Attributor & A,const Instruction & I,const AbstractAttribute & QueryingAA)2061fd87a68SDimitry Andric bool AA::isNoSyncInst(Attributor &A, const Instruction &I,
2071fd87a68SDimitry Andric const AbstractAttribute &QueryingAA) {
2081fd87a68SDimitry Andric // We are looking for volatile instructions or non-relaxed atomics.
2091fd87a68SDimitry Andric if (const auto *CB = dyn_cast<CallBase>(&I)) {
2101fd87a68SDimitry Andric if (CB->hasFnAttr(Attribute::NoSync))
2111fd87a68SDimitry Andric return true;
2121fd87a68SDimitry Andric
2131fd87a68SDimitry Andric // Non-convergent and readnone imply nosync.
2141fd87a68SDimitry Andric if (!CB->isConvergent() && !CB->mayReadOrWriteMemory())
2151fd87a68SDimitry Andric return true;
2161fd87a68SDimitry Andric
2171fd87a68SDimitry Andric if (AANoSync::isNoSyncIntrinsic(&I))
2181fd87a68SDimitry Andric return true;
2191fd87a68SDimitry Andric
22006c3fb27SDimitry Andric bool IsKnownNoSync;
22106c3fb27SDimitry Andric return AA::hasAssumedIRAttr<Attribute::NoSync>(
22206c3fb27SDimitry Andric A, &QueryingAA, IRPosition::callsite_function(*CB),
22306c3fb27SDimitry Andric DepClassTy::OPTIONAL, IsKnownNoSync);
2241fd87a68SDimitry Andric }
2251fd87a68SDimitry Andric
2261fd87a68SDimitry Andric if (!I.mayReadOrWriteMemory())
2271fd87a68SDimitry Andric return true;
2281fd87a68SDimitry Andric
2291fd87a68SDimitry Andric return !I.isVolatile() && !AANoSync::isNonRelaxedAtomic(&I);
2301fd87a68SDimitry Andric }
2311fd87a68SDimitry Andric
isDynamicallyUnique(Attributor & A,const AbstractAttribute & QueryingAA,const Value & V,bool ForAnalysisOnly)232fe6060f1SDimitry Andric bool AA::isDynamicallyUnique(Attributor &A, const AbstractAttribute &QueryingAA,
23381ad6265SDimitry Andric const Value &V, bool ForAnalysisOnly) {
23481ad6265SDimitry Andric // TODO: See the AAInstanceInfo class comment.
23581ad6265SDimitry Andric if (!ForAnalysisOnly)
236fe6060f1SDimitry Andric return false;
23706c3fb27SDimitry Andric auto *InstanceInfoAA = A.getAAFor<AAInstanceInfo>(
23881ad6265SDimitry Andric QueryingAA, IRPosition::value(V), DepClassTy::OPTIONAL);
23906c3fb27SDimitry Andric return InstanceInfoAA && InstanceInfoAA->isAssumedUniqueForAnalysis();
240fe6060f1SDimitry Andric }
241fe6060f1SDimitry Andric
2425f757f3fSDimitry Andric Constant *
getInitialValueForObj(Attributor & A,const AbstractAttribute & QueryingAA,Value & Obj,Type & Ty,const TargetLibraryInfo * TLI,const DataLayout & DL,AA::RangeTy * RangePtr)2435f757f3fSDimitry Andric AA::getInitialValueForObj(Attributor &A, const AbstractAttribute &QueryingAA,
2445f757f3fSDimitry Andric Value &Obj, Type &Ty, const TargetLibraryInfo *TLI,
2455f757f3fSDimitry Andric const DataLayout &DL, AA::RangeTy *RangePtr) {
246fe6060f1SDimitry Andric if (isa<AllocaInst>(Obj))
247fe6060f1SDimitry Andric return UndefValue::get(&Ty);
24881ad6265SDimitry Andric if (Constant *Init = getInitialValueOfAllocation(&Obj, TLI, &Ty))
24981ad6265SDimitry Andric return Init;
250fe6060f1SDimitry Andric auto *GV = dyn_cast<GlobalVariable>(&Obj);
25181ad6265SDimitry Andric if (!GV)
25281ad6265SDimitry Andric return nullptr;
25306c3fb27SDimitry Andric
25406c3fb27SDimitry Andric bool UsedAssumedInformation = false;
25506c3fb27SDimitry Andric Constant *Initializer = nullptr;
25606c3fb27SDimitry Andric if (A.hasGlobalVariableSimplificationCallback(*GV)) {
25706c3fb27SDimitry Andric auto AssumedGV = A.getAssumedInitializerFromCallBack(
2585f757f3fSDimitry Andric *GV, &QueryingAA, UsedAssumedInformation);
25906c3fb27SDimitry Andric Initializer = *AssumedGV;
26006c3fb27SDimitry Andric if (!Initializer)
26106c3fb27SDimitry Andric return nullptr;
26206c3fb27SDimitry Andric } else {
2635f757f3fSDimitry Andric if (!GV->hasLocalLinkage() &&
2645f757f3fSDimitry Andric (GV->isInterposable() || !(GV->isConstant() && GV->hasInitializer())))
265fe6060f1SDimitry Andric return nullptr;
266fe6060f1SDimitry Andric if (!GV->hasInitializer())
267fe6060f1SDimitry Andric return UndefValue::get(&Ty);
268bdd1243dSDimitry Andric
26906c3fb27SDimitry Andric if (!Initializer)
27006c3fb27SDimitry Andric Initializer = GV->getInitializer();
271bdd1243dSDimitry Andric }
272bdd1243dSDimitry Andric
27306c3fb27SDimitry Andric if (RangePtr && !RangePtr->offsetOrSizeAreUnknown()) {
27406c3fb27SDimitry Andric APInt Offset = APInt(64, RangePtr->Offset);
27506c3fb27SDimitry Andric return ConstantFoldLoadFromConst(Initializer, &Ty, Offset, DL);
27606c3fb27SDimitry Andric }
27706c3fb27SDimitry Andric
278*0fca6ea1SDimitry Andric return ConstantFoldLoadFromUniformValue(Initializer, &Ty, DL);
279fe6060f1SDimitry Andric }
280fe6060f1SDimitry Andric
isValidInScope(const Value & V,const Function * Scope)281fe6060f1SDimitry Andric bool AA::isValidInScope(const Value &V, const Function *Scope) {
282fe6060f1SDimitry Andric if (isa<Constant>(V))
283fe6060f1SDimitry Andric return true;
284fe6060f1SDimitry Andric if (auto *I = dyn_cast<Instruction>(&V))
285fe6060f1SDimitry Andric return I->getFunction() == Scope;
286fe6060f1SDimitry Andric if (auto *A = dyn_cast<Argument>(&V))
287fe6060f1SDimitry Andric return A->getParent() == Scope;
288fe6060f1SDimitry Andric return false;
289fe6060f1SDimitry Andric }
290fe6060f1SDimitry Andric
isValidAtPosition(const AA::ValueAndContext & VAC,InformationCache & InfoCache)29181ad6265SDimitry Andric bool AA::isValidAtPosition(const AA::ValueAndContext &VAC,
292fe6060f1SDimitry Andric InformationCache &InfoCache) {
29381ad6265SDimitry Andric if (isa<Constant>(VAC.getValue()) || VAC.getValue() == VAC.getCtxI())
294fe6060f1SDimitry Andric return true;
29581ad6265SDimitry Andric const Function *Scope = nullptr;
29681ad6265SDimitry Andric const Instruction *CtxI = VAC.getCtxI();
29781ad6265SDimitry Andric if (CtxI)
29881ad6265SDimitry Andric Scope = CtxI->getFunction();
29981ad6265SDimitry Andric if (auto *A = dyn_cast<Argument>(VAC.getValue()))
300fe6060f1SDimitry Andric return A->getParent() == Scope;
30181ad6265SDimitry Andric if (auto *I = dyn_cast<Instruction>(VAC.getValue())) {
302fe6060f1SDimitry Andric if (I->getFunction() == Scope) {
30381ad6265SDimitry Andric if (const DominatorTree *DT =
30481ad6265SDimitry Andric InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(
30581ad6265SDimitry Andric *Scope))
30681ad6265SDimitry Andric return DT->dominates(I, CtxI);
30781ad6265SDimitry Andric // Local dominance check mostly for the old PM passes.
30881ad6265SDimitry Andric if (CtxI && I->getParent() == CtxI->getParent())
30981ad6265SDimitry Andric return llvm::any_of(
31081ad6265SDimitry Andric make_range(I->getIterator(), I->getParent()->end()),
31181ad6265SDimitry Andric [&](const Instruction &AfterI) { return &AfterI == CtxI; });
31281ad6265SDimitry Andric }
313fe6060f1SDimitry Andric }
314fe6060f1SDimitry Andric return false;
315fe6060f1SDimitry Andric }
316fe6060f1SDimitry Andric
getWithType(Value & V,Type & Ty)317fe6060f1SDimitry Andric Value *AA::getWithType(Value &V, Type &Ty) {
318fe6060f1SDimitry Andric if (V.getType() == &Ty)
319fe6060f1SDimitry Andric return &V;
320fe6060f1SDimitry Andric if (isa<PoisonValue>(V))
321fe6060f1SDimitry Andric return PoisonValue::get(&Ty);
322fe6060f1SDimitry Andric if (isa<UndefValue>(V))
323fe6060f1SDimitry Andric return UndefValue::get(&Ty);
324fe6060f1SDimitry Andric if (auto *C = dyn_cast<Constant>(&V)) {
325fe6060f1SDimitry Andric if (C->isNullValue())
326fe6060f1SDimitry Andric return Constant::getNullValue(&Ty);
327fe6060f1SDimitry Andric if (C->getType()->isPointerTy() && Ty.isPointerTy())
328fe6060f1SDimitry Andric return ConstantExpr::getPointerCast(C, &Ty);
3296e75b2fbSDimitry Andric if (C->getType()->getPrimitiveSizeInBits() >= Ty.getPrimitiveSizeInBits()) {
330fe6060f1SDimitry Andric if (C->getType()->isIntegerTy() && Ty.isIntegerTy())
331fe6060f1SDimitry Andric return ConstantExpr::getTrunc(C, &Ty, /* OnlyIfReduced */ true);
332fe6060f1SDimitry Andric if (C->getType()->isFloatingPointTy() && Ty.isFloatingPointTy())
3335f757f3fSDimitry Andric return ConstantFoldCastInstruction(Instruction::FPTrunc, C, &Ty);
334fe6060f1SDimitry Andric }
3356e75b2fbSDimitry Andric }
336fe6060f1SDimitry Andric return nullptr;
337fe6060f1SDimitry Andric }
338fe6060f1SDimitry Andric
339bdd1243dSDimitry Andric std::optional<Value *>
combineOptionalValuesInAAValueLatice(const std::optional<Value * > & A,const std::optional<Value * > & B,Type * Ty)340bdd1243dSDimitry Andric AA::combineOptionalValuesInAAValueLatice(const std::optional<Value *> &A,
341bdd1243dSDimitry Andric const std::optional<Value *> &B,
342bdd1243dSDimitry Andric Type *Ty) {
343fe6060f1SDimitry Andric if (A == B)
344fe6060f1SDimitry Andric return A;
34581ad6265SDimitry Andric if (!B)
346fe6060f1SDimitry Andric return A;
347fe6060f1SDimitry Andric if (*B == nullptr)
348fe6060f1SDimitry Andric return nullptr;
34981ad6265SDimitry Andric if (!A)
350fe6060f1SDimitry Andric return Ty ? getWithType(**B, *Ty) : nullptr;
351fe6060f1SDimitry Andric if (*A == nullptr)
352fe6060f1SDimitry Andric return nullptr;
353fe6060f1SDimitry Andric if (!Ty)
354fe6060f1SDimitry Andric Ty = (*A)->getType();
355fe6060f1SDimitry Andric if (isa_and_nonnull<UndefValue>(*A))
356fe6060f1SDimitry Andric return getWithType(**B, *Ty);
357fe6060f1SDimitry Andric if (isa<UndefValue>(*B))
358fe6060f1SDimitry Andric return A;
359fe6060f1SDimitry Andric if (*A && *B && *A == getWithType(**B, *Ty))
360fe6060f1SDimitry Andric return A;
361fe6060f1SDimitry Andric return nullptr;
362fe6060f1SDimitry Andric }
363fe6060f1SDimitry Andric
36481ad6265SDimitry Andric template <bool IsLoad, typename Ty>
getPotentialCopiesOfMemoryValue(Attributor & A,Ty & I,SmallSetVector<Value *,4> & PotentialCopies,SmallSetVector<Instruction *,4> * PotentialValueOrigins,const AbstractAttribute & QueryingAA,bool & UsedAssumedInformation,bool OnlyExact)36581ad6265SDimitry Andric static bool getPotentialCopiesOfMemoryValue(
36681ad6265SDimitry Andric Attributor &A, Ty &I, SmallSetVector<Value *, 4> &PotentialCopies,
3675f757f3fSDimitry Andric SmallSetVector<Instruction *, 4> *PotentialValueOrigins,
36881ad6265SDimitry Andric const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
36981ad6265SDimitry Andric bool OnlyExact) {
37081ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Trying to determine the potential copies of " << I
37181ad6265SDimitry Andric << " (only exact: " << OnlyExact << ")\n";);
372fe6060f1SDimitry Andric
37381ad6265SDimitry Andric Value &Ptr = *I.getPointerOperand();
37481ad6265SDimitry Andric // Containers to remember the pointer infos and new copies while we are not
37581ad6265SDimitry Andric // sure that we can find all of them. If we abort we want to avoid spurious
37681ad6265SDimitry Andric // dependences and potential copies in the provided container.
377fe6060f1SDimitry Andric SmallVector<const AAPointerInfo *> PIs;
3785f757f3fSDimitry Andric SmallSetVector<Value *, 8> NewCopies;
3795f757f3fSDimitry Andric SmallSetVector<Instruction *, 8> NewCopyOrigins;
380fe6060f1SDimitry Andric
38181ad6265SDimitry Andric const auto *TLI =
38281ad6265SDimitry Andric A.getInfoCache().getTargetLibraryInfoForFunction(*I.getFunction());
383bdd1243dSDimitry Andric
384bdd1243dSDimitry Andric auto Pred = [&](Value &Obj) {
385bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Visit underlying object " << Obj << "\n");
386bdd1243dSDimitry Andric if (isa<UndefValue>(&Obj))
387bdd1243dSDimitry Andric return true;
388bdd1243dSDimitry Andric if (isa<ConstantPointerNull>(&Obj)) {
389fe6060f1SDimitry Andric // A null pointer access can be undefined but any offset from null may
390fe6060f1SDimitry Andric // be OK. We do not try to optimize the latter.
39181ad6265SDimitry Andric if (!NullPointerIsDefined(I.getFunction(),
392fe6060f1SDimitry Andric Ptr.getType()->getPointerAddressSpace()) &&
393fcaf7f86SDimitry Andric A.getAssumedSimplified(Ptr, QueryingAA, UsedAssumedInformation,
394bdd1243dSDimitry Andric AA::Interprocedural) == &Obj)
395bdd1243dSDimitry Andric return true;
396fe6060f1SDimitry Andric LLVM_DEBUG(
397fe6060f1SDimitry Andric dbgs() << "Underlying object is a valid nullptr, giving up.\n";);
398fe6060f1SDimitry Andric return false;
399fe6060f1SDimitry Andric }
40081ad6265SDimitry Andric // TODO: Use assumed noalias return.
401bdd1243dSDimitry Andric if (!isa<AllocaInst>(&Obj) && !isa<GlobalVariable>(&Obj) &&
402bdd1243dSDimitry Andric !(IsLoad ? isAllocationFn(&Obj, TLI) : isNoAliasCall(&Obj))) {
403bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Underlying object is not supported yet: " << Obj
404fe6060f1SDimitry Andric << "\n";);
405fe6060f1SDimitry Andric return false;
406fe6060f1SDimitry Andric }
407bdd1243dSDimitry Andric if (auto *GV = dyn_cast<GlobalVariable>(&Obj))
40881ad6265SDimitry Andric if (!GV->hasLocalLinkage() &&
40981ad6265SDimitry Andric !(GV->isConstant() && GV->hasInitializer())) {
410fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Underlying object is global with external "
411fe6060f1SDimitry Andric "linkage, not supported yet: "
412bdd1243dSDimitry Andric << Obj << "\n";);
413fe6060f1SDimitry Andric return false;
414fe6060f1SDimitry Andric }
415fe6060f1SDimitry Andric
416fcaf7f86SDimitry Andric bool NullOnly = true;
417fcaf7f86SDimitry Andric bool NullRequired = false;
418bdd1243dSDimitry Andric auto CheckForNullOnlyAndUndef = [&](std::optional<Value *> V,
419bdd1243dSDimitry Andric bool IsExact) {
420fcaf7f86SDimitry Andric if (!V || *V == nullptr)
421fcaf7f86SDimitry Andric NullOnly = false;
422fcaf7f86SDimitry Andric else if (isa<UndefValue>(*V))
423fcaf7f86SDimitry Andric /* No op */;
424fcaf7f86SDimitry Andric else if (isa<Constant>(*V) && cast<Constant>(*V)->isNullValue())
425fcaf7f86SDimitry Andric NullRequired = !IsExact;
426fcaf7f86SDimitry Andric else
427fcaf7f86SDimitry Andric NullOnly = false;
428fcaf7f86SDimitry Andric };
42981ad6265SDimitry Andric
4301ac55f4cSDimitry Andric auto AdjustWrittenValueType = [&](const AAPointerInfo::Access &Acc,
4311ac55f4cSDimitry Andric Value &V) {
4321ac55f4cSDimitry Andric Value *AdjV = AA::getWithType(V, *I.getType());
4331ac55f4cSDimitry Andric if (!AdjV) {
4341ac55f4cSDimitry Andric LLVM_DEBUG(dbgs() << "Underlying object written but stored value "
4351ac55f4cSDimitry Andric "cannot be converted to read type: "
4361ac55f4cSDimitry Andric << *Acc.getRemoteInst() << " : " << *I.getType()
4371ac55f4cSDimitry Andric << "\n";);
4381ac55f4cSDimitry Andric }
4391ac55f4cSDimitry Andric return AdjV;
4401ac55f4cSDimitry Andric };
4411ac55f4cSDimitry Andric
4425f757f3fSDimitry Andric auto SkipCB = [&](const AAPointerInfo::Access &Acc) {
4435f757f3fSDimitry Andric if ((IsLoad && !Acc.isWriteOrAssumption()) || (!IsLoad && !Acc.isRead()))
4445f757f3fSDimitry Andric return true;
4455f757f3fSDimitry Andric if (IsLoad) {
4465f757f3fSDimitry Andric if (Acc.isWrittenValueYetUndetermined())
4475f757f3fSDimitry Andric return true;
4485f757f3fSDimitry Andric if (PotentialValueOrigins && !isa<AssumeInst>(Acc.getRemoteInst()))
4495f757f3fSDimitry Andric return false;
4505f757f3fSDimitry Andric if (!Acc.isWrittenValueUnknown())
4515f757f3fSDimitry Andric if (Value *V = AdjustWrittenValueType(Acc, *Acc.getWrittenValue()))
4525f757f3fSDimitry Andric if (NewCopies.count(V)) {
4535f757f3fSDimitry Andric NewCopyOrigins.insert(Acc.getRemoteInst());
4545f757f3fSDimitry Andric return true;
4555f757f3fSDimitry Andric }
4565f757f3fSDimitry Andric if (auto *SI = dyn_cast<StoreInst>(Acc.getRemoteInst()))
4575f757f3fSDimitry Andric if (Value *V = AdjustWrittenValueType(Acc, *SI->getValueOperand()))
4585f757f3fSDimitry Andric if (NewCopies.count(V)) {
4595f757f3fSDimitry Andric NewCopyOrigins.insert(Acc.getRemoteInst());
4605f757f3fSDimitry Andric return true;
4615f757f3fSDimitry Andric }
4625f757f3fSDimitry Andric }
4635f757f3fSDimitry Andric return false;
4645f757f3fSDimitry Andric };
4655f757f3fSDimitry Andric
466fe6060f1SDimitry Andric auto CheckAccess = [&](const AAPointerInfo::Access &Acc, bool IsExact) {
467bdd1243dSDimitry Andric if ((IsLoad && !Acc.isWriteOrAssumption()) || (!IsLoad && !Acc.isRead()))
468fe6060f1SDimitry Andric return true;
46981ad6265SDimitry Andric if (IsLoad && Acc.isWrittenValueYetUndetermined())
47081ad6265SDimitry Andric return true;
471fcaf7f86SDimitry Andric CheckForNullOnlyAndUndef(Acc.getContent(), IsExact);
472fcaf7f86SDimitry Andric if (OnlyExact && !IsExact && !NullOnly &&
47381ad6265SDimitry Andric !isa_and_nonnull<UndefValue>(Acc.getWrittenValue())) {
47481ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Non exact access " << *Acc.getRemoteInst()
47581ad6265SDimitry Andric << ", abort!\n");
47681ad6265SDimitry Andric return false;
47781ad6265SDimitry Andric }
478fcaf7f86SDimitry Andric if (NullRequired && !NullOnly) {
479fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "Required all `null` accesses due to non exact "
480fcaf7f86SDimitry Andric "one, however found non-null one: "
481fcaf7f86SDimitry Andric << *Acc.getRemoteInst() << ", abort!\n");
482fcaf7f86SDimitry Andric return false;
483fcaf7f86SDimitry Andric }
48481ad6265SDimitry Andric if (IsLoad) {
48581ad6265SDimitry Andric assert(isa<LoadInst>(I) && "Expected load or store instruction only!");
48681ad6265SDimitry Andric if (!Acc.isWrittenValueUnknown()) {
4871ac55f4cSDimitry Andric Value *V = AdjustWrittenValueType(Acc, *Acc.getWrittenValue());
4881ac55f4cSDimitry Andric if (!V)
4891ac55f4cSDimitry Andric return false;
4905f757f3fSDimitry Andric NewCopies.insert(V);
4915f757f3fSDimitry Andric if (PotentialValueOrigins)
4925f757f3fSDimitry Andric NewCopyOrigins.insert(Acc.getRemoteInst());
49381ad6265SDimitry Andric return true;
49481ad6265SDimitry Andric }
49581ad6265SDimitry Andric auto *SI = dyn_cast<StoreInst>(Acc.getRemoteInst());
49681ad6265SDimitry Andric if (!SI) {
49781ad6265SDimitry Andric LLVM_DEBUG(dbgs() << "Underlying object written through a non-store "
49881ad6265SDimitry Andric "instruction not supported yet: "
49981ad6265SDimitry Andric << *Acc.getRemoteInst() << "\n";);
50081ad6265SDimitry Andric return false;
50181ad6265SDimitry Andric }
5021ac55f4cSDimitry Andric Value *V = AdjustWrittenValueType(Acc, *SI->getValueOperand());
5031ac55f4cSDimitry Andric if (!V)
5041ac55f4cSDimitry Andric return false;
5055f757f3fSDimitry Andric NewCopies.insert(V);
5065f757f3fSDimitry Andric if (PotentialValueOrigins)
5075f757f3fSDimitry Andric NewCopyOrigins.insert(SI);
50881ad6265SDimitry Andric } else {
50981ad6265SDimitry Andric assert(isa<StoreInst>(I) && "Expected load or store instruction only!");
510fe6060f1SDimitry Andric auto *LI = dyn_cast<LoadInst>(Acc.getRemoteInst());
51181ad6265SDimitry Andric if (!LI && OnlyExact) {
512fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "Underlying object read through a non-load "
513fe6060f1SDimitry Andric "instruction not supported yet: "
514fe6060f1SDimitry Andric << *Acc.getRemoteInst() << "\n";);
515fe6060f1SDimitry Andric return false;
516fe6060f1SDimitry Andric }
5175f757f3fSDimitry Andric NewCopies.insert(Acc.getRemoteInst());
51881ad6265SDimitry Andric }
519fe6060f1SDimitry Andric return true;
520fe6060f1SDimitry Andric };
521fe6060f1SDimitry Andric
522fcaf7f86SDimitry Andric // If the value has been written to we don't need the initial value of the
523fcaf7f86SDimitry Andric // object.
524fcaf7f86SDimitry Andric bool HasBeenWrittenTo = false;
525fcaf7f86SDimitry Andric
526bdd1243dSDimitry Andric AA::RangeTy Range;
52706c3fb27SDimitry Andric auto *PI = A.getAAFor<AAPointerInfo>(QueryingAA, IRPosition::value(Obj),
528fe6060f1SDimitry Andric DepClassTy::NONE);
5295f757f3fSDimitry Andric if (!PI || !PI->forallInterferingAccesses(
5305f757f3fSDimitry Andric A, QueryingAA, I,
53106c3fb27SDimitry Andric /* FindInterferingWrites */ IsLoad,
5325f757f3fSDimitry Andric /* FindInterferingReads */ !IsLoad, CheckAccess,
5335f757f3fSDimitry Andric HasBeenWrittenTo, Range, SkipCB)) {
534fe6060f1SDimitry Andric LLVM_DEBUG(
535fe6060f1SDimitry Andric dbgs()
536fe6060f1SDimitry Andric << "Failed to verify all interfering accesses for underlying object: "
537bdd1243dSDimitry Andric << Obj << "\n");
538fe6060f1SDimitry Andric return false;
539fe6060f1SDimitry Andric }
540fcaf7f86SDimitry Andric
541bdd1243dSDimitry Andric if (IsLoad && !HasBeenWrittenTo && !Range.isUnassigned()) {
542bdd1243dSDimitry Andric const DataLayout &DL = A.getDataLayout();
5435f757f3fSDimitry Andric Value *InitialValue = AA::getInitialValueForObj(
5445f757f3fSDimitry Andric A, QueryingAA, Obj, *I.getType(), TLI, DL, &Range);
545bdd1243dSDimitry Andric if (!InitialValue) {
546bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "Could not determine required initial value of "
547bdd1243dSDimitry Andric "underlying object, abort!\n");
548fcaf7f86SDimitry Andric return false;
549bdd1243dSDimitry Andric }
550fcaf7f86SDimitry Andric CheckForNullOnlyAndUndef(InitialValue, /* IsExact */ true);
551fcaf7f86SDimitry Andric if (NullRequired && !NullOnly) {
552fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "Non exact access but initial value that is not "
553fcaf7f86SDimitry Andric "null or undef, abort!\n");
554fcaf7f86SDimitry Andric return false;
555fcaf7f86SDimitry Andric }
556fcaf7f86SDimitry Andric
5575f757f3fSDimitry Andric NewCopies.insert(InitialValue);
5585f757f3fSDimitry Andric if (PotentialValueOrigins)
5595f757f3fSDimitry Andric NewCopyOrigins.insert(nullptr);
560fcaf7f86SDimitry Andric }
561fcaf7f86SDimitry Andric
56206c3fb27SDimitry Andric PIs.push_back(PI);
563bdd1243dSDimitry Andric
564bdd1243dSDimitry Andric return true;
565bdd1243dSDimitry Andric };
566bdd1243dSDimitry Andric
56706c3fb27SDimitry Andric const auto *AAUO = A.getAAFor<AAUnderlyingObjects>(
568bdd1243dSDimitry Andric QueryingAA, IRPosition::value(Ptr), DepClassTy::OPTIONAL);
56906c3fb27SDimitry Andric if (!AAUO || !AAUO->forallUnderlyingObjects(Pred)) {
570bdd1243dSDimitry Andric LLVM_DEBUG(
571bdd1243dSDimitry Andric dbgs() << "Underlying objects stored into could not be determined\n";);
572bdd1243dSDimitry Andric return false;
573fe6060f1SDimitry Andric }
574fe6060f1SDimitry Andric
57581ad6265SDimitry Andric // Only if we were successful collection all potential copies we record
57681ad6265SDimitry Andric // dependences (on non-fix AAPointerInfo AAs). We also only then modify the
57781ad6265SDimitry Andric // given PotentialCopies container.
578bdd1243dSDimitry Andric for (const auto *PI : PIs) {
579fe6060f1SDimitry Andric if (!PI->getState().isAtFixpoint())
580fe6060f1SDimitry Andric UsedAssumedInformation = true;
581fe6060f1SDimitry Andric A.recordDependence(*PI, QueryingAA, DepClassTy::OPTIONAL);
582fe6060f1SDimitry Andric }
583fe6060f1SDimitry Andric PotentialCopies.insert(NewCopies.begin(), NewCopies.end());
5845f757f3fSDimitry Andric if (PotentialValueOrigins)
5855f757f3fSDimitry Andric PotentialValueOrigins->insert(NewCopyOrigins.begin(), NewCopyOrigins.end());
586fe6060f1SDimitry Andric
587fe6060f1SDimitry Andric return true;
588fe6060f1SDimitry Andric }
589fe6060f1SDimitry Andric
getPotentiallyLoadedValues(Attributor & A,LoadInst & LI,SmallSetVector<Value *,4> & PotentialValues,SmallSetVector<Instruction *,4> & PotentialValueOrigins,const AbstractAttribute & QueryingAA,bool & UsedAssumedInformation,bool OnlyExact)59081ad6265SDimitry Andric bool AA::getPotentiallyLoadedValues(
59181ad6265SDimitry Andric Attributor &A, LoadInst &LI, SmallSetVector<Value *, 4> &PotentialValues,
59281ad6265SDimitry Andric SmallSetVector<Instruction *, 4> &PotentialValueOrigins,
59381ad6265SDimitry Andric const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
59481ad6265SDimitry Andric bool OnlyExact) {
59581ad6265SDimitry Andric return getPotentialCopiesOfMemoryValue</* IsLoad */ true>(
5965f757f3fSDimitry Andric A, LI, PotentialValues, &PotentialValueOrigins, QueryingAA,
59781ad6265SDimitry Andric UsedAssumedInformation, OnlyExact);
59881ad6265SDimitry Andric }
59981ad6265SDimitry Andric
getPotentialCopiesOfStoredValue(Attributor & A,StoreInst & SI,SmallSetVector<Value *,4> & PotentialCopies,const AbstractAttribute & QueryingAA,bool & UsedAssumedInformation,bool OnlyExact)60081ad6265SDimitry Andric bool AA::getPotentialCopiesOfStoredValue(
60181ad6265SDimitry Andric Attributor &A, StoreInst &SI, SmallSetVector<Value *, 4> &PotentialCopies,
60281ad6265SDimitry Andric const AbstractAttribute &QueryingAA, bool &UsedAssumedInformation,
60381ad6265SDimitry Andric bool OnlyExact) {
60481ad6265SDimitry Andric return getPotentialCopiesOfMemoryValue</* IsLoad */ false>(
6055f757f3fSDimitry Andric A, SI, PotentialCopies, nullptr, QueryingAA, UsedAssumedInformation,
6065f757f3fSDimitry Andric OnlyExact);
60781ad6265SDimitry Andric }
60881ad6265SDimitry Andric
isAssumedReadOnlyOrReadNone(Attributor & A,const IRPosition & IRP,const AbstractAttribute & QueryingAA,bool RequireReadNone,bool & IsKnown)6091fd87a68SDimitry Andric static bool isAssumedReadOnlyOrReadNone(Attributor &A, const IRPosition &IRP,
6101fd87a68SDimitry Andric const AbstractAttribute &QueryingAA,
6111fd87a68SDimitry Andric bool RequireReadNone, bool &IsKnown) {
61206c3fb27SDimitry Andric if (RequireReadNone) {
61306c3fb27SDimitry Andric if (AA::hasAssumedIRAttr<Attribute::ReadNone>(
61406c3fb27SDimitry Andric A, &QueryingAA, IRP, DepClassTy::OPTIONAL, IsKnown,
61506c3fb27SDimitry Andric /* IgnoreSubsumingPositions */ true))
61606c3fb27SDimitry Andric return true;
61706c3fb27SDimitry Andric } else if (AA::hasAssumedIRAttr<Attribute::ReadOnly>(
61806c3fb27SDimitry Andric A, &QueryingAA, IRP, DepClassTy::OPTIONAL, IsKnown,
61906c3fb27SDimitry Andric /* IgnoreSubsumingPositions */ true))
62006c3fb27SDimitry Andric return true;
6211fd87a68SDimitry Andric
6221fd87a68SDimitry Andric IRPosition::Kind Kind = IRP.getPositionKind();
6231fd87a68SDimitry Andric if (Kind == IRPosition::IRP_FUNCTION || Kind == IRPosition::IRP_CALL_SITE) {
62406c3fb27SDimitry Andric const auto *MemLocAA =
6251fd87a68SDimitry Andric A.getAAFor<AAMemoryLocation>(QueryingAA, IRP, DepClassTy::NONE);
62606c3fb27SDimitry Andric if (MemLocAA && MemLocAA->isAssumedReadNone()) {
62706c3fb27SDimitry Andric IsKnown = MemLocAA->isKnownReadNone();
6281fd87a68SDimitry Andric if (!IsKnown)
62906c3fb27SDimitry Andric A.recordDependence(*MemLocAA, QueryingAA, DepClassTy::OPTIONAL);
6301fd87a68SDimitry Andric return true;
6311fd87a68SDimitry Andric }
6321fd87a68SDimitry Andric }
6331fd87a68SDimitry Andric
63406c3fb27SDimitry Andric const auto *MemBehaviorAA =
6351fd87a68SDimitry Andric A.getAAFor<AAMemoryBehavior>(QueryingAA, IRP, DepClassTy::NONE);
63606c3fb27SDimitry Andric if (MemBehaviorAA &&
63706c3fb27SDimitry Andric (MemBehaviorAA->isAssumedReadNone() ||
63806c3fb27SDimitry Andric (!RequireReadNone && MemBehaviorAA->isAssumedReadOnly()))) {
63906c3fb27SDimitry Andric IsKnown = RequireReadNone ? MemBehaviorAA->isKnownReadNone()
64006c3fb27SDimitry Andric : MemBehaviorAA->isKnownReadOnly();
6411fd87a68SDimitry Andric if (!IsKnown)
64206c3fb27SDimitry Andric A.recordDependence(*MemBehaviorAA, QueryingAA, DepClassTy::OPTIONAL);
6431fd87a68SDimitry Andric return true;
6441fd87a68SDimitry Andric }
6451fd87a68SDimitry Andric
6461fd87a68SDimitry Andric return false;
6471fd87a68SDimitry Andric }
6481fd87a68SDimitry Andric
isAssumedReadOnly(Attributor & A,const IRPosition & IRP,const AbstractAttribute & QueryingAA,bool & IsKnown)6491fd87a68SDimitry Andric bool AA::isAssumedReadOnly(Attributor &A, const IRPosition &IRP,
6501fd87a68SDimitry Andric const AbstractAttribute &QueryingAA, bool &IsKnown) {
6511fd87a68SDimitry Andric return isAssumedReadOnlyOrReadNone(A, IRP, QueryingAA,
6521fd87a68SDimitry Andric /* RequireReadNone */ false, IsKnown);
6531fd87a68SDimitry Andric }
isAssumedReadNone(Attributor & A,const IRPosition & IRP,const AbstractAttribute & QueryingAA,bool & IsKnown)6541fd87a68SDimitry Andric bool AA::isAssumedReadNone(Attributor &A, const IRPosition &IRP,
6551fd87a68SDimitry Andric const AbstractAttribute &QueryingAA, bool &IsKnown) {
6561fd87a68SDimitry Andric return isAssumedReadOnlyOrReadNone(A, IRP, QueryingAA,
6571fd87a68SDimitry Andric /* RequireReadNone */ true, IsKnown);
6581fd87a68SDimitry Andric }
6591fd87a68SDimitry Andric
6601fd87a68SDimitry Andric 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)6611fd87a68SDimitry Andric isPotentiallyReachable(Attributor &A, const Instruction &FromI,
6621fd87a68SDimitry Andric const Instruction *ToI, const Function &ToFn,
6631fd87a68SDimitry Andric const AbstractAttribute &QueryingAA,
664bdd1243dSDimitry Andric const AA::InstExclusionSetTy *ExclusionSet,
6651fd87a68SDimitry Andric std::function<bool(const Function &F)> GoBackwardsCB) {
66606c3fb27SDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, {
667bdd1243dSDimitry Andric dbgs() << "[AA] isPotentiallyReachable @" << ToFn.getName() << " from "
668bdd1243dSDimitry Andric << FromI << " [GBCB: " << bool(GoBackwardsCB) << "][#ExS: "
669bdd1243dSDimitry Andric << (ExclusionSet ? std::to_string(ExclusionSet->size()) : "none")
670bdd1243dSDimitry Andric << "]\n";
671bdd1243dSDimitry Andric if (ExclusionSet)
672bdd1243dSDimitry Andric for (auto *ES : *ExclusionSet)
673bdd1243dSDimitry Andric dbgs() << *ES << "\n";
674bdd1243dSDimitry Andric });
6751fd87a68SDimitry Andric
67606c3fb27SDimitry Andric // We know kernels (generally) cannot be called from within the module. Thus,
67706c3fb27SDimitry Andric // for reachability we would need to step back from a kernel which would allow
67806c3fb27SDimitry Andric // us to reach anything anyway. Even if a kernel is invoked from another
67906c3fb27SDimitry Andric // kernel, values like allocas and shared memory are not accessible. We
68006c3fb27SDimitry Andric // implicitly check for this situation to avoid costly lookups.
68106c3fb27SDimitry Andric if (GoBackwardsCB && &ToFn != FromI.getFunction() &&
68206c3fb27SDimitry Andric !GoBackwardsCB(*FromI.getFunction()) && ToFn.hasFnAttribute("kernel") &&
68306c3fb27SDimitry Andric FromI.getFunction()->hasFnAttribute("kernel")) {
68406c3fb27SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] assume kernel cannot be reached from within the "
68506c3fb27SDimitry Andric "module; success\n";);
68606c3fb27SDimitry Andric return false;
68706c3fb27SDimitry Andric }
68806c3fb27SDimitry Andric
689bdd1243dSDimitry Andric // If we can go arbitrarily backwards we will eventually reach an entry point
690bdd1243dSDimitry Andric // that can reach ToI. Only if a set of blocks through which we cannot go is
691bdd1243dSDimitry Andric // provided, or once we track internal functions not accessible from the
692bdd1243dSDimitry Andric // outside, it makes sense to perform backwards analysis in the absence of a
693bdd1243dSDimitry Andric // GoBackwardsCB.
694bdd1243dSDimitry Andric if (!GoBackwardsCB && !ExclusionSet) {
695fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI
696bdd1243dSDimitry Andric << " is not checked backwards and does not have an "
697bdd1243dSDimitry Andric "exclusion set, abort\n");
698fcaf7f86SDimitry Andric return true;
699fcaf7f86SDimitry Andric }
700fcaf7f86SDimitry Andric
7011fd87a68SDimitry Andric SmallPtrSet<const Instruction *, 8> Visited;
7021fd87a68SDimitry Andric SmallVector<const Instruction *> Worklist;
7031fd87a68SDimitry Andric Worklist.push_back(&FromI);
7041fd87a68SDimitry Andric
7051fd87a68SDimitry Andric while (!Worklist.empty()) {
7061fd87a68SDimitry Andric const Instruction *CurFromI = Worklist.pop_back_val();
7071fd87a68SDimitry Andric if (!Visited.insert(CurFromI).second)
7081fd87a68SDimitry Andric continue;
7091fd87a68SDimitry Andric
7101fd87a68SDimitry Andric const Function *FromFn = CurFromI->getFunction();
7111fd87a68SDimitry Andric if (FromFn == &ToFn) {
7121fd87a68SDimitry Andric if (!ToI)
7131fd87a68SDimitry Andric return true;
7141fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] check " << *ToI << " from " << *CurFromI
7151fd87a68SDimitry Andric << " intraprocedurally\n");
71606c3fb27SDimitry Andric const auto *ReachabilityAA = A.getAAFor<AAIntraFnReachability>(
7171fd87a68SDimitry Andric QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL);
71806c3fb27SDimitry Andric bool Result = !ReachabilityAA || ReachabilityAA->isAssumedReachable(
71906c3fb27SDimitry Andric A, *CurFromI, *ToI, ExclusionSet);
7201fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " "
7211fd87a68SDimitry Andric << (Result ? "can potentially " : "cannot ") << "reach "
7221fd87a68SDimitry Andric << *ToI << " [Intra]\n");
7231fd87a68SDimitry Andric if (Result)
7241fd87a68SDimitry Andric return true;
7251fd87a68SDimitry Andric }
7261fd87a68SDimitry Andric
727bdd1243dSDimitry Andric bool Result = true;
728bdd1243dSDimitry Andric if (!ToFn.isDeclaration() && ToI) {
72906c3fb27SDimitry Andric const auto *ToReachabilityAA = A.getAAFor<AAIntraFnReachability>(
730bdd1243dSDimitry Andric QueryingAA, IRPosition::function(ToFn), DepClassTy::OPTIONAL);
731bdd1243dSDimitry Andric const Instruction &EntryI = ToFn.getEntryBlock().front();
73206c3fb27SDimitry Andric Result = !ToReachabilityAA || ToReachabilityAA->isAssumedReachable(
73306c3fb27SDimitry Andric A, EntryI, *ToI, ExclusionSet);
734bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Entry " << EntryI << " of @" << ToFn.getName()
735bdd1243dSDimitry Andric << " " << (Result ? "can potentially " : "cannot ")
736bdd1243dSDimitry Andric << "reach @" << *ToI << " [ToFn]\n");
737bdd1243dSDimitry Andric }
738bdd1243dSDimitry Andric
739bdd1243dSDimitry Andric if (Result) {
740bdd1243dSDimitry Andric // The entry of the ToFn can reach the instruction ToI. If the current
741bdd1243dSDimitry Andric // instruction is already known to reach the ToFn.
74206c3fb27SDimitry Andric const auto *FnReachabilityAA = A.getAAFor<AAInterFnReachability>(
7431fd87a68SDimitry Andric QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL);
74406c3fb27SDimitry Andric Result = !FnReachabilityAA || FnReachabilityAA->instructionCanReach(
74506c3fb27SDimitry Andric A, *CurFromI, ToFn, ExclusionSet);
7461fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] " << *CurFromI << " in @" << FromFn->getName()
7471fd87a68SDimitry Andric << " " << (Result ? "can potentially " : "cannot ")
7481fd87a68SDimitry Andric << "reach @" << ToFn.getName() << " [FromFn]\n");
7491fd87a68SDimitry Andric if (Result)
7501fd87a68SDimitry Andric return true;
751bdd1243dSDimitry Andric }
752bdd1243dSDimitry Andric
753bdd1243dSDimitry Andric // TODO: Check assumed nounwind.
75406c3fb27SDimitry Andric const auto *ReachabilityAA = A.getAAFor<AAIntraFnReachability>(
755bdd1243dSDimitry Andric QueryingAA, IRPosition::function(*FromFn), DepClassTy::OPTIONAL);
756bdd1243dSDimitry Andric auto ReturnInstCB = [&](Instruction &Ret) {
75706c3fb27SDimitry Andric bool Result = !ReachabilityAA || ReachabilityAA->isAssumedReachable(
75806c3fb27SDimitry Andric A, *CurFromI, Ret, ExclusionSet);
759bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA][Ret] " << *CurFromI << " "
760bdd1243dSDimitry Andric << (Result ? "can potentially " : "cannot ") << "reach "
761bdd1243dSDimitry Andric << Ret << " [Intra]\n");
762bdd1243dSDimitry Andric return !Result;
763bdd1243dSDimitry Andric };
764bdd1243dSDimitry Andric
765bdd1243dSDimitry Andric // Check if we can reach returns.
766bdd1243dSDimitry Andric bool UsedAssumedInformation = false;
7675f757f3fSDimitry Andric if (A.checkForAllInstructions(ReturnInstCB, FromFn, &QueryingAA,
768bdd1243dSDimitry Andric {Instruction::Ret}, UsedAssumedInformation)) {
769bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] No return is reachable, done\n");
770bdd1243dSDimitry Andric continue;
771bdd1243dSDimitry Andric }
772bdd1243dSDimitry Andric
773bdd1243dSDimitry Andric if (!GoBackwardsCB) {
774bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] check @" << ToFn.getName() << " from " << FromI
775bdd1243dSDimitry Andric << " is not checked backwards, abort\n");
776bdd1243dSDimitry Andric return true;
777bdd1243dSDimitry Andric }
7781fd87a68SDimitry Andric
7791fd87a68SDimitry Andric // If we do not go backwards from the FromFn we are done here and so far we
7801fd87a68SDimitry Andric // could not find a way to reach ToFn/ToI.
7811fd87a68SDimitry Andric if (!GoBackwardsCB(*FromFn))
7821fd87a68SDimitry Andric continue;
7831fd87a68SDimitry Andric
7841fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "Stepping backwards to the call sites of @"
7851fd87a68SDimitry Andric << FromFn->getName() << "\n");
7861fd87a68SDimitry Andric
7871fd87a68SDimitry Andric auto CheckCallSite = [&](AbstractCallSite ACS) {
7881fd87a68SDimitry Andric CallBase *CB = ACS.getInstruction();
7891fd87a68SDimitry Andric if (!CB)
7901fd87a68SDimitry Andric return false;
7911fd87a68SDimitry Andric
7921fd87a68SDimitry Andric if (isa<InvokeInst>(CB))
7931fd87a68SDimitry Andric return false;
7941fd87a68SDimitry Andric
7951fd87a68SDimitry Andric Instruction *Inst = CB->getNextNonDebugInstruction();
7961fd87a68SDimitry Andric Worklist.push_back(Inst);
7971fd87a68SDimitry Andric return true;
7981fd87a68SDimitry Andric };
7991fd87a68SDimitry Andric
8001fd87a68SDimitry Andric Result = !A.checkForAllCallSites(CheckCallSite, *FromFn,
8011fd87a68SDimitry Andric /* RequireAllCallSites */ true,
802d781ede6SDimitry Andric &QueryingAA, UsedAssumedInformation);
8031fd87a68SDimitry Andric if (Result) {
8041fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] stepping back to call sites from " << *CurFromI
8051fd87a68SDimitry Andric << " in @" << FromFn->getName()
8061fd87a68SDimitry Andric << " failed, give up\n");
8071fd87a68SDimitry Andric return true;
8081fd87a68SDimitry Andric }
8091fd87a68SDimitry Andric
8101fd87a68SDimitry Andric LLVM_DEBUG(dbgs() << "[AA] stepped back to call sites from " << *CurFromI
8111fd87a68SDimitry Andric << " in @" << FromFn->getName()
8121fd87a68SDimitry Andric << " worklist size is: " << Worklist.size() << "\n");
8131fd87a68SDimitry Andric }
8141fd87a68SDimitry Andric return false;
8151fd87a68SDimitry Andric }
8161fd87a68SDimitry Andric
isPotentiallyReachable(Attributor & A,const Instruction & FromI,const Instruction & ToI,const AbstractAttribute & QueryingAA,const AA::InstExclusionSetTy * ExclusionSet,std::function<bool (const Function & F)> GoBackwardsCB)8171fd87a68SDimitry Andric bool AA::isPotentiallyReachable(
8181fd87a68SDimitry Andric Attributor &A, const Instruction &FromI, const Instruction &ToI,
8191fd87a68SDimitry Andric const AbstractAttribute &QueryingAA,
820bdd1243dSDimitry Andric const AA::InstExclusionSetTy *ExclusionSet,
8211fd87a68SDimitry Andric std::function<bool(const Function &F)> GoBackwardsCB) {
8221fd87a68SDimitry Andric const Function *ToFn = ToI.getFunction();
8231fd87a68SDimitry Andric return ::isPotentiallyReachable(A, FromI, &ToI, *ToFn, QueryingAA,
824bdd1243dSDimitry Andric ExclusionSet, GoBackwardsCB);
8251fd87a68SDimitry Andric }
8261fd87a68SDimitry Andric
isPotentiallyReachable(Attributor & A,const Instruction & FromI,const Function & ToFn,const AbstractAttribute & QueryingAA,const AA::InstExclusionSetTy * ExclusionSet,std::function<bool (const Function & F)> GoBackwardsCB)8271fd87a68SDimitry Andric bool AA::isPotentiallyReachable(
8281fd87a68SDimitry Andric Attributor &A, const Instruction &FromI, const Function &ToFn,
8291fd87a68SDimitry Andric const AbstractAttribute &QueryingAA,
830bdd1243dSDimitry Andric const AA::InstExclusionSetTy *ExclusionSet,
8311fd87a68SDimitry Andric std::function<bool(const Function &F)> GoBackwardsCB) {
8321fd87a68SDimitry Andric return ::isPotentiallyReachable(A, FromI, /* ToI */ nullptr, ToFn, QueryingAA,
833bdd1243dSDimitry Andric ExclusionSet, GoBackwardsCB);
834bdd1243dSDimitry Andric }
835bdd1243dSDimitry Andric
isAssumedThreadLocalObject(Attributor & A,Value & Obj,const AbstractAttribute & QueryingAA)836bdd1243dSDimitry Andric bool AA::isAssumedThreadLocalObject(Attributor &A, Value &Obj,
837bdd1243dSDimitry Andric const AbstractAttribute &QueryingAA) {
838bdd1243dSDimitry Andric if (isa<UndefValue>(Obj))
839bdd1243dSDimitry Andric return true;
840bdd1243dSDimitry Andric if (isa<AllocaInst>(Obj)) {
841bdd1243dSDimitry Andric InformationCache &InfoCache = A.getInfoCache();
842bdd1243dSDimitry Andric if (!InfoCache.stackIsAccessibleByOtherThreads()) {
843bdd1243dSDimitry Andric LLVM_DEBUG(
844bdd1243dSDimitry Andric dbgs() << "[AA] Object '" << Obj
845bdd1243dSDimitry Andric << "' is thread local; stack objects are thread local.\n");
846bdd1243dSDimitry Andric return true;
847bdd1243dSDimitry Andric }
84806c3fb27SDimitry Andric bool IsKnownNoCapture;
84906c3fb27SDimitry Andric bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(
85006c3fb27SDimitry Andric A, &QueryingAA, IRPosition::value(Obj), DepClassTy::OPTIONAL,
85106c3fb27SDimitry Andric IsKnownNoCapture);
852bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj << "' is "
85306c3fb27SDimitry Andric << (IsAssumedNoCapture ? "" : "not") << " thread local; "
85406c3fb27SDimitry Andric << (IsAssumedNoCapture ? "non-" : "")
855bdd1243dSDimitry Andric << "captured stack object.\n");
85606c3fb27SDimitry Andric return IsAssumedNoCapture;
857bdd1243dSDimitry Andric }
858bdd1243dSDimitry Andric if (auto *GV = dyn_cast<GlobalVariable>(&Obj)) {
859bdd1243dSDimitry Andric if (GV->isConstant()) {
860bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj
861bdd1243dSDimitry Andric << "' is thread local; constant global\n");
862bdd1243dSDimitry Andric return true;
863bdd1243dSDimitry Andric }
864bdd1243dSDimitry Andric if (GV->isThreadLocal()) {
865bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj
866bdd1243dSDimitry Andric << "' is thread local; thread local global\n");
867bdd1243dSDimitry Andric return true;
868bdd1243dSDimitry Andric }
869bdd1243dSDimitry Andric }
870bdd1243dSDimitry Andric
871bdd1243dSDimitry Andric if (A.getInfoCache().targetIsGPU()) {
872bdd1243dSDimitry Andric if (Obj.getType()->getPointerAddressSpace() ==
873bdd1243dSDimitry Andric (int)AA::GPUAddressSpace::Local) {
874bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj
875bdd1243dSDimitry Andric << "' is thread local; GPU local memory\n");
876bdd1243dSDimitry Andric return true;
877bdd1243dSDimitry Andric }
878bdd1243dSDimitry Andric if (Obj.getType()->getPointerAddressSpace() ==
879bdd1243dSDimitry Andric (int)AA::GPUAddressSpace::Constant) {
880bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj
881bdd1243dSDimitry Andric << "' is thread local; GPU constant memory\n");
882bdd1243dSDimitry Andric return true;
883bdd1243dSDimitry Andric }
884bdd1243dSDimitry Andric }
885bdd1243dSDimitry Andric
886bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Object '" << Obj << "' is not thread local\n");
887bdd1243dSDimitry Andric return false;
888bdd1243dSDimitry Andric }
889bdd1243dSDimitry Andric
isPotentiallyAffectedByBarrier(Attributor & A,const Instruction & I,const AbstractAttribute & QueryingAA)890bdd1243dSDimitry Andric bool AA::isPotentiallyAffectedByBarrier(Attributor &A, const Instruction &I,
891bdd1243dSDimitry Andric const AbstractAttribute &QueryingAA) {
892bdd1243dSDimitry Andric if (!I.mayHaveSideEffects() && !I.mayReadFromMemory())
893bdd1243dSDimitry Andric return false;
894bdd1243dSDimitry Andric
895bdd1243dSDimitry Andric SmallSetVector<const Value *, 8> Ptrs;
896bdd1243dSDimitry Andric
897bdd1243dSDimitry Andric auto AddLocationPtr = [&](std::optional<MemoryLocation> Loc) {
898bdd1243dSDimitry Andric if (!Loc || !Loc->Ptr) {
899bdd1243dSDimitry Andric LLVM_DEBUG(
900bdd1243dSDimitry Andric dbgs() << "[AA] Access to unknown location; -> requires barriers\n");
901bdd1243dSDimitry Andric return false;
902bdd1243dSDimitry Andric }
903bdd1243dSDimitry Andric Ptrs.insert(Loc->Ptr);
904bdd1243dSDimitry Andric return true;
905bdd1243dSDimitry Andric };
906bdd1243dSDimitry Andric
907bdd1243dSDimitry Andric if (const MemIntrinsic *MI = dyn_cast<MemIntrinsic>(&I)) {
908bdd1243dSDimitry Andric if (!AddLocationPtr(MemoryLocation::getForDest(MI)))
909bdd1243dSDimitry Andric return true;
910bdd1243dSDimitry Andric if (const MemTransferInst *MTI = dyn_cast<MemTransferInst>(&I))
911bdd1243dSDimitry Andric if (!AddLocationPtr(MemoryLocation::getForSource(MTI)))
912bdd1243dSDimitry Andric return true;
913bdd1243dSDimitry Andric } else if (!AddLocationPtr(MemoryLocation::getOrNone(&I)))
914bdd1243dSDimitry Andric return true;
915bdd1243dSDimitry Andric
916bdd1243dSDimitry Andric return isPotentiallyAffectedByBarrier(A, Ptrs.getArrayRef(), QueryingAA, &I);
917bdd1243dSDimitry Andric }
918bdd1243dSDimitry Andric
isPotentiallyAffectedByBarrier(Attributor & A,ArrayRef<const Value * > Ptrs,const AbstractAttribute & QueryingAA,const Instruction * CtxI)919bdd1243dSDimitry Andric bool AA::isPotentiallyAffectedByBarrier(Attributor &A,
920bdd1243dSDimitry Andric ArrayRef<const Value *> Ptrs,
921bdd1243dSDimitry Andric const AbstractAttribute &QueryingAA,
922bdd1243dSDimitry Andric const Instruction *CtxI) {
923bdd1243dSDimitry Andric for (const Value *Ptr : Ptrs) {
924bdd1243dSDimitry Andric if (!Ptr) {
925bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] nullptr; -> requires barriers\n");
926bdd1243dSDimitry Andric return true;
927bdd1243dSDimitry Andric }
928bdd1243dSDimitry Andric
929bdd1243dSDimitry Andric auto Pred = [&](Value &Obj) {
930bdd1243dSDimitry Andric if (AA::isAssumedThreadLocalObject(A, Obj, QueryingAA))
931bdd1243dSDimitry Andric return true;
932bdd1243dSDimitry Andric LLVM_DEBUG(dbgs() << "[AA] Access to '" << Obj << "' via '" << *Ptr
933bdd1243dSDimitry Andric << "'; -> requires barrier\n");
934bdd1243dSDimitry Andric return false;
935bdd1243dSDimitry Andric };
936bdd1243dSDimitry Andric
93706c3fb27SDimitry Andric const auto *UnderlyingObjsAA = A.getAAFor<AAUnderlyingObjects>(
938bdd1243dSDimitry Andric QueryingAA, IRPosition::value(*Ptr), DepClassTy::OPTIONAL);
93906c3fb27SDimitry Andric if (!UnderlyingObjsAA || !UnderlyingObjsAA->forallUnderlyingObjects(Pred))
940bdd1243dSDimitry Andric return true;
941bdd1243dSDimitry Andric }
942bdd1243dSDimitry Andric return false;
9431fd87a68SDimitry Andric }
9441fd87a68SDimitry Andric
9450b57cec5SDimitry Andric /// Return true if \p New is equal or worse than \p Old.
isEqualOrWorse(const Attribute & New,const Attribute & Old)9460b57cec5SDimitry Andric static bool isEqualOrWorse(const Attribute &New, const Attribute &Old) {
9470b57cec5SDimitry Andric if (!Old.isIntAttribute())
9480b57cec5SDimitry Andric return true;
9490b57cec5SDimitry Andric
9500b57cec5SDimitry Andric return Old.getValueAsInt() >= New.getValueAsInt();
9510b57cec5SDimitry Andric }
9520b57cec5SDimitry Andric
9530b57cec5SDimitry Andric /// Return true if the information provided by \p Attr was added to the
95406c3fb27SDimitry Andric /// attribute set \p AttrSet. This is only the case if it was not already
95506c3fb27SDimitry Andric /// present in \p AttrSet.
addIfNotExistent(LLVMContext & Ctx,const Attribute & Attr,AttributeSet AttrSet,bool ForceReplace,AttrBuilder & AB)9560b57cec5SDimitry Andric static bool addIfNotExistent(LLVMContext &Ctx, const Attribute &Attr,
95706c3fb27SDimitry Andric AttributeSet AttrSet, bool ForceReplace,
95806c3fb27SDimitry Andric AttrBuilder &AB) {
9590b57cec5SDimitry Andric
9600b57cec5SDimitry Andric if (Attr.isEnumAttribute()) {
9610b57cec5SDimitry Andric Attribute::AttrKind Kind = Attr.getKindAsEnum();
96206c3fb27SDimitry Andric if (AttrSet.hasAttribute(Kind))
9630b57cec5SDimitry Andric return false;
96406c3fb27SDimitry Andric AB.addAttribute(Kind);
9650b57cec5SDimitry Andric return true;
9660b57cec5SDimitry Andric }
9670b57cec5SDimitry Andric if (Attr.isStringAttribute()) {
9680b57cec5SDimitry Andric StringRef Kind = Attr.getKindAsString();
96906c3fb27SDimitry Andric if (AttrSet.hasAttribute(Kind)) {
97006c3fb27SDimitry Andric if (!ForceReplace)
9710b57cec5SDimitry Andric return false;
97206c3fb27SDimitry Andric }
97306c3fb27SDimitry Andric AB.addAttribute(Kind, Attr.getValueAsString());
9740b57cec5SDimitry Andric return true;
9750b57cec5SDimitry Andric }
9768bcb0991SDimitry Andric if (Attr.isIntAttribute()) {
9778bcb0991SDimitry Andric Attribute::AttrKind Kind = Attr.getKindAsEnum();
97806c3fb27SDimitry Andric if (!ForceReplace && Kind == Attribute::Memory) {
97906c3fb27SDimitry Andric MemoryEffects ME = Attr.getMemoryEffects() & AttrSet.getMemoryEffects();
98006c3fb27SDimitry Andric if (ME == AttrSet.getMemoryEffects())
9818bcb0991SDimitry Andric return false;
98206c3fb27SDimitry Andric AB.addMemoryAttr(ME);
98306c3fb27SDimitry Andric return true;
98406c3fb27SDimitry Andric }
98506c3fb27SDimitry Andric if (AttrSet.hasAttribute(Kind)) {
98606c3fb27SDimitry Andric if (!ForceReplace && isEqualOrWorse(Attr, AttrSet.getAttribute(Kind)))
98706c3fb27SDimitry Andric return false;
98806c3fb27SDimitry Andric }
98906c3fb27SDimitry Andric AB.addAttribute(Attr);
9908bcb0991SDimitry Andric return true;
9918bcb0991SDimitry Andric }
9920b57cec5SDimitry Andric
9930b57cec5SDimitry Andric llvm_unreachable("Expected enum or string attribute!");
9940b57cec5SDimitry Andric }
9958bcb0991SDimitry Andric
getAssociatedArgument() const9965ffd83dbSDimitry Andric Argument *IRPosition::getAssociatedArgument() const {
9975ffd83dbSDimitry Andric if (getPositionKind() == IRP_ARGUMENT)
9985ffd83dbSDimitry Andric return cast<Argument>(&getAnchorValue());
9995ffd83dbSDimitry Andric
10005ffd83dbSDimitry Andric // Not an Argument and no argument number means this is not a call site
10015ffd83dbSDimitry Andric // argument, thus we cannot find a callback argument to return.
1002e8d8bef9SDimitry Andric int ArgNo = getCallSiteArgNo();
10035ffd83dbSDimitry Andric if (ArgNo < 0)
10048bcb0991SDimitry Andric return nullptr;
10058bcb0991SDimitry Andric
10065ffd83dbSDimitry Andric // Use abstract call sites to make the connection between the call site
10075ffd83dbSDimitry Andric // values and the ones in callbacks. If a callback was found that makes use
10085ffd83dbSDimitry Andric // of the underlying call site operand, we want the corresponding callback
10095ffd83dbSDimitry Andric // callee argument and not the direct callee argument.
1010bdd1243dSDimitry Andric std::optional<Argument *> CBCandidateArg;
10115ffd83dbSDimitry Andric SmallVector<const Use *, 4> CallbackUses;
10125ffd83dbSDimitry Andric const auto &CB = cast<CallBase>(getAnchorValue());
10135ffd83dbSDimitry Andric AbstractCallSite::getCallbackUses(CB, CallbackUses);
10145ffd83dbSDimitry Andric for (const Use *U : CallbackUses) {
10155ffd83dbSDimitry Andric AbstractCallSite ACS(U);
10165ffd83dbSDimitry Andric assert(ACS && ACS.isCallbackCall());
10175ffd83dbSDimitry Andric if (!ACS.getCalledFunction())
10185ffd83dbSDimitry Andric continue;
10195ffd83dbSDimitry Andric
10205ffd83dbSDimitry Andric for (unsigned u = 0, e = ACS.getNumArgOperands(); u < e; u++) {
10215ffd83dbSDimitry Andric
10225ffd83dbSDimitry Andric // Test if the underlying call site operand is argument number u of the
10235ffd83dbSDimitry Andric // callback callee.
10245ffd83dbSDimitry Andric if (ACS.getCallArgOperandNo(u) != ArgNo)
10255ffd83dbSDimitry Andric continue;
10265ffd83dbSDimitry Andric
10275ffd83dbSDimitry Andric assert(ACS.getCalledFunction()->arg_size() > u &&
10285ffd83dbSDimitry Andric "ACS mapped into var-args arguments!");
102981ad6265SDimitry Andric if (CBCandidateArg) {
10305ffd83dbSDimitry Andric CBCandidateArg = nullptr;
10315ffd83dbSDimitry Andric break;
10325ffd83dbSDimitry Andric }
10335ffd83dbSDimitry Andric CBCandidateArg = ACS.getCalledFunction()->getArg(u);
10345ffd83dbSDimitry Andric }
10355ffd83dbSDimitry Andric }
10365ffd83dbSDimitry Andric
10375ffd83dbSDimitry Andric // If we found a unique callback candidate argument, return it.
1038bdd1243dSDimitry Andric if (CBCandidateArg && *CBCandidateArg)
1039bdd1243dSDimitry Andric return *CBCandidateArg;
10405ffd83dbSDimitry Andric
10415ffd83dbSDimitry Andric // If no callbacks were found, or none used the underlying call site operand
10425ffd83dbSDimitry Andric // exclusively, use the direct callee argument if available.
104306c3fb27SDimitry Andric auto *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand());
10445ffd83dbSDimitry Andric if (Callee && Callee->arg_size() > unsigned(ArgNo))
10455ffd83dbSDimitry Andric return Callee->getArg(ArgNo);
10465ffd83dbSDimitry Andric
10475ffd83dbSDimitry Andric return nullptr;
10488bcb0991SDimitry Andric }
10490b57cec5SDimitry Andric
update(Attributor & A)10500b57cec5SDimitry Andric ChangeStatus AbstractAttribute::update(Attributor &A) {
10510b57cec5SDimitry Andric ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
10520b57cec5SDimitry Andric if (getState().isAtFixpoint())
10530b57cec5SDimitry Andric return HasChanged;
10540b57cec5SDimitry Andric
10550b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Update: " << *this << "\n");
10560b57cec5SDimitry Andric
10570b57cec5SDimitry Andric HasChanged = updateImpl(A);
10580b57cec5SDimitry Andric
10590b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Update " << HasChanged << " " << *this
10600b57cec5SDimitry Andric << "\n");
10610b57cec5SDimitry Andric
10620b57cec5SDimitry Andric return HasChanged;
10630b57cec5SDimitry Andric }
10640b57cec5SDimitry Andric
Attributor(SetVector<Function * > & Functions,InformationCache & InfoCache,AttributorConfig Configuration)10655f757f3fSDimitry Andric Attributor::Attributor(SetVector<Function *> &Functions,
10665f757f3fSDimitry Andric InformationCache &InfoCache,
10675f757f3fSDimitry Andric AttributorConfig Configuration)
10685f757f3fSDimitry Andric : Allocator(InfoCache.Allocator), Functions(Functions),
10695f757f3fSDimitry Andric InfoCache(InfoCache), Configuration(Configuration) {
10705f757f3fSDimitry Andric if (!isClosedWorldModule())
10715f757f3fSDimitry Andric return;
10725f757f3fSDimitry Andric for (Function *Fn : Functions)
10735f757f3fSDimitry Andric if (Fn->hasAddressTaken(/*PutOffender=*/nullptr,
10745f757f3fSDimitry Andric /*IgnoreCallbackUses=*/false,
10755f757f3fSDimitry Andric /*IgnoreAssumeLikeCalls=*/true,
10765f757f3fSDimitry Andric /*IgnoreLLVMUsed=*/true,
10775f757f3fSDimitry Andric /*IgnoreARCAttachedCall=*/false,
10785f757f3fSDimitry Andric /*IgnoreCastedDirectCall=*/true))
10795f757f3fSDimitry Andric InfoCache.IndirectlyCallableFunctions.push_back(Fn);
10805f757f3fSDimitry Andric }
10815f757f3fSDimitry Andric
getAttrsFromAssumes(const IRPosition & IRP,Attribute::AttrKind AK,SmallVectorImpl<Attribute> & Attrs)108206c3fb27SDimitry Andric bool Attributor::getAttrsFromAssumes(const IRPosition &IRP,
108306c3fb27SDimitry Andric Attribute::AttrKind AK,
108406c3fb27SDimitry Andric SmallVectorImpl<Attribute> &Attrs) {
108506c3fb27SDimitry Andric assert(IRP.getPositionKind() != IRPosition::IRP_INVALID &&
108606c3fb27SDimitry Andric "Did expect a valid position!");
108706c3fb27SDimitry Andric MustBeExecutedContextExplorer *Explorer =
108806c3fb27SDimitry Andric getInfoCache().getMustBeExecutedContextExplorer();
108906c3fb27SDimitry Andric if (!Explorer)
109006c3fb27SDimitry Andric return false;
10910b57cec5SDimitry Andric
109206c3fb27SDimitry Andric Value &AssociatedValue = IRP.getAssociatedValue();
10930b57cec5SDimitry Andric
109406c3fb27SDimitry Andric const Assume2KnowledgeMap &A2K =
109506c3fb27SDimitry Andric getInfoCache().getKnowledgeMap().lookup({&AssociatedValue, AK});
109606c3fb27SDimitry Andric
109706c3fb27SDimitry Andric // Check if we found any potential assume use, if not we don't need to create
109806c3fb27SDimitry Andric // explorer iterators.
109906c3fb27SDimitry Andric if (A2K.empty())
110006c3fb27SDimitry Andric return false;
110106c3fb27SDimitry Andric
110206c3fb27SDimitry Andric LLVMContext &Ctx = AssociatedValue.getContext();
110306c3fb27SDimitry Andric unsigned AttrsSize = Attrs.size();
110406c3fb27SDimitry Andric auto EIt = Explorer->begin(IRP.getCtxI()),
110506c3fb27SDimitry Andric EEnd = Explorer->end(IRP.getCtxI());
110606c3fb27SDimitry Andric for (const auto &It : A2K)
110706c3fb27SDimitry Andric if (Explorer->findInContextOf(It.first, EIt, EEnd))
110806c3fb27SDimitry Andric Attrs.push_back(Attribute::get(Ctx, AK, It.second.Max));
110906c3fb27SDimitry Andric return AttrsSize != Attrs.size();
11100b57cec5SDimitry Andric }
11110b57cec5SDimitry Andric
111206c3fb27SDimitry Andric template <typename DescTy>
111306c3fb27SDimitry Andric ChangeStatus
updateAttrMap(const IRPosition & IRP,ArrayRef<DescTy> AttrDescs,function_ref<bool (const DescTy &,AttributeSet,AttributeMask &,AttrBuilder &)> CB)11145f757f3fSDimitry Andric Attributor::updateAttrMap(const IRPosition &IRP, ArrayRef<DescTy> AttrDescs,
111506c3fb27SDimitry Andric function_ref<bool(const DescTy &, AttributeSet,
111606c3fb27SDimitry Andric AttributeMask &, AttrBuilder &)>
111706c3fb27SDimitry Andric CB) {
111806c3fb27SDimitry Andric if (AttrDescs.empty())
111906c3fb27SDimitry Andric return ChangeStatus::UNCHANGED;
112006c3fb27SDimitry Andric switch (IRP.getPositionKind()) {
112106c3fb27SDimitry Andric case IRPosition::IRP_FLOAT:
112206c3fb27SDimitry Andric case IRPosition::IRP_INVALID:
112306c3fb27SDimitry Andric return ChangeStatus::UNCHANGED;
112406c3fb27SDimitry Andric default:
112506c3fb27SDimitry Andric break;
112606c3fb27SDimitry Andric };
112706c3fb27SDimitry Andric
112806c3fb27SDimitry Andric AttributeList AL;
112906c3fb27SDimitry Andric Value *AttrListAnchor = IRP.getAttrListAnchor();
113006c3fb27SDimitry Andric auto It = AttrsMap.find(AttrListAnchor);
113106c3fb27SDimitry Andric if (It == AttrsMap.end())
113206c3fb27SDimitry Andric AL = IRP.getAttrList();
113306c3fb27SDimitry Andric else
113406c3fb27SDimitry Andric AL = It->getSecond();
113506c3fb27SDimitry Andric
113606c3fb27SDimitry Andric LLVMContext &Ctx = IRP.getAnchorValue().getContext();
113706c3fb27SDimitry Andric auto AttrIdx = IRP.getAttrIdx();
113806c3fb27SDimitry Andric AttributeSet AS = AL.getAttributes(AttrIdx);
113906c3fb27SDimitry Andric AttributeMask AM;
114006c3fb27SDimitry Andric AttrBuilder AB(Ctx);
114106c3fb27SDimitry Andric
11428bcb0991SDimitry Andric ChangeStatus HasChanged = ChangeStatus::UNCHANGED;
114306c3fb27SDimitry Andric for (const DescTy &AttrDesc : AttrDescs)
114406c3fb27SDimitry Andric if (CB(AttrDesc, AS, AM, AB))
11450b57cec5SDimitry Andric HasChanged = ChangeStatus::CHANGED;
11460b57cec5SDimitry Andric
11470b57cec5SDimitry Andric if (HasChanged == ChangeStatus::UNCHANGED)
114806c3fb27SDimitry Andric return ChangeStatus::UNCHANGED;
11490b57cec5SDimitry Andric
115006c3fb27SDimitry Andric AL = AL.removeAttributesAtIndex(Ctx, AttrIdx, AM);
115106c3fb27SDimitry Andric AL = AL.addAttributesAtIndex(Ctx, AttrIdx, AB);
115206c3fb27SDimitry Andric AttrsMap[AttrListAnchor] = AL;
115306c3fb27SDimitry Andric return ChangeStatus::CHANGED;
11540b57cec5SDimitry Andric }
11550b57cec5SDimitry Andric
hasAttr(const IRPosition & IRP,ArrayRef<Attribute::AttrKind> AttrKinds,bool IgnoreSubsumingPositions,Attribute::AttrKind ImpliedAttributeKind)115606c3fb27SDimitry Andric bool Attributor::hasAttr(const IRPosition &IRP,
115706c3fb27SDimitry Andric ArrayRef<Attribute::AttrKind> AttrKinds,
115806c3fb27SDimitry Andric bool IgnoreSubsumingPositions,
115906c3fb27SDimitry Andric Attribute::AttrKind ImpliedAttributeKind) {
116006c3fb27SDimitry Andric bool Implied = false;
116106c3fb27SDimitry Andric bool HasAttr = false;
116206c3fb27SDimitry Andric auto HasAttrCB = [&](const Attribute::AttrKind &Kind, AttributeSet AttrSet,
116306c3fb27SDimitry Andric AttributeMask &, AttrBuilder &) {
116406c3fb27SDimitry Andric if (AttrSet.hasAttribute(Kind)) {
116506c3fb27SDimitry Andric Implied |= Kind != ImpliedAttributeKind;
116606c3fb27SDimitry Andric HasAttr = true;
116706c3fb27SDimitry Andric }
116806c3fb27SDimitry Andric return false;
116906c3fb27SDimitry Andric };
117006c3fb27SDimitry Andric for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) {
117106c3fb27SDimitry Andric updateAttrMap<Attribute::AttrKind>(EquivIRP, AttrKinds, HasAttrCB);
117206c3fb27SDimitry Andric if (HasAttr)
117306c3fb27SDimitry Andric break;
117406c3fb27SDimitry Andric // The first position returned by the SubsumingPositionIterator is
117506c3fb27SDimitry Andric // always the position itself. If we ignore subsuming positions we
117606c3fb27SDimitry Andric // are done after the first iteration.
117706c3fb27SDimitry Andric if (IgnoreSubsumingPositions)
117806c3fb27SDimitry Andric break;
117906c3fb27SDimitry Andric Implied = true;
118006c3fb27SDimitry Andric }
118106c3fb27SDimitry Andric if (!HasAttr) {
118206c3fb27SDimitry Andric Implied = true;
118306c3fb27SDimitry Andric SmallVector<Attribute> Attrs;
118406c3fb27SDimitry Andric for (Attribute::AttrKind AK : AttrKinds)
118506c3fb27SDimitry Andric if (getAttrsFromAssumes(IRP, AK, Attrs)) {
118606c3fb27SDimitry Andric HasAttr = true;
118706c3fb27SDimitry Andric break;
118806c3fb27SDimitry Andric }
118906c3fb27SDimitry Andric }
119006c3fb27SDimitry Andric
119106c3fb27SDimitry Andric // Check if we should manifest the implied attribute kind at the IRP.
119206c3fb27SDimitry Andric if (ImpliedAttributeKind != Attribute::None && HasAttr && Implied)
119306c3fb27SDimitry Andric manifestAttrs(IRP, {Attribute::get(IRP.getAnchorValue().getContext(),
119406c3fb27SDimitry Andric ImpliedAttributeKind)});
119506c3fb27SDimitry Andric return HasAttr;
119606c3fb27SDimitry Andric }
119706c3fb27SDimitry Andric
getAttrs(const IRPosition & IRP,ArrayRef<Attribute::AttrKind> AttrKinds,SmallVectorImpl<Attribute> & Attrs,bool IgnoreSubsumingPositions)119806c3fb27SDimitry Andric void Attributor::getAttrs(const IRPosition &IRP,
119906c3fb27SDimitry Andric ArrayRef<Attribute::AttrKind> AttrKinds,
120006c3fb27SDimitry Andric SmallVectorImpl<Attribute> &Attrs,
120106c3fb27SDimitry Andric bool IgnoreSubsumingPositions) {
120206c3fb27SDimitry Andric auto CollectAttrCB = [&](const Attribute::AttrKind &Kind,
120306c3fb27SDimitry Andric AttributeSet AttrSet, AttributeMask &,
120406c3fb27SDimitry Andric AttrBuilder &) {
120506c3fb27SDimitry Andric if (AttrSet.hasAttribute(Kind))
120606c3fb27SDimitry Andric Attrs.push_back(AttrSet.getAttribute(Kind));
120706c3fb27SDimitry Andric return false;
120806c3fb27SDimitry Andric };
120906c3fb27SDimitry Andric for (const IRPosition &EquivIRP : SubsumingPositionIterator(IRP)) {
121006c3fb27SDimitry Andric updateAttrMap<Attribute::AttrKind>(EquivIRP, AttrKinds, CollectAttrCB);
121106c3fb27SDimitry Andric // The first position returned by the SubsumingPositionIterator is
121206c3fb27SDimitry Andric // always the position itself. If we ignore subsuming positions we
121306c3fb27SDimitry Andric // are done after the first iteration.
121406c3fb27SDimitry Andric if (IgnoreSubsumingPositions)
121506c3fb27SDimitry Andric break;
121606c3fb27SDimitry Andric }
121706c3fb27SDimitry Andric for (Attribute::AttrKind AK : AttrKinds)
121806c3fb27SDimitry Andric getAttrsFromAssumes(IRP, AK, Attrs);
121906c3fb27SDimitry Andric }
122006c3fb27SDimitry Andric
removeAttrs(const IRPosition & IRP,ArrayRef<Attribute::AttrKind> AttrKinds)12215f757f3fSDimitry Andric ChangeStatus Attributor::removeAttrs(const IRPosition &IRP,
12225f757f3fSDimitry Andric ArrayRef<Attribute::AttrKind> AttrKinds) {
122306c3fb27SDimitry Andric auto RemoveAttrCB = [&](const Attribute::AttrKind &Kind, AttributeSet AttrSet,
122406c3fb27SDimitry Andric AttributeMask &AM, AttrBuilder &) {
122506c3fb27SDimitry Andric if (!AttrSet.hasAttribute(Kind))
122606c3fb27SDimitry Andric return false;
122706c3fb27SDimitry Andric AM.addAttribute(Kind);
122806c3fb27SDimitry Andric return true;
122906c3fb27SDimitry Andric };
123006c3fb27SDimitry Andric return updateAttrMap<Attribute::AttrKind>(IRP, AttrKinds, RemoveAttrCB);
123106c3fb27SDimitry Andric }
123206c3fb27SDimitry Andric
removeAttrs(const IRPosition & IRP,ArrayRef<StringRef> Attrs)12335f757f3fSDimitry Andric ChangeStatus Attributor::removeAttrs(const IRPosition &IRP,
12345f757f3fSDimitry Andric ArrayRef<StringRef> Attrs) {
12355f757f3fSDimitry Andric auto RemoveAttrCB = [&](StringRef Attr, AttributeSet AttrSet,
12365f757f3fSDimitry Andric AttributeMask &AM, AttrBuilder &) -> bool {
12375f757f3fSDimitry Andric if (!AttrSet.hasAttribute(Attr))
12385f757f3fSDimitry Andric return false;
12395f757f3fSDimitry Andric AM.addAttribute(Attr);
12405f757f3fSDimitry Andric return true;
12415f757f3fSDimitry Andric };
12425f757f3fSDimitry Andric
12435f757f3fSDimitry Andric return updateAttrMap<StringRef>(IRP, Attrs, RemoveAttrCB);
12445f757f3fSDimitry Andric }
12455f757f3fSDimitry Andric
manifestAttrs(const IRPosition & IRP,ArrayRef<Attribute> Attrs,bool ForceReplace)124606c3fb27SDimitry Andric ChangeStatus Attributor::manifestAttrs(const IRPosition &IRP,
12475f757f3fSDimitry Andric ArrayRef<Attribute> Attrs,
124806c3fb27SDimitry Andric bool ForceReplace) {
124906c3fb27SDimitry Andric LLVMContext &Ctx = IRP.getAnchorValue().getContext();
125006c3fb27SDimitry Andric auto AddAttrCB = [&](const Attribute &Attr, AttributeSet AttrSet,
125106c3fb27SDimitry Andric AttributeMask &, AttrBuilder &AB) {
125206c3fb27SDimitry Andric return addIfNotExistent(Ctx, Attr, AttrSet, ForceReplace, AB);
125306c3fb27SDimitry Andric };
125406c3fb27SDimitry Andric return updateAttrMap<Attribute>(IRP, Attrs, AddAttrCB);
12550b57cec5SDimitry Andric }
12560b57cec5SDimitry Andric
12575ffd83dbSDimitry Andric const IRPosition IRPosition::EmptyKey(DenseMapInfo<void *>::getEmptyKey());
12585ffd83dbSDimitry Andric const IRPosition
12595ffd83dbSDimitry Andric IRPosition::TombstoneKey(DenseMapInfo<void *>::getTombstoneKey());
12608bcb0991SDimitry Andric
SubsumingPositionIterator(const IRPosition & IRP)12618bcb0991SDimitry Andric SubsumingPositionIterator::SubsumingPositionIterator(const IRPosition &IRP) {
12628bcb0991SDimitry Andric IRPositions.emplace_back(IRP);
12638bcb0991SDimitry Andric
126406c3fb27SDimitry Andric // Helper to determine if operand bundles on a call site are benign or
1265e8d8bef9SDimitry Andric // potentially problematic. We handle only llvm.assume for now.
1266e8d8bef9SDimitry Andric auto CanIgnoreOperandBundles = [](const CallBase &CB) {
1267e8d8bef9SDimitry Andric return (isa<IntrinsicInst>(CB) &&
1268e8d8bef9SDimitry Andric cast<IntrinsicInst>(CB).getIntrinsicID() == Intrinsic ::assume);
1269e8d8bef9SDimitry Andric };
1270e8d8bef9SDimitry Andric
12715ffd83dbSDimitry Andric const auto *CB = dyn_cast<CallBase>(&IRP.getAnchorValue());
12728bcb0991SDimitry Andric switch (IRP.getPositionKind()) {
12738bcb0991SDimitry Andric case IRPosition::IRP_INVALID:
12748bcb0991SDimitry Andric case IRPosition::IRP_FLOAT:
12758bcb0991SDimitry Andric case IRPosition::IRP_FUNCTION:
12768bcb0991SDimitry Andric return;
12778bcb0991SDimitry Andric case IRPosition::IRP_ARGUMENT:
12788bcb0991SDimitry Andric case IRPosition::IRP_RETURNED:
12795ffd83dbSDimitry Andric IRPositions.emplace_back(IRPosition::function(*IRP.getAnchorScope()));
12808bcb0991SDimitry Andric return;
12818bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE:
12825ffd83dbSDimitry Andric assert(CB && "Expected call site!");
12838bcb0991SDimitry Andric // TODO: We need to look at the operand bundles similar to the redirection
12848bcb0991SDimitry Andric // in CallBase.
1285e8d8bef9SDimitry Andric if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB))
128606c3fb27SDimitry Andric if (auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand()))
12878bcb0991SDimitry Andric IRPositions.emplace_back(IRPosition::function(*Callee));
12888bcb0991SDimitry Andric return;
12898bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE_RETURNED:
12905ffd83dbSDimitry Andric assert(CB && "Expected call site!");
12918bcb0991SDimitry Andric // TODO: We need to look at the operand bundles similar to the redirection
12928bcb0991SDimitry Andric // in CallBase.
1293e8d8bef9SDimitry Andric if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) {
129406c3fb27SDimitry Andric if (auto *Callee =
129506c3fb27SDimitry Andric dyn_cast_if_present<Function>(CB->getCalledOperand())) {
12968bcb0991SDimitry Andric IRPositions.emplace_back(IRPosition::returned(*Callee));
12978bcb0991SDimitry Andric IRPositions.emplace_back(IRPosition::function(*Callee));
12985ffd83dbSDimitry Andric for (const Argument &Arg : Callee->args())
12995ffd83dbSDimitry Andric if (Arg.hasReturnedAttr()) {
13008bcb0991SDimitry Andric IRPositions.emplace_back(
13015ffd83dbSDimitry Andric IRPosition::callsite_argument(*CB, Arg.getArgNo()));
13025ffd83dbSDimitry Andric IRPositions.emplace_back(
13035ffd83dbSDimitry Andric IRPosition::value(*CB->getArgOperand(Arg.getArgNo())));
13045ffd83dbSDimitry Andric IRPositions.emplace_back(IRPosition::argument(Arg));
13055ffd83dbSDimitry Andric }
13065ffd83dbSDimitry Andric }
13075ffd83dbSDimitry Andric }
13085ffd83dbSDimitry Andric IRPositions.emplace_back(IRPosition::callsite_function(*CB));
13098bcb0991SDimitry Andric return;
13108bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE_ARGUMENT: {
1311e8d8bef9SDimitry Andric assert(CB && "Expected call site!");
13128bcb0991SDimitry Andric // TODO: We need to look at the operand bundles similar to the redirection
13138bcb0991SDimitry Andric // in CallBase.
1314e8d8bef9SDimitry Andric if (!CB->hasOperandBundles() || CanIgnoreOperandBundles(*CB)) {
131506c3fb27SDimitry Andric auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand());
1316e8d8bef9SDimitry Andric if (Callee) {
1317e8d8bef9SDimitry Andric if (Argument *Arg = IRP.getAssociatedArgument())
1318e8d8bef9SDimitry Andric IRPositions.emplace_back(IRPosition::argument(*Arg));
13198bcb0991SDimitry Andric IRPositions.emplace_back(IRPosition::function(*Callee));
13208bcb0991SDimitry Andric }
1321e8d8bef9SDimitry Andric }
13228bcb0991SDimitry Andric IRPositions.emplace_back(IRPosition::value(IRP.getAssociatedValue()));
13238bcb0991SDimitry Andric return;
13248bcb0991SDimitry Andric }
13258bcb0991SDimitry Andric }
13260b57cec5SDimitry Andric }
13270b57cec5SDimitry Andric
verify()13288bcb0991SDimitry Andric void IRPosition::verify() {
13295ffd83dbSDimitry Andric #ifdef EXPENSIVE_CHECKS
13305ffd83dbSDimitry Andric switch (getPositionKind()) {
13318bcb0991SDimitry Andric case IRP_INVALID:
1332fe6060f1SDimitry Andric assert((CBContext == nullptr) &&
1333fe6060f1SDimitry Andric "Invalid position must not have CallBaseContext!");
13345ffd83dbSDimitry Andric assert(!Enc.getOpaqueValue() &&
13355ffd83dbSDimitry Andric "Expected a nullptr for an invalid position!");
13365ffd83dbSDimitry Andric return;
13378bcb0991SDimitry Andric case IRP_FLOAT:
13381fd87a68SDimitry Andric assert((!isa<Argument>(&getAssociatedValue())) &&
13391fd87a68SDimitry Andric "Expected specialized kind for argument values!");
13405ffd83dbSDimitry Andric return;
13418bcb0991SDimitry Andric case IRP_RETURNED:
13425ffd83dbSDimitry Andric assert(isa<Function>(getAsValuePtr()) &&
13438bcb0991SDimitry Andric "Expected function for a 'returned' position!");
13445ffd83dbSDimitry Andric assert(getAsValuePtr() == &getAssociatedValue() &&
13455ffd83dbSDimitry Andric "Associated value mismatch!");
13465ffd83dbSDimitry Andric return;
13478bcb0991SDimitry Andric case IRP_CALL_SITE_RETURNED:
1348fe6060f1SDimitry Andric assert((CBContext == nullptr) &&
1349fe6060f1SDimitry Andric "'call site returned' position must not have CallBaseContext!");
13505ffd83dbSDimitry Andric assert((isa<CallBase>(getAsValuePtr())) &&
13518bcb0991SDimitry Andric "Expected call base for 'call site returned' position!");
13525ffd83dbSDimitry Andric assert(getAsValuePtr() == &getAssociatedValue() &&
13535ffd83dbSDimitry Andric "Associated value mismatch!");
13545ffd83dbSDimitry Andric return;
13558bcb0991SDimitry Andric case IRP_CALL_SITE:
1356fe6060f1SDimitry Andric assert((CBContext == nullptr) &&
1357fe6060f1SDimitry Andric "'call site function' position must not have CallBaseContext!");
13585ffd83dbSDimitry Andric assert((isa<CallBase>(getAsValuePtr())) &&
13598bcb0991SDimitry Andric "Expected call base for 'call site function' position!");
13605ffd83dbSDimitry Andric assert(getAsValuePtr() == &getAssociatedValue() &&
13615ffd83dbSDimitry Andric "Associated value mismatch!");
13625ffd83dbSDimitry Andric return;
13638bcb0991SDimitry Andric case IRP_FUNCTION:
13645ffd83dbSDimitry Andric assert(isa<Function>(getAsValuePtr()) &&
13658bcb0991SDimitry Andric "Expected function for a 'function' position!");
13665ffd83dbSDimitry Andric assert(getAsValuePtr() == &getAssociatedValue() &&
13675ffd83dbSDimitry Andric "Associated value mismatch!");
13688bcb0991SDimitry Andric return;
13695ffd83dbSDimitry Andric case IRP_ARGUMENT:
13705ffd83dbSDimitry Andric assert(isa<Argument>(getAsValuePtr()) &&
13715ffd83dbSDimitry Andric "Expected argument for a 'argument' position!");
13725ffd83dbSDimitry Andric assert(getAsValuePtr() == &getAssociatedValue() &&
13735ffd83dbSDimitry Andric "Associated value mismatch!");
13748bcb0991SDimitry Andric return;
13755ffd83dbSDimitry Andric case IRP_CALL_SITE_ARGUMENT: {
1376fe6060f1SDimitry Andric assert((CBContext == nullptr) &&
1377fe6060f1SDimitry Andric "'call site argument' position must not have CallBaseContext!");
13785ffd83dbSDimitry Andric Use *U = getAsUsePtr();
137904eeddc0SDimitry Andric (void)U; // Silence unused variable warning.
13805ffd83dbSDimitry Andric assert(U && "Expected use for a 'call site argument' position!");
13815ffd83dbSDimitry Andric assert(isa<CallBase>(U->getUser()) &&
13825ffd83dbSDimitry Andric "Expected call base user for a 'call site argument' position!");
13835ffd83dbSDimitry Andric assert(cast<CallBase>(U->getUser())->isArgOperand(U) &&
13845ffd83dbSDimitry Andric "Expected call base argument operand for a 'call site argument' "
13855ffd83dbSDimitry Andric "position");
13865ffd83dbSDimitry Andric assert(cast<CallBase>(U->getUser())->getArgOperandNo(U) ==
1387e8d8bef9SDimitry Andric unsigned(getCallSiteArgNo()) &&
13885ffd83dbSDimitry Andric "Argument number mismatch!");
13895ffd83dbSDimitry Andric assert(U->get() == &getAssociatedValue() && "Associated value mismatch!");
13900b57cec5SDimitry Andric return;
13910b57cec5SDimitry Andric }
13920b57cec5SDimitry Andric }
13935ffd83dbSDimitry Andric #endif
13940b57cec5SDimitry Andric }
13950b57cec5SDimitry Andric
1396bdd1243dSDimitry Andric std::optional<Constant *>
getAssumedConstant(const IRPosition & IRP,const AbstractAttribute & AA,bool & UsedAssumedInformation)1397fe6060f1SDimitry Andric Attributor::getAssumedConstant(const IRPosition &IRP,
1398fe6060f1SDimitry Andric const AbstractAttribute &AA,
1399480093f4SDimitry Andric bool &UsedAssumedInformation) {
1400fe6060f1SDimitry Andric // First check all callbacks provided by outside AAs. If any of them returns
1401bdd1243dSDimitry Andric // a non-null value that is different from the associated value, or
1402bdd1243dSDimitry Andric // std::nullopt, we assume it's simplified.
1403fe6060f1SDimitry Andric for (auto &CB : SimplificationCallbacks.lookup(IRP)) {
1404bdd1243dSDimitry Andric std::optional<Value *> SimplifiedV = CB(IRP, &AA, UsedAssumedInformation);
140581ad6265SDimitry Andric if (!SimplifiedV)
1406bdd1243dSDimitry Andric return std::nullopt;
1407fe6060f1SDimitry Andric if (isa_and_nonnull<Constant>(*SimplifiedV))
1408fe6060f1SDimitry Andric return cast<Constant>(*SimplifiedV);
1409fe6060f1SDimitry Andric return nullptr;
1410fe6060f1SDimitry Andric }
141181ad6265SDimitry Andric if (auto *C = dyn_cast<Constant>(&IRP.getAssociatedValue()))
141281ad6265SDimitry Andric return C;
1413fcaf7f86SDimitry Andric SmallVector<AA::ValueAndContext> Values;
1414fcaf7f86SDimitry Andric if (getAssumedSimplifiedValues(IRP, &AA, Values,
1415fcaf7f86SDimitry Andric AA::ValueScope::Interprocedural,
1416fcaf7f86SDimitry Andric UsedAssumedInformation)) {
1417fcaf7f86SDimitry Andric if (Values.empty())
1418bdd1243dSDimitry Andric return std::nullopt;
1419fcaf7f86SDimitry Andric if (auto *C = dyn_cast_or_null<Constant>(
1420fcaf7f86SDimitry Andric AAPotentialValues::getSingleValue(*this, AA, IRP, Values)))
1421fcaf7f86SDimitry Andric return C;
14225ffd83dbSDimitry Andric }
1423fcaf7f86SDimitry Andric return nullptr;
1424480093f4SDimitry Andric }
1425480093f4SDimitry Andric
getAssumedSimplified(const IRPosition & IRP,const AbstractAttribute * AA,bool & UsedAssumedInformation,AA::ValueScope S)1426bdd1243dSDimitry Andric std::optional<Value *> Attributor::getAssumedSimplified(
1427bdd1243dSDimitry Andric const IRPosition &IRP, const AbstractAttribute *AA,
1428bdd1243dSDimitry Andric bool &UsedAssumedInformation, AA::ValueScope S) {
1429fe6060f1SDimitry Andric // First check all callbacks provided by outside AAs. If any of them returns
1430bdd1243dSDimitry Andric // a non-null value that is different from the associated value, or
1431bdd1243dSDimitry Andric // std::nullopt, we assume it's simplified.
1432fe6060f1SDimitry Andric for (auto &CB : SimplificationCallbacks.lookup(IRP))
1433fe6060f1SDimitry Andric return CB(IRP, AA, UsedAssumedInformation);
1434fe6060f1SDimitry Andric
1435fcaf7f86SDimitry Andric SmallVector<AA::ValueAndContext> Values;
1436fcaf7f86SDimitry Andric if (!getAssumedSimplifiedValues(IRP, AA, Values, S, UsedAssumedInformation))
1437fcaf7f86SDimitry Andric return &IRP.getAssociatedValue();
1438fcaf7f86SDimitry Andric if (Values.empty())
1439bdd1243dSDimitry Andric return std::nullopt;
1440fe6060f1SDimitry Andric if (AA)
1441fcaf7f86SDimitry Andric if (Value *V = AAPotentialValues::getSingleValue(*this, *AA, IRP, Values))
1442fcaf7f86SDimitry Andric return V;
1443fcaf7f86SDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_RETURNED ||
1444fcaf7f86SDimitry Andric IRP.getPositionKind() == IRPosition::IRP_CALL_SITE_RETURNED)
1445fcaf7f86SDimitry Andric return nullptr;
1446fcaf7f86SDimitry Andric return &IRP.getAssociatedValue();
1447fe6060f1SDimitry Andric }
1448fcaf7f86SDimitry Andric
getAssumedSimplifiedValues(const IRPosition & InitialIRP,const AbstractAttribute * AA,SmallVectorImpl<AA::ValueAndContext> & Values,AA::ValueScope S,bool & UsedAssumedInformation,bool RecurseForSelectAndPHI)1449fcaf7f86SDimitry Andric bool Attributor::getAssumedSimplifiedValues(
145006c3fb27SDimitry Andric const IRPosition &InitialIRP, const AbstractAttribute *AA,
1451fcaf7f86SDimitry Andric SmallVectorImpl<AA::ValueAndContext> &Values, AA::ValueScope S,
145206c3fb27SDimitry Andric bool &UsedAssumedInformation, bool RecurseForSelectAndPHI) {
145306c3fb27SDimitry Andric SmallPtrSet<Value *, 8> Seen;
145406c3fb27SDimitry Andric SmallVector<IRPosition, 8> Worklist;
145506c3fb27SDimitry Andric Worklist.push_back(InitialIRP);
145606c3fb27SDimitry Andric while (!Worklist.empty()) {
145706c3fb27SDimitry Andric const IRPosition &IRP = Worklist.pop_back_val();
145806c3fb27SDimitry Andric
1459fcaf7f86SDimitry Andric // First check all callbacks provided by outside AAs. If any of them returns
1460bdd1243dSDimitry Andric // a non-null value that is different from the associated value, or
1461bdd1243dSDimitry Andric // std::nullopt, we assume it's simplified.
146206c3fb27SDimitry Andric int NV = Values.size();
1463fcaf7f86SDimitry Andric const auto &SimplificationCBs = SimplificationCallbacks.lookup(IRP);
1464bdd1243dSDimitry Andric for (const auto &CB : SimplificationCBs) {
1465bdd1243dSDimitry Andric std::optional<Value *> CBResult = CB(IRP, AA, UsedAssumedInformation);
1466fcaf7f86SDimitry Andric if (!CBResult.has_value())
1467fcaf7f86SDimitry Andric continue;
1468bdd1243dSDimitry Andric Value *V = *CBResult;
1469fcaf7f86SDimitry Andric if (!V)
1470fcaf7f86SDimitry Andric return false;
1471fcaf7f86SDimitry Andric if ((S & AA::ValueScope::Interprocedural) ||
1472fcaf7f86SDimitry Andric AA::isValidInScope(*V, IRP.getAnchorScope()))
1473fcaf7f86SDimitry Andric Values.push_back(AA::ValueAndContext{*V, nullptr});
1474fcaf7f86SDimitry Andric else
1475fcaf7f86SDimitry Andric return false;
1476fcaf7f86SDimitry Andric }
147706c3fb27SDimitry Andric if (SimplificationCBs.empty()) {
147806c3fb27SDimitry Andric // If no high-level/outside simplification occurred, use
147906c3fb27SDimitry Andric // AAPotentialValues.
148006c3fb27SDimitry Andric const auto *PotentialValuesAA =
1481fcaf7f86SDimitry Andric getOrCreateAAFor<AAPotentialValues>(IRP, AA, DepClassTy::OPTIONAL);
148206c3fb27SDimitry Andric if (PotentialValuesAA && PotentialValuesAA->getAssumedSimplifiedValues(*this, Values, S)) {
148306c3fb27SDimitry Andric UsedAssumedInformation |= !PotentialValuesAA->isAtFixpoint();
148406c3fb27SDimitry Andric } else if (IRP.getPositionKind() != IRPosition::IRP_RETURNED) {
148506c3fb27SDimitry Andric Values.push_back({IRP.getAssociatedValue(), IRP.getCtxI()});
148606c3fb27SDimitry Andric } else {
148706c3fb27SDimitry Andric // TODO: We could visit all returns and add the operands.
1488fcaf7f86SDimitry Andric return false;
148906c3fb27SDimitry Andric }
149006c3fb27SDimitry Andric }
149106c3fb27SDimitry Andric
149206c3fb27SDimitry Andric if (!RecurseForSelectAndPHI)
149306c3fb27SDimitry Andric break;
149406c3fb27SDimitry Andric
149506c3fb27SDimitry Andric for (int I = NV, E = Values.size(); I < E; ++I) {
149606c3fb27SDimitry Andric Value *V = Values[I].getValue();
149706c3fb27SDimitry Andric if (!isa<PHINode>(V) && !isa<SelectInst>(V))
149806c3fb27SDimitry Andric continue;
149906c3fb27SDimitry Andric if (!Seen.insert(V).second)
150006c3fb27SDimitry Andric continue;
150106c3fb27SDimitry Andric // Move the last element to this slot.
150206c3fb27SDimitry Andric Values[I] = Values[E - 1];
150306c3fb27SDimitry Andric // Eliminate the last slot, adjust the indices.
150406c3fb27SDimitry Andric Values.pop_back();
150506c3fb27SDimitry Andric --E;
150606c3fb27SDimitry Andric --I;
150706c3fb27SDimitry Andric // Add a new value (select or phi) to the worklist.
150806c3fb27SDimitry Andric Worklist.push_back(IRPosition::value(*V));
150906c3fb27SDimitry Andric }
151006c3fb27SDimitry Andric }
1511fcaf7f86SDimitry Andric return true;
1512fe6060f1SDimitry Andric }
1513fe6060f1SDimitry Andric
translateArgumentToCallSiteContent(std::optional<Value * > V,CallBase & CB,const AbstractAttribute & AA,bool & UsedAssumedInformation)1514bdd1243dSDimitry Andric std::optional<Value *> Attributor::translateArgumentToCallSiteContent(
1515bdd1243dSDimitry Andric std::optional<Value *> V, CallBase &CB, const AbstractAttribute &AA,
1516fe6060f1SDimitry Andric bool &UsedAssumedInformation) {
151781ad6265SDimitry Andric if (!V)
1518fe6060f1SDimitry Andric return V;
1519fe6060f1SDimitry Andric if (*V == nullptr || isa<Constant>(*V))
1520fe6060f1SDimitry Andric return V;
1521fe6060f1SDimitry Andric if (auto *Arg = dyn_cast<Argument>(*V))
152206c3fb27SDimitry Andric if (CB.getCalledOperand() == Arg->getParent() &&
152306c3fb27SDimitry Andric CB.arg_size() > Arg->getArgNo())
1524fe6060f1SDimitry Andric if (!Arg->hasPointeeInMemoryValueAttr())
1525fe6060f1SDimitry Andric return getAssumedSimplified(
1526fe6060f1SDimitry Andric IRPosition::callsite_argument(CB, Arg->getArgNo()), AA,
1527fcaf7f86SDimitry Andric UsedAssumedInformation, AA::Intraprocedural);
1528fe6060f1SDimitry Andric return nullptr;
1529fe6060f1SDimitry Andric }
1530fe6060f1SDimitry Andric
~Attributor()15315ffd83dbSDimitry Andric Attributor::~Attributor() {
15325ffd83dbSDimitry Andric // The abstract attributes are allocated via the BumpPtrAllocator Allocator,
15335ffd83dbSDimitry Andric // thus we cannot delete them. We can, and want to, destruct them though.
1534bdd1243dSDimitry Andric for (auto &It : AAMap) {
1535bdd1243dSDimitry Andric AbstractAttribute *AA = It.getSecond();
15365ffd83dbSDimitry Andric AA->~AbstractAttribute();
1537480093f4SDimitry Andric }
1538e8d8bef9SDimitry Andric }
1539480093f4SDimitry Andric
isAssumedDead(const AbstractAttribute & AA,const AAIsDead * FnLivenessAA,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,DepClassTy DepClass)15408bcb0991SDimitry Andric bool Attributor::isAssumedDead(const AbstractAttribute &AA,
15415ffd83dbSDimitry Andric const AAIsDead *FnLivenessAA,
1542fe6060f1SDimitry Andric bool &UsedAssumedInformation,
15435ffd83dbSDimitry Andric bool CheckBBLivenessOnly, DepClassTy DepClass) {
154406c3fb27SDimitry Andric if (!Configuration.UseLiveness)
154506c3fb27SDimitry Andric return false;
15465ffd83dbSDimitry Andric const IRPosition &IRP = AA.getIRPosition();
15475ffd83dbSDimitry Andric if (!Functions.count(IRP.getAnchorScope()))
15488bcb0991SDimitry Andric return false;
1549fe6060f1SDimitry Andric return isAssumedDead(IRP, &AA, FnLivenessAA, UsedAssumedInformation,
1550fe6060f1SDimitry Andric CheckBBLivenessOnly, DepClass);
15515ffd83dbSDimitry Andric }
15528bcb0991SDimitry Andric
isAssumedDead(const Use & U,const AbstractAttribute * QueryingAA,const AAIsDead * FnLivenessAA,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,DepClassTy DepClass)15535ffd83dbSDimitry Andric bool Attributor::isAssumedDead(const Use &U,
15545ffd83dbSDimitry Andric const AbstractAttribute *QueryingAA,
15555ffd83dbSDimitry Andric const AAIsDead *FnLivenessAA,
1556fe6060f1SDimitry Andric bool &UsedAssumedInformation,
15575ffd83dbSDimitry Andric bool CheckBBLivenessOnly, DepClassTy DepClass) {
155806c3fb27SDimitry Andric if (!Configuration.UseLiveness)
155906c3fb27SDimitry Andric return false;
15605ffd83dbSDimitry Andric Instruction *UserI = dyn_cast<Instruction>(U.getUser());
15615ffd83dbSDimitry Andric if (!UserI)
15625ffd83dbSDimitry Andric return isAssumedDead(IRPosition::value(*U.get()), QueryingAA, FnLivenessAA,
1563fe6060f1SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly, DepClass);
15645ffd83dbSDimitry Andric
15655ffd83dbSDimitry Andric if (auto *CB = dyn_cast<CallBase>(UserI)) {
15665ffd83dbSDimitry Andric // For call site argument uses we can check if the argument is
15675ffd83dbSDimitry Andric // unused/dead.
15685ffd83dbSDimitry Andric if (CB->isArgOperand(&U)) {
15695ffd83dbSDimitry Andric const IRPosition &CSArgPos =
15705ffd83dbSDimitry Andric IRPosition::callsite_argument(*CB, CB->getArgOperandNo(&U));
15715ffd83dbSDimitry Andric return isAssumedDead(CSArgPos, QueryingAA, FnLivenessAA,
1572fe6060f1SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly,
1573fe6060f1SDimitry Andric DepClass);
15745ffd83dbSDimitry Andric }
15755ffd83dbSDimitry Andric } else if (ReturnInst *RI = dyn_cast<ReturnInst>(UserI)) {
15765ffd83dbSDimitry Andric const IRPosition &RetPos = IRPosition::returned(*RI->getFunction());
1577fe6060f1SDimitry Andric return isAssumedDead(RetPos, QueryingAA, FnLivenessAA,
1578fe6060f1SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly, DepClass);
15795ffd83dbSDimitry Andric } else if (PHINode *PHI = dyn_cast<PHINode>(UserI)) {
15805ffd83dbSDimitry Andric BasicBlock *IncomingBB = PHI->getIncomingBlock(U);
15815ffd83dbSDimitry Andric return isAssumedDead(*IncomingBB->getTerminator(), QueryingAA, FnLivenessAA,
1582fe6060f1SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly, DepClass);
158381ad6265SDimitry Andric } else if (StoreInst *SI = dyn_cast<StoreInst>(UserI)) {
158481ad6265SDimitry Andric if (!CheckBBLivenessOnly && SI->getPointerOperand() != U.get()) {
158581ad6265SDimitry Andric const IRPosition IRP = IRPosition::inst(*SI);
158606c3fb27SDimitry Andric const AAIsDead *IsDeadAA =
158781ad6265SDimitry Andric getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE);
158806c3fb27SDimitry Andric if (IsDeadAA && IsDeadAA->isRemovableStore()) {
158981ad6265SDimitry Andric if (QueryingAA)
159006c3fb27SDimitry Andric recordDependence(*IsDeadAA, *QueryingAA, DepClass);
159106c3fb27SDimitry Andric if (!IsDeadAA->isKnown(AAIsDead::IS_REMOVABLE))
159281ad6265SDimitry Andric UsedAssumedInformation = true;
159381ad6265SDimitry Andric return true;
159481ad6265SDimitry Andric }
159581ad6265SDimitry Andric }
15965ffd83dbSDimitry Andric }
15975ffd83dbSDimitry Andric
15981fd87a68SDimitry Andric return isAssumedDead(IRPosition::inst(*UserI), QueryingAA, FnLivenessAA,
1599fe6060f1SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly, DepClass);
16005ffd83dbSDimitry Andric }
16015ffd83dbSDimitry Andric
isAssumedDead(const Instruction & I,const AbstractAttribute * QueryingAA,const AAIsDead * FnLivenessAA,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,DepClassTy DepClass,bool CheckForDeadStore)16025ffd83dbSDimitry Andric bool Attributor::isAssumedDead(const Instruction &I,
16035ffd83dbSDimitry Andric const AbstractAttribute *QueryingAA,
16045ffd83dbSDimitry Andric const AAIsDead *FnLivenessAA,
1605fe6060f1SDimitry Andric bool &UsedAssumedInformation,
1606bdd1243dSDimitry Andric bool CheckBBLivenessOnly, DepClassTy DepClass,
1607bdd1243dSDimitry Andric bool CheckForDeadStore) {
160806c3fb27SDimitry Andric if (!Configuration.UseLiveness)
160906c3fb27SDimitry Andric return false;
1610fe6060f1SDimitry Andric const IRPosition::CallBaseContext *CBCtx =
1611fe6060f1SDimitry Andric QueryingAA ? QueryingAA->getCallBaseContext() : nullptr;
1612fe6060f1SDimitry Andric
1613fe6060f1SDimitry Andric if (ManifestAddedBlocks.contains(I.getParent()))
1614fe6060f1SDimitry Andric return false;
1615fe6060f1SDimitry Andric
1616bdd1243dSDimitry Andric const Function &F = *I.getFunction();
1617bdd1243dSDimitry Andric if (!FnLivenessAA || FnLivenessAA->getAnchorScope() != &F)
161806c3fb27SDimitry Andric FnLivenessAA = getOrCreateAAFor<AAIsDead>(IRPosition::function(F, CBCtx),
1619fe6060f1SDimitry Andric QueryingAA, DepClassTy::NONE);
16208bcb0991SDimitry Andric
1621bdd1243dSDimitry Andric // Don't use recursive reasoning.
162206c3fb27SDimitry Andric if (!FnLivenessAA || QueryingAA == FnLivenessAA)
1623bdd1243dSDimitry Andric return false;
1624bdd1243dSDimitry Andric
16255ffd83dbSDimitry Andric // If we have a context instruction and a liveness AA we use it.
1626bdd1243dSDimitry Andric if (CheckBBLivenessOnly ? FnLivenessAA->isAssumedDead(I.getParent())
1627bdd1243dSDimitry Andric : FnLivenessAA->isAssumedDead(&I)) {
16285ffd83dbSDimitry Andric if (QueryingAA)
16295ffd83dbSDimitry Andric recordDependence(*FnLivenessAA, *QueryingAA, DepClass);
1630fe6060f1SDimitry Andric if (!FnLivenessAA->isKnownDead(&I))
1631fe6060f1SDimitry Andric UsedAssumedInformation = true;
1632480093f4SDimitry Andric return true;
1633480093f4SDimitry Andric }
1634480093f4SDimitry Andric
16355ffd83dbSDimitry Andric if (CheckBBLivenessOnly)
16365ffd83dbSDimitry Andric return false;
16375ffd83dbSDimitry Andric
16381fd87a68SDimitry Andric const IRPosition IRP = IRPosition::inst(I, CBCtx);
163906c3fb27SDimitry Andric const AAIsDead *IsDeadAA =
16401fd87a68SDimitry Andric getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE);
1641bdd1243dSDimitry Andric
1642bdd1243dSDimitry Andric // Don't use recursive reasoning.
164306c3fb27SDimitry Andric if (!IsDeadAA || QueryingAA == IsDeadAA)
16445ffd83dbSDimitry Andric return false;
16455ffd83dbSDimitry Andric
164606c3fb27SDimitry Andric if (IsDeadAA->isAssumedDead()) {
16475ffd83dbSDimitry Andric if (QueryingAA)
164806c3fb27SDimitry Andric recordDependence(*IsDeadAA, *QueryingAA, DepClass);
164906c3fb27SDimitry Andric if (!IsDeadAA->isKnownDead())
1650fe6060f1SDimitry Andric UsedAssumedInformation = true;
16515ffd83dbSDimitry Andric return true;
16525ffd83dbSDimitry Andric }
16535ffd83dbSDimitry Andric
165406c3fb27SDimitry Andric if (CheckForDeadStore && isa<StoreInst>(I) && IsDeadAA->isRemovableStore()) {
1655bdd1243dSDimitry Andric if (QueryingAA)
165606c3fb27SDimitry Andric recordDependence(*IsDeadAA, *QueryingAA, DepClass);
165706c3fb27SDimitry Andric if (!IsDeadAA->isKnownDead())
1658bdd1243dSDimitry Andric UsedAssumedInformation = true;
1659bdd1243dSDimitry Andric return true;
1660bdd1243dSDimitry Andric }
1661bdd1243dSDimitry Andric
16625ffd83dbSDimitry Andric return false;
16635ffd83dbSDimitry Andric }
16645ffd83dbSDimitry Andric
isAssumedDead(const IRPosition & IRP,const AbstractAttribute * QueryingAA,const AAIsDead * FnLivenessAA,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,DepClassTy DepClass)16655ffd83dbSDimitry Andric bool Attributor::isAssumedDead(const IRPosition &IRP,
16665ffd83dbSDimitry Andric const AbstractAttribute *QueryingAA,
16675ffd83dbSDimitry Andric const AAIsDead *FnLivenessAA,
1668fe6060f1SDimitry Andric bool &UsedAssumedInformation,
16695ffd83dbSDimitry Andric bool CheckBBLivenessOnly, DepClassTy DepClass) {
167006c3fb27SDimitry Andric if (!Configuration.UseLiveness)
167106c3fb27SDimitry Andric return false;
1672bdd1243dSDimitry Andric // Don't check liveness for constants, e.g. functions, used as (floating)
1673bdd1243dSDimitry Andric // values since the context instruction and such is here meaningless.
1674bdd1243dSDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_FLOAT &&
1675bdd1243dSDimitry Andric isa<Constant>(IRP.getAssociatedValue())) {
1676bdd1243dSDimitry Andric return false;
1677bdd1243dSDimitry Andric }
1678bdd1243dSDimitry Andric
16795ffd83dbSDimitry Andric Instruction *CtxI = IRP.getCtxI();
16805ffd83dbSDimitry Andric if (CtxI &&
1681fe6060f1SDimitry Andric isAssumedDead(*CtxI, QueryingAA, FnLivenessAA, UsedAssumedInformation,
16825ffd83dbSDimitry Andric /* CheckBBLivenessOnly */ true,
16835ffd83dbSDimitry Andric CheckBBLivenessOnly ? DepClass : DepClassTy::OPTIONAL))
16845ffd83dbSDimitry Andric return true;
16855ffd83dbSDimitry Andric
16865ffd83dbSDimitry Andric if (CheckBBLivenessOnly)
16875ffd83dbSDimitry Andric return false;
16885ffd83dbSDimitry Andric
16895ffd83dbSDimitry Andric // If we haven't succeeded we query the specific liveness info for the IRP.
16905ffd83dbSDimitry Andric const AAIsDead *IsDeadAA;
16915ffd83dbSDimitry Andric if (IRP.getPositionKind() == IRPosition::IRP_CALL_SITE)
169206c3fb27SDimitry Andric IsDeadAA = getOrCreateAAFor<AAIsDead>(
16935ffd83dbSDimitry Andric IRPosition::callsite_returned(cast<CallBase>(IRP.getAssociatedValue())),
1694fe6060f1SDimitry Andric QueryingAA, DepClassTy::NONE);
16955ffd83dbSDimitry Andric else
169606c3fb27SDimitry Andric IsDeadAA = getOrCreateAAFor<AAIsDead>(IRP, QueryingAA, DepClassTy::NONE);
1697bdd1243dSDimitry Andric
1698bdd1243dSDimitry Andric // Don't use recursive reasoning.
169906c3fb27SDimitry Andric if (!IsDeadAA || QueryingAA == IsDeadAA)
17005ffd83dbSDimitry Andric return false;
17015ffd83dbSDimitry Andric
17025ffd83dbSDimitry Andric if (IsDeadAA->isAssumedDead()) {
17035ffd83dbSDimitry Andric if (QueryingAA)
17045ffd83dbSDimitry Andric recordDependence(*IsDeadAA, *QueryingAA, DepClass);
1705fe6060f1SDimitry Andric if (!IsDeadAA->isKnownDead())
1706fe6060f1SDimitry Andric UsedAssumedInformation = true;
1707fe6060f1SDimitry Andric return true;
1708fe6060f1SDimitry Andric }
1709fe6060f1SDimitry Andric
1710fe6060f1SDimitry Andric return false;
1711fe6060f1SDimitry Andric }
1712fe6060f1SDimitry Andric
isAssumedDead(const BasicBlock & BB,const AbstractAttribute * QueryingAA,const AAIsDead * FnLivenessAA,DepClassTy DepClass)1713fe6060f1SDimitry Andric bool Attributor::isAssumedDead(const BasicBlock &BB,
1714fe6060f1SDimitry Andric const AbstractAttribute *QueryingAA,
1715fe6060f1SDimitry Andric const AAIsDead *FnLivenessAA,
1716fe6060f1SDimitry Andric DepClassTy DepClass) {
171706c3fb27SDimitry Andric if (!Configuration.UseLiveness)
171806c3fb27SDimitry Andric return false;
1719bdd1243dSDimitry Andric const Function &F = *BB.getParent();
1720bdd1243dSDimitry Andric if (!FnLivenessAA || FnLivenessAA->getAnchorScope() != &F)
172106c3fb27SDimitry Andric FnLivenessAA = getOrCreateAAFor<AAIsDead>(IRPosition::function(F),
1722fe6060f1SDimitry Andric QueryingAA, DepClassTy::NONE);
1723bdd1243dSDimitry Andric
1724bdd1243dSDimitry Andric // Don't use recursive reasoning.
172506c3fb27SDimitry Andric if (!FnLivenessAA || QueryingAA == FnLivenessAA)
1726bdd1243dSDimitry Andric return false;
1727bdd1243dSDimitry Andric
1728fe6060f1SDimitry Andric if (FnLivenessAA->isAssumedDead(&BB)) {
1729fe6060f1SDimitry Andric if (QueryingAA)
1730fe6060f1SDimitry Andric recordDependence(*FnLivenessAA, *QueryingAA, DepClass);
17315ffd83dbSDimitry Andric return true;
17325ffd83dbSDimitry Andric }
17335ffd83dbSDimitry Andric
17345ffd83dbSDimitry Andric return false;
17355ffd83dbSDimitry Andric }
17365ffd83dbSDimitry Andric
checkForAllCallees(function_ref<bool (ArrayRef<const Function * >)> Pred,const AbstractAttribute & QueryingAA,const CallBase & CB)17375f757f3fSDimitry Andric bool Attributor::checkForAllCallees(
17385f757f3fSDimitry Andric function_ref<bool(ArrayRef<const Function *>)> Pred,
17395f757f3fSDimitry Andric const AbstractAttribute &QueryingAA, const CallBase &CB) {
17405f757f3fSDimitry Andric if (const Function *Callee = dyn_cast<Function>(CB.getCalledOperand()))
17415f757f3fSDimitry Andric return Pred(Callee);
17425f757f3fSDimitry Andric
17435f757f3fSDimitry Andric const auto *CallEdgesAA = getAAFor<AACallEdges>(
17445f757f3fSDimitry Andric QueryingAA, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL);
17455f757f3fSDimitry Andric if (!CallEdgesAA || CallEdgesAA->hasUnknownCallee())
17465f757f3fSDimitry Andric return false;
17475f757f3fSDimitry Andric
17485f757f3fSDimitry Andric const auto &Callees = CallEdgesAA->getOptimisticEdges();
17495f757f3fSDimitry Andric return Pred(Callees.getArrayRef());
17505f757f3fSDimitry Andric }
17515f757f3fSDimitry Andric
canMarkAsVisited(const User * Usr)1752*0fca6ea1SDimitry Andric bool canMarkAsVisited(const User *Usr) {
1753*0fca6ea1SDimitry Andric return isa<PHINode>(Usr) || !isa<Instruction>(Usr);
1754*0fca6ea1SDimitry Andric }
1755*0fca6ea1SDimitry Andric
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)175604eeddc0SDimitry Andric bool Attributor::checkForAllUses(
175704eeddc0SDimitry Andric function_ref<bool(const Use &, bool &)> Pred,
175804eeddc0SDimitry Andric const AbstractAttribute &QueryingAA, const Value &V,
175904eeddc0SDimitry Andric bool CheckBBLivenessOnly, DepClassTy LivenessDepClass,
176081ad6265SDimitry Andric bool IgnoreDroppableUses,
176104eeddc0SDimitry Andric function_ref<bool(const Use &OldU, const Use &NewU)> EquivalentUseCB) {
17625ffd83dbSDimitry Andric
1763bdd1243dSDimitry Andric // Check virtual uses first.
1764bdd1243dSDimitry Andric for (VirtualUseCallbackTy &CB : VirtualUseCallbacks.lookup(&V))
1765bdd1243dSDimitry Andric if (!CB(*this, &QueryingAA))
1766bdd1243dSDimitry Andric return false;
1767bdd1243dSDimitry Andric
17685ffd83dbSDimitry Andric // Check the trivial case first as it catches void values.
17695ffd83dbSDimitry Andric if (V.use_empty())
17705ffd83dbSDimitry Andric return true;
17715ffd83dbSDimitry Andric
1772480093f4SDimitry Andric const IRPosition &IRP = QueryingAA.getIRPosition();
1773480093f4SDimitry Andric SmallVector<const Use *, 16> Worklist;
1774480093f4SDimitry Andric SmallPtrSet<const Use *, 16> Visited;
1775480093f4SDimitry Andric
1776fcaf7f86SDimitry Andric auto AddUsers = [&](const Value &V, const Use *OldUse) {
1777fcaf7f86SDimitry Andric for (const Use &UU : V.uses()) {
1778fcaf7f86SDimitry Andric if (OldUse && EquivalentUseCB && !EquivalentUseCB(*OldUse, UU)) {
1779fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Potential copy was "
1780fcaf7f86SDimitry Andric "rejected by the equivalence call back: "
1781fcaf7f86SDimitry Andric << *UU << "!\n");
1782fcaf7f86SDimitry Andric return false;
1783fcaf7f86SDimitry Andric }
1784fcaf7f86SDimitry Andric
1785fcaf7f86SDimitry Andric Worklist.push_back(&UU);
1786fcaf7f86SDimitry Andric }
1787fcaf7f86SDimitry Andric return true;
1788fcaf7f86SDimitry Andric };
1789fcaf7f86SDimitry Andric
1790fcaf7f86SDimitry Andric AddUsers(V, /* OldUse */ nullptr);
1791480093f4SDimitry Andric
1792480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Got " << Worklist.size()
1793480093f4SDimitry Andric << " initial uses to check\n");
1794480093f4SDimitry Andric
1795480093f4SDimitry Andric const Function *ScopeFn = IRP.getAnchorScope();
1796480093f4SDimitry Andric const auto *LivenessAA =
179706c3fb27SDimitry Andric ScopeFn ? getAAFor<AAIsDead>(QueryingAA, IRPosition::function(*ScopeFn),
1798fe6060f1SDimitry Andric DepClassTy::NONE)
1799480093f4SDimitry Andric : nullptr;
1800480093f4SDimitry Andric
1801480093f4SDimitry Andric while (!Worklist.empty()) {
1802480093f4SDimitry Andric const Use *U = Worklist.pop_back_val();
1803*0fca6ea1SDimitry Andric if (canMarkAsVisited(U->getUser()) && !Visited.insert(U).second)
1804480093f4SDimitry Andric continue;
1805bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, {
18061fd87a68SDimitry Andric if (auto *Fn = dyn_cast<Function>(U->getUser()))
18071fd87a68SDimitry Andric dbgs() << "[Attributor] Check use: " << **U << " in " << Fn->getName()
18081fd87a68SDimitry Andric << "\n";
18091fd87a68SDimitry Andric else
18101fd87a68SDimitry Andric dbgs() << "[Attributor] Check use: " << **U << " in " << *U->getUser()
18111fd87a68SDimitry Andric << "\n";
18121fd87a68SDimitry Andric });
1813fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
1814fe6060f1SDimitry Andric if (isAssumedDead(*U, &QueryingAA, LivenessAA, UsedAssumedInformation,
1815fe6060f1SDimitry Andric CheckBBLivenessOnly, LivenessDepClass)) {
1816bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
1817bdd1243dSDimitry Andric dbgs() << "[Attributor] Dead use, skip!\n");
18185ffd83dbSDimitry Andric continue;
18195ffd83dbSDimitry Andric }
182081ad6265SDimitry Andric if (IgnoreDroppableUses && U->getUser()->isDroppable()) {
1821bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
1822bdd1243dSDimitry Andric dbgs() << "[Attributor] Droppable user, skip!\n");
1823480093f4SDimitry Andric continue;
1824480093f4SDimitry Andric }
1825480093f4SDimitry Andric
1826fe6060f1SDimitry Andric if (auto *SI = dyn_cast<StoreInst>(U->getUser())) {
1827fe6060f1SDimitry Andric if (&SI->getOperandUse(0) == U) {
1828349cc55cSDimitry Andric if (!Visited.insert(U).second)
1829349cc55cSDimitry Andric continue;
1830fe6060f1SDimitry Andric SmallSetVector<Value *, 4> PotentialCopies;
183181ad6265SDimitry Andric if (AA::getPotentialCopiesOfStoredValue(
183281ad6265SDimitry Andric *this, *SI, PotentialCopies, QueryingAA, UsedAssumedInformation,
183381ad6265SDimitry Andric /* OnlyExact */ true)) {
1834bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
1835bdd1243dSDimitry Andric dbgs()
1836bdd1243dSDimitry Andric << "[Attributor] Value is stored, continue with "
1837fe6060f1SDimitry Andric << PotentialCopies.size()
1838fe6060f1SDimitry Andric << " potential copies instead!\n");
1839fe6060f1SDimitry Andric for (Value *PotentialCopy : PotentialCopies)
1840fcaf7f86SDimitry Andric if (!AddUsers(*PotentialCopy, U))
184104eeddc0SDimitry Andric return false;
1842fe6060f1SDimitry Andric continue;
1843fe6060f1SDimitry Andric }
1844fe6060f1SDimitry Andric }
1845fe6060f1SDimitry Andric }
1846fe6060f1SDimitry Andric
1847480093f4SDimitry Andric bool Follow = false;
1848480093f4SDimitry Andric if (!Pred(*U, Follow))
1849480093f4SDimitry Andric return false;
1850480093f4SDimitry Andric if (!Follow)
1851480093f4SDimitry Andric continue;
1852fcaf7f86SDimitry Andric
1853fcaf7f86SDimitry Andric User &Usr = *U->getUser();
1854fcaf7f86SDimitry Andric AddUsers(Usr, /* OldUse */ nullptr);
1855fcaf7f86SDimitry Andric
1856fcaf7f86SDimitry Andric auto *RI = dyn_cast<ReturnInst>(&Usr);
1857fcaf7f86SDimitry Andric if (!RI)
1858fcaf7f86SDimitry Andric continue;
1859fcaf7f86SDimitry Andric
1860fcaf7f86SDimitry Andric Function &F = *RI->getFunction();
1861fcaf7f86SDimitry Andric auto CallSitePred = [&](AbstractCallSite ACS) {
1862fcaf7f86SDimitry Andric return AddUsers(*ACS.getInstruction(), U);
1863fcaf7f86SDimitry Andric };
1864fcaf7f86SDimitry Andric if (!checkForAllCallSites(CallSitePred, F, /* RequireAllCallSites */ true,
1865fcaf7f86SDimitry Andric &QueryingAA, UsedAssumedInformation)) {
1866fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Could not follow return instruction "
1867fcaf7f86SDimitry Andric "to all call sites: "
1868fcaf7f86SDimitry Andric << *RI << "\n");
1869fcaf7f86SDimitry Andric return false;
1870fcaf7f86SDimitry Andric }
1871480093f4SDimitry Andric }
1872480093f4SDimitry Andric
18738bcb0991SDimitry Andric return true;
18748bcb0991SDimitry Andric }
18758bcb0991SDimitry Andric
checkForAllCallSites(function_ref<bool (AbstractCallSite)> Pred,const AbstractAttribute & QueryingAA,bool RequireAllCallSites,bool & UsedAssumedInformation)18765ffd83dbSDimitry Andric bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
18775ffd83dbSDimitry Andric const AbstractAttribute &QueryingAA,
18785ffd83dbSDimitry Andric bool RequireAllCallSites,
1879d781ede6SDimitry Andric bool &UsedAssumedInformation) {
18800b57cec5SDimitry Andric // We can try to determine information from
18810b57cec5SDimitry Andric // the call sites. However, this is only possible all call sites are known,
18820b57cec5SDimitry Andric // hence the function has internal linkage.
18838bcb0991SDimitry Andric const IRPosition &IRP = QueryingAA.getIRPosition();
18848bcb0991SDimitry Andric const Function *AssociatedFunction = IRP.getAssociatedFunction();
18858bcb0991SDimitry Andric if (!AssociatedFunction) {
18868bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] No function associated with " << IRP
18878bcb0991SDimitry Andric << "\n");
18888bcb0991SDimitry Andric return false;
18898bcb0991SDimitry Andric }
18908bcb0991SDimitry Andric
18918bcb0991SDimitry Andric return checkForAllCallSites(Pred, *AssociatedFunction, RequireAllCallSites,
1892d781ede6SDimitry Andric &QueryingAA, UsedAssumedInformation);
18938bcb0991SDimitry Andric }
18948bcb0991SDimitry Andric
checkForAllCallSites(function_ref<bool (AbstractCallSite)> Pred,const Function & Fn,bool RequireAllCallSites,const AbstractAttribute * QueryingAA,bool & UsedAssumedInformation,bool CheckPotentiallyDead)18955ffd83dbSDimitry Andric bool Attributor::checkForAllCallSites(function_ref<bool(AbstractCallSite)> Pred,
18965ffd83dbSDimitry Andric const Function &Fn,
18975ffd83dbSDimitry Andric bool RequireAllCallSites,
18985ffd83dbSDimitry Andric const AbstractAttribute *QueryingAA,
1899bdd1243dSDimitry Andric bool &UsedAssumedInformation,
1900bdd1243dSDimitry Andric bool CheckPotentiallyDead) {
19018bcb0991SDimitry Andric if (RequireAllCallSites && !Fn.hasLocalLinkage()) {
19020b57cec5SDimitry Andric LLVM_DEBUG(
19030b57cec5SDimitry Andric dbgs()
19048bcb0991SDimitry Andric << "[Attributor] Function " << Fn.getName()
19050b57cec5SDimitry Andric << " has no internal linkage, hence not all call sites are known\n");
19060b57cec5SDimitry Andric return false;
19070b57cec5SDimitry Andric }
1908bdd1243dSDimitry Andric // Check virtual uses first.
1909bdd1243dSDimitry Andric for (VirtualUseCallbackTy &CB : VirtualUseCallbacks.lookup(&Fn))
1910bdd1243dSDimitry Andric if (!CB(*this, QueryingAA))
1911bdd1243dSDimitry Andric return false;
19120b57cec5SDimitry Andric
19135ffd83dbSDimitry Andric SmallVector<const Use *, 8> Uses(make_pointer_range(Fn.uses()));
19145ffd83dbSDimitry Andric for (unsigned u = 0; u < Uses.size(); ++u) {
19155ffd83dbSDimitry Andric const Use &U = *Uses[u];
1916bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, {
19171fd87a68SDimitry Andric if (auto *Fn = dyn_cast<Function>(U))
19181fd87a68SDimitry Andric dbgs() << "[Attributor] Check use: " << Fn->getName() << " in "
19191fd87a68SDimitry Andric << *U.getUser() << "\n";
19201fd87a68SDimitry Andric else
19211fd87a68SDimitry Andric dbgs() << "[Attributor] Check use: " << *U << " in " << *U.getUser()
19221fd87a68SDimitry Andric << "\n";
19231fd87a68SDimitry Andric });
1924bdd1243dSDimitry Andric if (!CheckPotentiallyDead &&
1925bdd1243dSDimitry Andric isAssumedDead(U, QueryingAA, nullptr, UsedAssumedInformation,
1926fe6060f1SDimitry Andric /* CheckBBLivenessOnly */ true)) {
1927bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
1928bdd1243dSDimitry Andric dbgs() << "[Attributor] Dead use, skip!\n");
19295ffd83dbSDimitry Andric continue;
19305ffd83dbSDimitry Andric }
19315ffd83dbSDimitry Andric if (ConstantExpr *CE = dyn_cast<ConstantExpr>(U.getUser())) {
193281ad6265SDimitry Andric if (CE->isCast() && CE->getType()->isPointerTy()) {
1933bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, {
1934349cc55cSDimitry Andric dbgs() << "[Attributor] Use, is constant cast expression, add "
1935bdd1243dSDimitry Andric << CE->getNumUses() << " uses of that expression instead!\n";
1936bdd1243dSDimitry Andric });
19375ffd83dbSDimitry Andric for (const Use &CEU : CE->uses())
19385ffd83dbSDimitry Andric Uses.push_back(&CEU);
19395ffd83dbSDimitry Andric continue;
19405ffd83dbSDimitry Andric }
19415ffd83dbSDimitry Andric }
19425ffd83dbSDimitry Andric
19438bcb0991SDimitry Andric AbstractCallSite ACS(&U);
19448bcb0991SDimitry Andric if (!ACS) {
1945480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Function " << Fn.getName()
19468bcb0991SDimitry Andric << " has non call site use " << *U.get() << " in "
19478bcb0991SDimitry Andric << *U.getUser() << "\n");
1948480093f4SDimitry Andric // BlockAddress users are allowed.
1949480093f4SDimitry Andric if (isa<BlockAddress>(U.getUser()))
1950480093f4SDimitry Andric continue;
19510b57cec5SDimitry Andric return false;
19520b57cec5SDimitry Andric }
19530b57cec5SDimitry Andric
19548bcb0991SDimitry Andric const Use *EffectiveUse =
19558bcb0991SDimitry Andric ACS.isCallbackCall() ? &ACS.getCalleeUseForCallback() : &U;
19568bcb0991SDimitry Andric if (!ACS.isCallee(EffectiveUse)) {
1957349cc55cSDimitry Andric if (!RequireAllCallSites) {
1958349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] User " << *EffectiveUse->getUser()
1959349cc55cSDimitry Andric << " is not a call of " << Fn.getName()
1960349cc55cSDimitry Andric << ", skip use\n");
19618bcb0991SDimitry Andric continue;
1962349cc55cSDimitry Andric }
1963349cc55cSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] User " << *EffectiveUse->getUser()
1964480093f4SDimitry Andric << " is an invalid use of " << Fn.getName() << "\n");
19658bcb0991SDimitry Andric return false;
19668bcb0991SDimitry Andric }
19678bcb0991SDimitry Andric
19685ffd83dbSDimitry Andric // Make sure the arguments that can be matched between the call site and the
19695ffd83dbSDimitry Andric // callee argee on their type. It is unlikely they do not and it doesn't
19705ffd83dbSDimitry Andric // make sense for all attributes to know/care about this.
19715ffd83dbSDimitry Andric assert(&Fn == ACS.getCalledFunction() && "Expected known callee");
19725ffd83dbSDimitry Andric unsigned MinArgsParams =
19735ffd83dbSDimitry Andric std::min(size_t(ACS.getNumArgOperands()), Fn.arg_size());
19745ffd83dbSDimitry Andric for (unsigned u = 0; u < MinArgsParams; ++u) {
19755ffd83dbSDimitry Andric Value *CSArgOp = ACS.getCallArgOperand(u);
19765ffd83dbSDimitry Andric if (CSArgOp && Fn.getArg(u)->getType() != CSArgOp->getType()) {
19775ffd83dbSDimitry Andric LLVM_DEBUG(
19785ffd83dbSDimitry Andric dbgs() << "[Attributor] Call site / callee argument type mismatch ["
19795ffd83dbSDimitry Andric << u << "@" << Fn.getName() << ": "
19805ffd83dbSDimitry Andric << *Fn.getArg(u)->getType() << " vs. "
19815ffd83dbSDimitry Andric << *ACS.getCallArgOperand(u)->getType() << "\n");
19825ffd83dbSDimitry Andric return false;
19835ffd83dbSDimitry Andric }
19845ffd83dbSDimitry Andric }
19855ffd83dbSDimitry Andric
19868bcb0991SDimitry Andric if (Pred(ACS))
19870b57cec5SDimitry Andric continue;
19880b57cec5SDimitry Andric
19898bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Call site callback failed for "
19908bcb0991SDimitry Andric << *ACS.getInstruction() << "\n");
19910b57cec5SDimitry Andric return false;
19920b57cec5SDimitry Andric }
19930b57cec5SDimitry Andric
19940b57cec5SDimitry Andric return true;
19950b57cec5SDimitry Andric }
19960b57cec5SDimitry Andric
shouldPropagateCallBaseContext(const IRPosition & IRP)1997fe6060f1SDimitry Andric bool Attributor::shouldPropagateCallBaseContext(const IRPosition &IRP) {
1998fe6060f1SDimitry Andric // TODO: Maintain a cache of Values that are
1999fe6060f1SDimitry Andric // on the pathway from a Argument to a Instruction that would effect the
2000fe6060f1SDimitry Andric // liveness/return state etc.
2001fe6060f1SDimitry Andric return EnableCallSiteSpecific;
2002fe6060f1SDimitry Andric }
2003fe6060f1SDimitry Andric
checkForAllReturnedValues(function_ref<bool (Value &)> Pred,const AbstractAttribute & QueryingAA,AA::ValueScope S,bool RecurseForSelectAndPHI)200406c3fb27SDimitry Andric bool Attributor::checkForAllReturnedValues(function_ref<bool(Value &)> Pred,
200506c3fb27SDimitry Andric const AbstractAttribute &QueryingAA,
200606c3fb27SDimitry Andric AA::ValueScope S,
200706c3fb27SDimitry Andric bool RecurseForSelectAndPHI) {
20088bcb0991SDimitry Andric
20098bcb0991SDimitry Andric const IRPosition &IRP = QueryingAA.getIRPosition();
20108bcb0991SDimitry Andric const Function *AssociatedFunction = IRP.getAssociatedFunction();
20118bcb0991SDimitry Andric if (!AssociatedFunction)
20128bcb0991SDimitry Andric return false;
20138bcb0991SDimitry Andric
201406c3fb27SDimitry Andric bool UsedAssumedInformation = false;
201506c3fb27SDimitry Andric SmallVector<AA::ValueAndContext> Values;
201606c3fb27SDimitry Andric if (!getAssumedSimplifiedValues(
201706c3fb27SDimitry Andric IRPosition::returned(*AssociatedFunction), &QueryingAA, Values, S,
201806c3fb27SDimitry Andric UsedAssumedInformation, RecurseForSelectAndPHI))
20198bcb0991SDimitry Andric return false;
20208bcb0991SDimitry Andric
202106c3fb27SDimitry Andric return llvm::all_of(Values, [&](const AA::ValueAndContext &VAC) {
202206c3fb27SDimitry Andric return Pred(*VAC.getValue());
20238bcb0991SDimitry Andric });
20248bcb0991SDimitry Andric }
20258bcb0991SDimitry Andric
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)20265ffd83dbSDimitry Andric static bool checkForAllInstructionsImpl(
20275ffd83dbSDimitry Andric Attributor *A, InformationCache::OpcodeInstMapTy &OpcodeInstMap,
20285ffd83dbSDimitry Andric function_ref<bool(Instruction &)> Pred, const AbstractAttribute *QueryingAA,
20295f757f3fSDimitry Andric const AAIsDead *LivenessAA, ArrayRef<unsigned> Opcodes,
2030fe6060f1SDimitry Andric bool &UsedAssumedInformation, bool CheckBBLivenessOnly = false,
2031fe6060f1SDimitry Andric bool CheckPotentiallyDead = false) {
20328bcb0991SDimitry Andric for (unsigned Opcode : Opcodes) {
20335ffd83dbSDimitry Andric // Check if we have instructions with this opcode at all first.
20345ffd83dbSDimitry Andric auto *Insts = OpcodeInstMap.lookup(Opcode);
20355ffd83dbSDimitry Andric if (!Insts)
20368bcb0991SDimitry Andric continue;
20375ffd83dbSDimitry Andric
20385ffd83dbSDimitry Andric for (Instruction *I : *Insts) {
20395ffd83dbSDimitry Andric // Skip dead instructions.
2040fe6060f1SDimitry Andric if (A && !CheckPotentiallyDead &&
20411fd87a68SDimitry Andric A->isAssumedDead(IRPosition::inst(*I), QueryingAA, LivenessAA,
20421fd87a68SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly)) {
2043bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
2044bdd1243dSDimitry Andric dbgs() << "[Attributor] Instruction " << *I
20451fd87a68SDimitry Andric << " is potentially dead, skip!\n";);
20465ffd83dbSDimitry Andric continue;
20471fd87a68SDimitry Andric }
20488bcb0991SDimitry Andric
20498bcb0991SDimitry Andric if (!Pred(*I))
20508bcb0991SDimitry Andric return false;
20518bcb0991SDimitry Andric }
20528bcb0991SDimitry Andric }
20538bcb0991SDimitry Andric return true;
20548bcb0991SDimitry Andric }
20558bcb0991SDimitry Andric
checkForAllInstructions(function_ref<bool (Instruction &)> Pred,const Function * Fn,const AbstractAttribute * QueryingAA,ArrayRef<unsigned> Opcodes,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,bool CheckPotentiallyDead)20565ffd83dbSDimitry Andric bool Attributor::checkForAllInstructions(function_ref<bool(Instruction &)> Pred,
205781ad6265SDimitry Andric const Function *Fn,
20585f757f3fSDimitry Andric const AbstractAttribute *QueryingAA,
20595f757f3fSDimitry Andric ArrayRef<unsigned> Opcodes,
2060fe6060f1SDimitry Andric bool &UsedAssumedInformation,
2061fe6060f1SDimitry Andric bool CheckBBLivenessOnly,
2062fe6060f1SDimitry Andric bool CheckPotentiallyDead) {
20638bcb0991SDimitry Andric // Since we need to provide instructions we have to have an exact definition.
206481ad6265SDimitry Andric if (!Fn || Fn->isDeclaration())
2065fe6060f1SDimitry Andric return false;
2066fe6060f1SDimitry Andric
206781ad6265SDimitry Andric const IRPosition &QueryIRP = IRPosition::function(*Fn);
2068e8d8bef9SDimitry Andric const auto *LivenessAA =
20695f757f3fSDimitry Andric CheckPotentiallyDead && QueryingAA
20705f757f3fSDimitry Andric ? (getAAFor<AAIsDead>(*QueryingAA, QueryIRP, DepClassTy::NONE))
20715f757f3fSDimitry Andric : nullptr;
20728bcb0991SDimitry Andric
207381ad6265SDimitry Andric auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn);
20745f757f3fSDimitry Andric if (!checkForAllInstructionsImpl(this, OpcodeInstMap, Pred, QueryingAA,
2075fe6060f1SDimitry Andric LivenessAA, Opcodes, UsedAssumedInformation,
2076fe6060f1SDimitry Andric CheckBBLivenessOnly, CheckPotentiallyDead))
20778bcb0991SDimitry Andric return false;
20788bcb0991SDimitry Andric
20798bcb0991SDimitry Andric return true;
20808bcb0991SDimitry Andric }
20818bcb0991SDimitry Andric
checkForAllInstructions(function_ref<bool (Instruction &)> Pred,const AbstractAttribute & QueryingAA,ArrayRef<unsigned> Opcodes,bool & UsedAssumedInformation,bool CheckBBLivenessOnly,bool CheckPotentiallyDead)208281ad6265SDimitry Andric bool Attributor::checkForAllInstructions(function_ref<bool(Instruction &)> Pred,
208381ad6265SDimitry Andric const AbstractAttribute &QueryingAA,
20845f757f3fSDimitry Andric ArrayRef<unsigned> Opcodes,
208581ad6265SDimitry Andric bool &UsedAssumedInformation,
208681ad6265SDimitry Andric bool CheckBBLivenessOnly,
208781ad6265SDimitry Andric bool CheckPotentiallyDead) {
208881ad6265SDimitry Andric const IRPosition &IRP = QueryingAA.getIRPosition();
208981ad6265SDimitry Andric const Function *AssociatedFunction = IRP.getAssociatedFunction();
20905f757f3fSDimitry Andric return checkForAllInstructions(Pred, AssociatedFunction, &QueryingAA, Opcodes,
209181ad6265SDimitry Andric UsedAssumedInformation, CheckBBLivenessOnly,
209281ad6265SDimitry Andric CheckPotentiallyDead);
209381ad6265SDimitry Andric }
209481ad6265SDimitry Andric
checkForAllReadWriteInstructions(function_ref<bool (Instruction &)> Pred,AbstractAttribute & QueryingAA,bool & UsedAssumedInformation)20958bcb0991SDimitry Andric bool Attributor::checkForAllReadWriteInstructions(
2096fe6060f1SDimitry Andric function_ref<bool(Instruction &)> Pred, AbstractAttribute &QueryingAA,
2097fe6060f1SDimitry Andric bool &UsedAssumedInformation) {
209806c3fb27SDimitry Andric TimeTraceScope TS("checkForAllReadWriteInstructions");
20998bcb0991SDimitry Andric
21008bcb0991SDimitry Andric const Function *AssociatedFunction =
21018bcb0991SDimitry Andric QueryingAA.getIRPosition().getAssociatedFunction();
21028bcb0991SDimitry Andric if (!AssociatedFunction)
21038bcb0991SDimitry Andric return false;
21048bcb0991SDimitry Andric
21058bcb0991SDimitry Andric const IRPosition &QueryIRP = IRPosition::function(*AssociatedFunction);
210606c3fb27SDimitry Andric const auto *LivenessAA =
2107fe6060f1SDimitry Andric getAAFor<AAIsDead>(QueryingAA, QueryIRP, DepClassTy::NONE);
21088bcb0991SDimitry Andric
21098bcb0991SDimitry Andric for (Instruction *I :
21108bcb0991SDimitry Andric InfoCache.getReadOrWriteInstsForFunction(*AssociatedFunction)) {
21118bcb0991SDimitry Andric // Skip dead instructions.
211206c3fb27SDimitry Andric if (isAssumedDead(IRPosition::inst(*I), &QueryingAA, LivenessAA,
2113fe6060f1SDimitry Andric UsedAssumedInformation))
21148bcb0991SDimitry Andric continue;
21158bcb0991SDimitry Andric
21168bcb0991SDimitry Andric if (!Pred(*I))
21178bcb0991SDimitry Andric return false;
21188bcb0991SDimitry Andric }
21198bcb0991SDimitry Andric
21208bcb0991SDimitry Andric return true;
21218bcb0991SDimitry Andric }
21228bcb0991SDimitry Andric
runTillFixpoint()21235ffd83dbSDimitry Andric void Attributor::runTillFixpoint() {
2124e8d8bef9SDimitry Andric TimeTraceScope TimeScope("Attributor::runTillFixpoint");
21250b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Identified and initialized "
2126e8d8bef9SDimitry Andric << DG.SyntheticRoot.Deps.size()
21270b57cec5SDimitry Andric << " abstract attributes.\n");
21280b57cec5SDimitry Andric
21290b57cec5SDimitry Andric // Now that all abstract attributes are collected and initialized we start
21300b57cec5SDimitry Andric // the abstract analysis.
21310b57cec5SDimitry Andric
21320b57cec5SDimitry Andric unsigned IterationCounter = 1;
213381ad6265SDimitry Andric unsigned MaxIterations =
213481ad6265SDimitry Andric Configuration.MaxFixpointIterations.value_or(SetFixpointIterations);
21350b57cec5SDimitry Andric
21365ffd83dbSDimitry Andric SmallVector<AbstractAttribute *, 32> ChangedAAs;
2137480093f4SDimitry Andric SetVector<AbstractAttribute *> Worklist, InvalidAAs;
2138e8d8bef9SDimitry Andric Worklist.insert(DG.SyntheticRoot.begin(), DG.SyntheticRoot.end());
21390b57cec5SDimitry Andric
21400b57cec5SDimitry Andric do {
21418bcb0991SDimitry Andric // Remember the size to determine new attributes.
2142e8d8bef9SDimitry Andric size_t NumAAs = DG.SyntheticRoot.Deps.size();
21430b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n\n[Attributor] #Iteration: " << IterationCounter
21440b57cec5SDimitry Andric << ", Worklist size: " << Worklist.size() << "\n");
21450b57cec5SDimitry Andric
2146480093f4SDimitry Andric // For invalid AAs we can fix dependent AAs that have a required dependence,
2147480093f4SDimitry Andric // thereby folding long dependence chains in a single step without the need
2148480093f4SDimitry Andric // to run updates.
2149480093f4SDimitry Andric for (unsigned u = 0; u < InvalidAAs.size(); ++u) {
2150480093f4SDimitry Andric AbstractAttribute *InvalidAA = InvalidAAs[u];
2151480093f4SDimitry Andric
21525ffd83dbSDimitry Andric // Check the dependences to fast track invalidation.
2153bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
2154bdd1243dSDimitry Andric dbgs() << "[Attributor] InvalidAA: " << *InvalidAA
2155bdd1243dSDimitry Andric << " has " << InvalidAA->Deps.size()
21565ffd83dbSDimitry Andric << " required & optional dependences\n");
215706c3fb27SDimitry Andric for (auto &DepIt : InvalidAA->Deps) {
215806c3fb27SDimitry Andric AbstractAttribute *DepAA = cast<AbstractAttribute>(DepIt.getPointer());
215906c3fb27SDimitry Andric if (DepIt.getInt() == unsigned(DepClassTy::OPTIONAL)) {
2160bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE,
2161bdd1243dSDimitry Andric dbgs() << " - recompute: " << *DepAA);
21625ffd83dbSDimitry Andric Worklist.insert(DepAA);
21635ffd83dbSDimitry Andric continue;
21645ffd83dbSDimitry Andric }
2165bdd1243dSDimitry Andric DEBUG_WITH_TYPE(VERBOSE_DEBUG_TYPE, dbgs()
2166bdd1243dSDimitry Andric << " - invalidate: " << *DepAA);
21675ffd83dbSDimitry Andric DepAA->getState().indicatePessimisticFixpoint();
21685ffd83dbSDimitry Andric assert(DepAA->getState().isAtFixpoint() && "Expected fixpoint state!");
21695ffd83dbSDimitry Andric if (!DepAA->getState().isValidState())
21705ffd83dbSDimitry Andric InvalidAAs.insert(DepAA);
21715ffd83dbSDimitry Andric else
21725ffd83dbSDimitry Andric ChangedAAs.push_back(DepAA);
21735ffd83dbSDimitry Andric }
217406c3fb27SDimitry Andric InvalidAA->Deps.clear();
21758bcb0991SDimitry Andric }
21768bcb0991SDimitry Andric
21770b57cec5SDimitry Andric // Add all abstract attributes that are potentially dependent on one that
21780b57cec5SDimitry Andric // changed to the work list.
217906c3fb27SDimitry Andric for (AbstractAttribute *ChangedAA : ChangedAAs) {
218006c3fb27SDimitry Andric for (auto &DepIt : ChangedAA->Deps)
218106c3fb27SDimitry Andric Worklist.insert(cast<AbstractAttribute>(DepIt.getPointer()));
218206c3fb27SDimitry Andric ChangedAA->Deps.clear();
21830b57cec5SDimitry Andric }
21840b57cec5SDimitry Andric
21858bcb0991SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] #Iteration: " << IterationCounter
21868bcb0991SDimitry Andric << ", Worklist+Dependent size: " << Worklist.size()
21878bcb0991SDimitry Andric << "\n");
21888bcb0991SDimitry Andric
2189480093f4SDimitry Andric // Reset the changed and invalid set.
21900b57cec5SDimitry Andric ChangedAAs.clear();
2191480093f4SDimitry Andric InvalidAAs.clear();
21920b57cec5SDimitry Andric
21930b57cec5SDimitry Andric // Update all abstract attribute in the work list and record the ones that
21940b57cec5SDimitry Andric // changed.
21955ffd83dbSDimitry Andric for (AbstractAttribute *AA : Worklist) {
21965ffd83dbSDimitry Andric const auto &AAState = AA->getState();
21975ffd83dbSDimitry Andric if (!AAState.isAtFixpoint())
21985ffd83dbSDimitry Andric if (updateAA(*AA) == ChangeStatus::CHANGED)
21990b57cec5SDimitry Andric ChangedAAs.push_back(AA);
22000b57cec5SDimitry Andric
22015ffd83dbSDimitry Andric // Use the InvalidAAs vector to propagate invalid states fast transitively
22025ffd83dbSDimitry Andric // without requiring updates.
22035ffd83dbSDimitry Andric if (!AAState.isValidState())
22045ffd83dbSDimitry Andric InvalidAAs.insert(AA);
22055ffd83dbSDimitry Andric }
22068bcb0991SDimitry Andric
22078bcb0991SDimitry Andric // Add attributes to the changed set if they have been created in the last
22088bcb0991SDimitry Andric // iteration.
2209e8d8bef9SDimitry Andric ChangedAAs.append(DG.SyntheticRoot.begin() + NumAAs,
2210e8d8bef9SDimitry Andric DG.SyntheticRoot.end());
22118bcb0991SDimitry Andric
22120b57cec5SDimitry Andric // Reset the work list and repopulate with the changed abstract attributes.
22130b57cec5SDimitry Andric // Note that dependent ones are added above.
22140b57cec5SDimitry Andric Worklist.clear();
22150b57cec5SDimitry Andric Worklist.insert(ChangedAAs.begin(), ChangedAAs.end());
22161fd87a68SDimitry Andric Worklist.insert(QueryAAsAwaitingUpdate.begin(),
22171fd87a68SDimitry Andric QueryAAsAwaitingUpdate.end());
22181fd87a68SDimitry Andric QueryAAsAwaitingUpdate.clear();
22190b57cec5SDimitry Andric
222006c3fb27SDimitry Andric } while (!Worklist.empty() && (IterationCounter++ < MaxIterations));
22210b57cec5SDimitry Andric
222281ad6265SDimitry Andric if (IterationCounter > MaxIterations && !Functions.empty()) {
2223349cc55cSDimitry Andric auto Remark = [&](OptimizationRemarkMissed ORM) {
2224349cc55cSDimitry Andric return ORM << "Attributor did not reach a fixpoint after "
222581ad6265SDimitry Andric << ore::NV("Iterations", MaxIterations) << " iterations.";
2226349cc55cSDimitry Andric };
222781ad6265SDimitry Andric Function *F = Functions.front();
2228349cc55cSDimitry Andric emitRemark<OptimizationRemarkMissed>(F, "FixedPoint", Remark);
2229349cc55cSDimitry Andric }
2230349cc55cSDimitry Andric
22310b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n[Attributor] Fixpoint iteration done after: "
223281ad6265SDimitry Andric << IterationCounter << "/" << MaxIterations
22330b57cec5SDimitry Andric << " iterations\n");
22340b57cec5SDimitry Andric
22350b57cec5SDimitry Andric // Reset abstract arguments not settled in a sound fixpoint by now. This
22360b57cec5SDimitry Andric // happens when we stopped the fixpoint iteration early. Note that only the
22370b57cec5SDimitry Andric // ones marked as "changed" *and* the ones transitively depending on them
22380b57cec5SDimitry Andric // need to be reverted to a pessimistic state. Others might not be in a
22390b57cec5SDimitry Andric // fixpoint state but we can use the optimistic results for them anyway.
22400b57cec5SDimitry Andric SmallPtrSet<AbstractAttribute *, 32> Visited;
22410b57cec5SDimitry Andric for (unsigned u = 0; u < ChangedAAs.size(); u++) {
22420b57cec5SDimitry Andric AbstractAttribute *ChangedAA = ChangedAAs[u];
22430b57cec5SDimitry Andric if (!Visited.insert(ChangedAA).second)
22440b57cec5SDimitry Andric continue;
22450b57cec5SDimitry Andric
22460b57cec5SDimitry Andric AbstractState &State = ChangedAA->getState();
22470b57cec5SDimitry Andric if (!State.isAtFixpoint()) {
22480b57cec5SDimitry Andric State.indicatePessimisticFixpoint();
22490b57cec5SDimitry Andric
22500b57cec5SDimitry Andric NumAttributesTimedOut++;
22510b57cec5SDimitry Andric }
22520b57cec5SDimitry Andric
225306c3fb27SDimitry Andric for (auto &DepIt : ChangedAA->Deps)
225406c3fb27SDimitry Andric ChangedAAs.push_back(cast<AbstractAttribute>(DepIt.getPointer()));
225506c3fb27SDimitry Andric ChangedAA->Deps.clear();
22560b57cec5SDimitry Andric }
22570b57cec5SDimitry Andric
22580b57cec5SDimitry Andric LLVM_DEBUG({
22590b57cec5SDimitry Andric if (!Visited.empty())
22600b57cec5SDimitry Andric dbgs() << "\n[Attributor] Finalized " << Visited.size()
22610b57cec5SDimitry Andric << " abstract attributes.\n";
22620b57cec5SDimitry Andric });
22635ffd83dbSDimitry Andric }
22645ffd83dbSDimitry Andric
registerForUpdate(AbstractAttribute & AA)22651fd87a68SDimitry Andric void Attributor::registerForUpdate(AbstractAttribute &AA) {
22661fd87a68SDimitry Andric assert(AA.isQueryAA() &&
22671fd87a68SDimitry Andric "Non-query AAs should not be required to register for updates!");
22681fd87a68SDimitry Andric QueryAAsAwaitingUpdate.insert(&AA);
22691fd87a68SDimitry Andric }
22701fd87a68SDimitry Andric
manifestAttributes()22715ffd83dbSDimitry Andric ChangeStatus Attributor::manifestAttributes() {
2272e8d8bef9SDimitry Andric TimeTraceScope TimeScope("Attributor::manifestAttributes");
2273e8d8bef9SDimitry Andric size_t NumFinalAAs = DG.SyntheticRoot.Deps.size();
22745ffd83dbSDimitry Andric
22750b57cec5SDimitry Andric unsigned NumManifested = 0;
22760b57cec5SDimitry Andric unsigned NumAtFixpoint = 0;
22770b57cec5SDimitry Andric ChangeStatus ManifestChange = ChangeStatus::UNCHANGED;
2278e8d8bef9SDimitry Andric for (auto &DepAA : DG.SyntheticRoot.Deps) {
2279e8d8bef9SDimitry Andric AbstractAttribute *AA = cast<AbstractAttribute>(DepAA.getPointer());
22800b57cec5SDimitry Andric AbstractState &State = AA->getState();
22810b57cec5SDimitry Andric
22820b57cec5SDimitry Andric // If there is not already a fixpoint reached, we can now take the
22830b57cec5SDimitry Andric // optimistic state. This is correct because we enforced a pessimistic one
22840b57cec5SDimitry Andric // on abstract attributes that were transitively dependent on a changed one
22850b57cec5SDimitry Andric // already above.
22860b57cec5SDimitry Andric if (!State.isAtFixpoint())
22870b57cec5SDimitry Andric State.indicateOptimisticFixpoint();
22880b57cec5SDimitry Andric
2289fe6060f1SDimitry Andric // We must not manifest Attributes that use Callbase info.
2290fe6060f1SDimitry Andric if (AA->hasCallBaseContext())
2291fe6060f1SDimitry Andric continue;
22920b57cec5SDimitry Andric // If the state is invalid, we do not try to manifest it.
22930b57cec5SDimitry Andric if (!State.isValidState())
22940b57cec5SDimitry Andric continue;
22950b57cec5SDimitry Andric
229681ad6265SDimitry Andric if (AA->getCtxI() && !isRunOn(*AA->getAnchorScope()))
229781ad6265SDimitry Andric continue;
229881ad6265SDimitry Andric
22998bcb0991SDimitry Andric // Skip dead code.
2300fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
2301fe6060f1SDimitry Andric if (isAssumedDead(*AA, nullptr, UsedAssumedInformation,
2302fe6060f1SDimitry Andric /* CheckBBLivenessOnly */ true))
23038bcb0991SDimitry Andric continue;
2304e8d8bef9SDimitry Andric // Check if the manifest debug counter that allows skipping manifestation of
2305e8d8bef9SDimitry Andric // AAs
2306e8d8bef9SDimitry Andric if (!DebugCounter::shouldExecute(ManifestDBGCounter))
2307e8d8bef9SDimitry Andric continue;
23080b57cec5SDimitry Andric // Manifest the state and record if we changed the IR.
23090b57cec5SDimitry Andric ChangeStatus LocalChange = AA->manifest(*this);
23108bcb0991SDimitry Andric if (LocalChange == ChangeStatus::CHANGED && AreStatisticsEnabled())
23118bcb0991SDimitry Andric AA->trackStatistics();
23125ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Manifest " << LocalChange << " : " << *AA
23135ffd83dbSDimitry Andric << "\n");
23148bcb0991SDimitry Andric
23150b57cec5SDimitry Andric ManifestChange = ManifestChange | LocalChange;
23160b57cec5SDimitry Andric
23170b57cec5SDimitry Andric NumAtFixpoint++;
23180b57cec5SDimitry Andric NumManifested += (LocalChange == ChangeStatus::CHANGED);
23190b57cec5SDimitry Andric }
23200b57cec5SDimitry Andric
23210b57cec5SDimitry Andric (void)NumManifested;
23220b57cec5SDimitry Andric (void)NumAtFixpoint;
23230b57cec5SDimitry Andric LLVM_DEBUG(dbgs() << "\n[Attributor] Manifested " << NumManifested
23240b57cec5SDimitry Andric << " arguments while " << NumAtFixpoint
23250b57cec5SDimitry Andric << " were in a valid fixpoint state\n");
23260b57cec5SDimitry Andric
23270b57cec5SDimitry Andric NumAttributesManifested += NumManifested;
23280b57cec5SDimitry Andric NumAttributesValidFixpoint += NumAtFixpoint;
23290b57cec5SDimitry Andric
23308bcb0991SDimitry Andric (void)NumFinalAAs;
2331e8d8bef9SDimitry Andric if (NumFinalAAs != DG.SyntheticRoot.Deps.size()) {
233206c3fb27SDimitry Andric auto DepIt = DG.SyntheticRoot.Deps.begin();
233306c3fb27SDimitry Andric for (unsigned u = 0; u < NumFinalAAs; ++u)
233406c3fb27SDimitry Andric ++DepIt;
233506c3fb27SDimitry Andric for (unsigned u = NumFinalAAs; u < DG.SyntheticRoot.Deps.size();
233606c3fb27SDimitry Andric ++u, ++DepIt) {
2337e8d8bef9SDimitry Andric errs() << "Unexpected abstract attribute: "
233806c3fb27SDimitry Andric << cast<AbstractAttribute>(DepIt->getPointer()) << " :: "
233906c3fb27SDimitry Andric << cast<AbstractAttribute>(DepIt->getPointer())
2340e8d8bef9SDimitry Andric ->getIRPosition()
2341e8d8bef9SDimitry Andric .getAssociatedValue()
23425ffd83dbSDimitry Andric << "\n";
234306c3fb27SDimitry Andric }
23445ffd83dbSDimitry Andric llvm_unreachable("Expected the final number of abstract attributes to "
23455ffd83dbSDimitry Andric "remain unchanged!");
23465ffd83dbSDimitry Andric }
234706c3fb27SDimitry Andric
234806c3fb27SDimitry Andric for (auto &It : AttrsMap) {
234906c3fb27SDimitry Andric AttributeList &AL = It.getSecond();
235006c3fb27SDimitry Andric const IRPosition &IRP =
235106c3fb27SDimitry Andric isa<Function>(It.getFirst())
235206c3fb27SDimitry Andric ? IRPosition::function(*cast<Function>(It.getFirst()))
235306c3fb27SDimitry Andric : IRPosition::callsite_function(*cast<CallBase>(It.getFirst()));
235406c3fb27SDimitry Andric IRP.setAttrList(AL);
235506c3fb27SDimitry Andric }
235606c3fb27SDimitry Andric
23575ffd83dbSDimitry Andric return ManifestChange;
23585ffd83dbSDimitry Andric }
23598bcb0991SDimitry Andric
identifyDeadInternalFunctions()2360e8d8bef9SDimitry Andric void Attributor::identifyDeadInternalFunctions() {
2361fe6060f1SDimitry Andric // Early exit if we don't intend to delete functions.
236281ad6265SDimitry Andric if (!Configuration.DeleteFns)
2363fe6060f1SDimitry Andric return;
2364fe6060f1SDimitry Andric
2365bdd1243dSDimitry Andric // To avoid triggering an assertion in the lazy call graph we will not delete
2366bdd1243dSDimitry Andric // any internal library functions. We should modify the assertion though and
2367bdd1243dSDimitry Andric // allow internals to be deleted.
2368bdd1243dSDimitry Andric const auto *TLI =
2369bdd1243dSDimitry Andric isModulePass()
2370bdd1243dSDimitry Andric ? nullptr
2371bdd1243dSDimitry Andric : getInfoCache().getTargetLibraryInfoForFunction(*Functions.back());
2372bdd1243dSDimitry Andric LibFunc LF;
2373bdd1243dSDimitry Andric
2374e8d8bef9SDimitry Andric // Identify dead internal functions and delete them. This happens outside
2375e8d8bef9SDimitry Andric // the other fixpoint analysis as we might treat potentially dead functions
2376e8d8bef9SDimitry Andric // as live to lower the number of iterations. If they happen to be dead, the
2377e8d8bef9SDimitry Andric // below fixpoint loop will identify and eliminate them.
2378bdd1243dSDimitry Andric
2379e8d8bef9SDimitry Andric SmallVector<Function *, 8> InternalFns;
2380e8d8bef9SDimitry Andric for (Function *F : Functions)
2381bdd1243dSDimitry Andric if (F->hasLocalLinkage() && (isModulePass() || !TLI->getLibFunc(*F, LF)))
2382e8d8bef9SDimitry Andric InternalFns.push_back(F);
2383e8d8bef9SDimitry Andric
2384e8d8bef9SDimitry Andric SmallPtrSet<Function *, 8> LiveInternalFns;
2385e8d8bef9SDimitry Andric bool FoundLiveInternal = true;
2386e8d8bef9SDimitry Andric while (FoundLiveInternal) {
2387e8d8bef9SDimitry Andric FoundLiveInternal = false;
2388*0fca6ea1SDimitry Andric for (Function *&F : InternalFns) {
2389e8d8bef9SDimitry Andric if (!F)
2390e8d8bef9SDimitry Andric continue;
2391e8d8bef9SDimitry Andric
2392d781ede6SDimitry Andric bool UsedAssumedInformation = false;
2393e8d8bef9SDimitry Andric if (checkForAllCallSites(
2394e8d8bef9SDimitry Andric [&](AbstractCallSite ACS) {
2395e8d8bef9SDimitry Andric Function *Callee = ACS.getInstruction()->getFunction();
2396e8d8bef9SDimitry Andric return ToBeDeletedFunctions.count(Callee) ||
2397e8d8bef9SDimitry Andric (Functions.count(Callee) && Callee->hasLocalLinkage() &&
2398e8d8bef9SDimitry Andric !LiveInternalFns.count(Callee));
2399e8d8bef9SDimitry Andric },
2400d781ede6SDimitry Andric *F, true, nullptr, UsedAssumedInformation)) {
2401e8d8bef9SDimitry Andric continue;
2402e8d8bef9SDimitry Andric }
2403e8d8bef9SDimitry Andric
2404e8d8bef9SDimitry Andric LiveInternalFns.insert(F);
2405*0fca6ea1SDimitry Andric F = nullptr;
2406e8d8bef9SDimitry Andric FoundLiveInternal = true;
2407e8d8bef9SDimitry Andric }
2408e8d8bef9SDimitry Andric }
2409e8d8bef9SDimitry Andric
2410*0fca6ea1SDimitry Andric for (Function *F : InternalFns)
2411*0fca6ea1SDimitry Andric if (F)
2412e8d8bef9SDimitry Andric ToBeDeletedFunctions.insert(F);
2413e8d8bef9SDimitry Andric }
2414e8d8bef9SDimitry Andric
cleanupIR()24155ffd83dbSDimitry Andric ChangeStatus Attributor::cleanupIR() {
2416e8d8bef9SDimitry Andric TimeTraceScope TimeScope("Attributor::cleanupIR");
24178bcb0991SDimitry Andric // Delete stuff at the end to avoid invalid references and a nice order.
2418fe6060f1SDimitry Andric LLVM_DEBUG(dbgs() << "\n[Attributor] Delete/replace at least "
24198bcb0991SDimitry Andric << ToBeDeletedFunctions.size() << " functions and "
24208bcb0991SDimitry Andric << ToBeDeletedBlocks.size() << " blocks and "
2421480093f4SDimitry Andric << ToBeDeletedInsts.size() << " instructions and "
2422fe6060f1SDimitry Andric << ToBeChangedValues.size() << " values and "
242381ad6265SDimitry Andric << ToBeChangedUses.size() << " uses. To insert "
2424fcaf7f86SDimitry Andric << ToBeChangedToUnreachableInsts.size()
2425fcaf7f86SDimitry Andric << " unreachables.\n"
2426fe6060f1SDimitry Andric << "Preserve manifest added " << ManifestAddedBlocks.size()
2427fe6060f1SDimitry Andric << " blocks\n");
2428480093f4SDimitry Andric
24295ffd83dbSDimitry Andric SmallVector<WeakTrackingVH, 32> DeadInsts;
2430480093f4SDimitry Andric SmallVector<Instruction *, 32> TerminatorsToFold;
2431480093f4SDimitry Andric
2432fe6060f1SDimitry Andric auto ReplaceUse = [&](Use *U, Value *NewV) {
2433480093f4SDimitry Andric Value *OldV = U->get();
24345ffd83dbSDimitry Andric
2435fe6060f1SDimitry Andric // If we plan to replace NewV we need to update it at this point.
2436fe6060f1SDimitry Andric do {
2437fe6060f1SDimitry Andric const auto &Entry = ToBeChangedValues.lookup(NewV);
2438bdd1243dSDimitry Andric if (!get<0>(Entry))
2439fe6060f1SDimitry Andric break;
2440bdd1243dSDimitry Andric NewV = get<0>(Entry);
2441fe6060f1SDimitry Andric } while (true);
2442fe6060f1SDimitry Andric
244381ad6265SDimitry Andric Instruction *I = dyn_cast<Instruction>(U->getUser());
244481ad6265SDimitry Andric assert((!I || isRunOn(*I->getFunction())) &&
244581ad6265SDimitry Andric "Cannot replace an instruction outside the current SCC!");
244681ad6265SDimitry Andric
24475ffd83dbSDimitry Andric // Do not replace uses in returns if the value is a must-tail call we will
24485ffd83dbSDimitry Andric // not delete.
244981ad6265SDimitry Andric if (auto *RI = dyn_cast_or_null<ReturnInst>(I)) {
24505ffd83dbSDimitry Andric if (auto *CI = dyn_cast<CallInst>(OldV->stripPointerCasts()))
245181ad6265SDimitry Andric if (CI->isMustTailCall() && !ToBeDeletedInsts.count(CI))
2452fe6060f1SDimitry Andric return;
2453fe6060f1SDimitry Andric // If we rewrite a return and the new value is not an argument, strip the
2454fe6060f1SDimitry Andric // `returned` attribute as it is wrong now.
2455fe6060f1SDimitry Andric if (!isa<Argument>(NewV))
2456fe6060f1SDimitry Andric for (auto &Arg : RI->getFunction()->args())
2457fe6060f1SDimitry Andric Arg.removeAttr(Attribute::Returned);
2458fe6060f1SDimitry Andric }
2459fe6060f1SDimitry Andric
2460480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "Use " << *NewV << " in " << *U->getUser()
2461480093f4SDimitry Andric << " instead of " << *OldV << "\n");
2462480093f4SDimitry Andric U->set(NewV);
2463fe6060f1SDimitry Andric
24645ffd83dbSDimitry Andric if (Instruction *I = dyn_cast<Instruction>(OldV)) {
24655ffd83dbSDimitry Andric CGModifiedFunctions.insert(I->getFunction());
2466480093f4SDimitry Andric if (!isa<PHINode>(I) && !ToBeDeletedInsts.count(I) &&
24675ffd83dbSDimitry Andric isInstructionTriviallyDead(I))
2468480093f4SDimitry Andric DeadInsts.push_back(I);
2469480093f4SDimitry Andric }
2470fe6060f1SDimitry Andric if (isa<UndefValue>(NewV) && isa<CallBase>(U->getUser())) {
2471fe6060f1SDimitry Andric auto *CB = cast<CallBase>(U->getUser());
2472fe6060f1SDimitry Andric if (CB->isArgOperand(U)) {
2473fe6060f1SDimitry Andric unsigned Idx = CB->getArgOperandNo(U);
2474fe6060f1SDimitry Andric CB->removeParamAttr(Idx, Attribute::NoUndef);
247506c3fb27SDimitry Andric auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand());
247606c3fb27SDimitry Andric if (Callee && Callee->arg_size() > Idx)
247706c3fb27SDimitry Andric Callee->removeParamAttr(Idx, Attribute::NoUndef);
2478fe6060f1SDimitry Andric }
2479fe6060f1SDimitry Andric }
2480480093f4SDimitry Andric if (isa<Constant>(NewV) && isa<BranchInst>(U->getUser())) {
2481480093f4SDimitry Andric Instruction *UserI = cast<Instruction>(U->getUser());
2482480093f4SDimitry Andric if (isa<UndefValue>(NewV)) {
2483480093f4SDimitry Andric ToBeChangedToUnreachableInsts.insert(UserI);
2484480093f4SDimitry Andric } else {
2485480093f4SDimitry Andric TerminatorsToFold.push_back(UserI);
2486480093f4SDimitry Andric }
2487480093f4SDimitry Andric }
2488fe6060f1SDimitry Andric };
2489fe6060f1SDimitry Andric
2490fe6060f1SDimitry Andric for (auto &It : ToBeChangedUses) {
2491fe6060f1SDimitry Andric Use *U = It.first;
2492fe6060f1SDimitry Andric Value *NewV = It.second;
2493fe6060f1SDimitry Andric ReplaceUse(U, NewV);
2494480093f4SDimitry Andric }
2495fe6060f1SDimitry Andric
2496fe6060f1SDimitry Andric SmallVector<Use *, 4> Uses;
2497fe6060f1SDimitry Andric for (auto &It : ToBeChangedValues) {
2498fe6060f1SDimitry Andric Value *OldV = It.first;
2499bdd1243dSDimitry Andric auto [NewV, Done] = It.second;
2500fe6060f1SDimitry Andric Uses.clear();
2501fe6060f1SDimitry Andric for (auto &U : OldV->uses())
2502bdd1243dSDimitry Andric if (Done || !U.getUser()->isDroppable())
2503fe6060f1SDimitry Andric Uses.push_back(&U);
250481ad6265SDimitry Andric for (Use *U : Uses) {
250581ad6265SDimitry Andric if (auto *I = dyn_cast<Instruction>(U->getUser()))
250681ad6265SDimitry Andric if (!isRunOn(*I->getFunction()))
250781ad6265SDimitry Andric continue;
2508fe6060f1SDimitry Andric ReplaceUse(U, NewV);
2509fe6060f1SDimitry Andric }
251081ad6265SDimitry Andric }
2511fe6060f1SDimitry Andric
2512bdd1243dSDimitry Andric for (const auto &V : InvokeWithDeadSuccessor)
2513480093f4SDimitry Andric if (InvokeInst *II = dyn_cast_or_null<InvokeInst>(V)) {
2514fe6060f1SDimitry Andric assert(isRunOn(*II->getFunction()) &&
2515fe6060f1SDimitry Andric "Cannot replace an invoke outside the current SCC!");
2516480093f4SDimitry Andric bool UnwindBBIsDead = II->hasFnAttr(Attribute::NoUnwind);
2517480093f4SDimitry Andric bool NormalBBIsDead = II->hasFnAttr(Attribute::NoReturn);
2518480093f4SDimitry Andric bool Invoke2CallAllowed =
25195ffd83dbSDimitry Andric !AAIsDead::mayCatchAsynchronousExceptions(*II->getFunction());
2520480093f4SDimitry Andric assert((UnwindBBIsDead || NormalBBIsDead) &&
2521480093f4SDimitry Andric "Invoke does not have dead successors!");
2522480093f4SDimitry Andric BasicBlock *BB = II->getParent();
2523480093f4SDimitry Andric BasicBlock *NormalDestBB = II->getNormalDest();
2524480093f4SDimitry Andric if (UnwindBBIsDead) {
2525480093f4SDimitry Andric Instruction *NormalNextIP = &NormalDestBB->front();
2526480093f4SDimitry Andric if (Invoke2CallAllowed) {
2527480093f4SDimitry Andric changeToCall(II);
2528480093f4SDimitry Andric NormalNextIP = BB->getTerminator();
2529480093f4SDimitry Andric }
2530480093f4SDimitry Andric if (NormalBBIsDead)
2531480093f4SDimitry Andric ToBeChangedToUnreachableInsts.insert(NormalNextIP);
2532480093f4SDimitry Andric } else {
2533480093f4SDimitry Andric assert(NormalBBIsDead && "Broken invariant!");
2534480093f4SDimitry Andric if (!NormalDestBB->getUniquePredecessor())
2535480093f4SDimitry Andric NormalDestBB = SplitBlockPredecessors(NormalDestBB, {BB}, ".dead");
2536480093f4SDimitry Andric ToBeChangedToUnreachableInsts.insert(&NormalDestBB->front());
2537480093f4SDimitry Andric }
2538480093f4SDimitry Andric }
25395ffd83dbSDimitry Andric for (Instruction *I : TerminatorsToFold) {
254081ad6265SDimitry Andric assert(isRunOn(*I->getFunction()) &&
254181ad6265SDimitry Andric "Cannot replace a terminator outside the current SCC!");
25425ffd83dbSDimitry Andric CGModifiedFunctions.insert(I->getFunction());
2543480093f4SDimitry Andric ConstantFoldTerminator(I->getParent());
25445ffd83dbSDimitry Andric }
2545bdd1243dSDimitry Andric for (const auto &V : ToBeChangedToUnreachableInsts)
25465ffd83dbSDimitry Andric if (Instruction *I = dyn_cast_or_null<Instruction>(V)) {
2547fcaf7f86SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Change to unreachable: " << *I
2548fcaf7f86SDimitry Andric << "\n");
254981ad6265SDimitry Andric assert(isRunOn(*I->getFunction()) &&
255081ad6265SDimitry Andric "Cannot replace an instruction outside the current SCC!");
25515ffd83dbSDimitry Andric CGModifiedFunctions.insert(I->getFunction());
2552fe6060f1SDimitry Andric changeToUnreachable(I);
25535ffd83dbSDimitry Andric }
2554480093f4SDimitry Andric
2555bdd1243dSDimitry Andric for (const auto &V : ToBeDeletedInsts) {
25565ffd83dbSDimitry Andric if (Instruction *I = dyn_cast_or_null<Instruction>(V)) {
2557*0fca6ea1SDimitry Andric assert((!isa<CallBase>(I) || isa<IntrinsicInst>(I) ||
2558*0fca6ea1SDimitry Andric isRunOn(*I->getFunction())) &&
255981ad6265SDimitry Andric "Cannot delete an instruction outside the current SCC!");
25605ffd83dbSDimitry Andric I->dropDroppableUses();
25615ffd83dbSDimitry Andric CGModifiedFunctions.insert(I->getFunction());
25625ffd83dbSDimitry Andric if (!I->getType()->isVoidTy())
25638bcb0991SDimitry Andric I->replaceAllUsesWith(UndefValue::get(I->getType()));
2564480093f4SDimitry Andric if (!isa<PHINode>(I) && isInstructionTriviallyDead(I))
2565480093f4SDimitry Andric DeadInsts.push_back(I);
2566480093f4SDimitry Andric else
25678bcb0991SDimitry Andric I->eraseFromParent();
25688bcb0991SDimitry Andric }
25695ffd83dbSDimitry Andric }
25705ffd83dbSDimitry Andric
257181ad6265SDimitry Andric llvm::erase_if(DeadInsts, [&](WeakTrackingVH I) { return !I; });
2572fe6060f1SDimitry Andric
2573fe6060f1SDimitry Andric LLVM_DEBUG({
2574fe6060f1SDimitry Andric dbgs() << "[Attributor] DeadInsts size: " << DeadInsts.size() << "\n";
2575fe6060f1SDimitry Andric for (auto &I : DeadInsts)
2576fe6060f1SDimitry Andric if (I)
2577fe6060f1SDimitry Andric dbgs() << " - " << *I << "\n";
2578fe6060f1SDimitry Andric });
25798bcb0991SDimitry Andric
2580480093f4SDimitry Andric RecursivelyDeleteTriviallyDeadInstructions(DeadInsts);
2581480093f4SDimitry Andric
25828bcb0991SDimitry Andric if (unsigned NumDeadBlocks = ToBeDeletedBlocks.size()) {
25838bcb0991SDimitry Andric SmallVector<BasicBlock *, 8> ToBeDeletedBBs;
25848bcb0991SDimitry Andric ToBeDeletedBBs.reserve(NumDeadBlocks);
25855ffd83dbSDimitry Andric for (BasicBlock *BB : ToBeDeletedBlocks) {
2586fe6060f1SDimitry Andric assert(isRunOn(*BB->getParent()) &&
2587fe6060f1SDimitry Andric "Cannot delete a block outside the current SCC!");
25885ffd83dbSDimitry Andric CGModifiedFunctions.insert(BB->getParent());
2589fe6060f1SDimitry Andric // Do not delete BBs added during manifests of AAs.
2590fe6060f1SDimitry Andric if (ManifestAddedBlocks.contains(BB))
2591fe6060f1SDimitry Andric continue;
25925ffd83dbSDimitry Andric ToBeDeletedBBs.push_back(BB);
25935ffd83dbSDimitry Andric }
2594480093f4SDimitry Andric // Actually we do not delete the blocks but squash them into a single
2595480093f4SDimitry Andric // unreachable but untangling branches that jump here is something we need
2596480093f4SDimitry Andric // to do in a more generic way.
25971fd87a68SDimitry Andric detachDeadBlocks(ToBeDeletedBBs, nullptr);
25988bcb0991SDimitry Andric }
25998bcb0991SDimitry Andric
2600e8d8bef9SDimitry Andric identifyDeadInternalFunctions();
2601480093f4SDimitry Andric
2602480093f4SDimitry Andric // Rewrite the functions as requested during manifest.
26035ffd83dbSDimitry Andric ChangeStatus ManifestChange = rewriteFunctionSignatures(CGModifiedFunctions);
2604480093f4SDimitry Andric
26055ffd83dbSDimitry Andric for (Function *Fn : CGModifiedFunctions)
2606fe6060f1SDimitry Andric if (!ToBeDeletedFunctions.count(Fn) && Functions.count(Fn))
260781ad6265SDimitry Andric Configuration.CGUpdater.reanalyzeFunction(*Fn);
2608480093f4SDimitry Andric
2609e8d8bef9SDimitry Andric for (Function *Fn : ToBeDeletedFunctions) {
2610e8d8bef9SDimitry Andric if (!Functions.count(Fn))
2611e8d8bef9SDimitry Andric continue;
261281ad6265SDimitry Andric Configuration.CGUpdater.removeFunction(*Fn);
2613e8d8bef9SDimitry Andric }
2614e8d8bef9SDimitry Andric
2615e8d8bef9SDimitry Andric if (!ToBeChangedUses.empty())
2616e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2617e8d8bef9SDimitry Andric
2618e8d8bef9SDimitry Andric if (!ToBeChangedToUnreachableInsts.empty())
2619e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2620e8d8bef9SDimitry Andric
2621e8d8bef9SDimitry Andric if (!ToBeDeletedFunctions.empty())
2622e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2623e8d8bef9SDimitry Andric
2624e8d8bef9SDimitry Andric if (!ToBeDeletedBlocks.empty())
2625e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2626e8d8bef9SDimitry Andric
2627e8d8bef9SDimitry Andric if (!ToBeDeletedInsts.empty())
2628e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2629e8d8bef9SDimitry Andric
2630e8d8bef9SDimitry Andric if (!InvokeWithDeadSuccessor.empty())
2631e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
2632e8d8bef9SDimitry Andric
2633e8d8bef9SDimitry Andric if (!DeadInsts.empty())
2634e8d8bef9SDimitry Andric ManifestChange = ChangeStatus::CHANGED;
26355ffd83dbSDimitry Andric
26365ffd83dbSDimitry Andric NumFnDeleted += ToBeDeletedFunctions.size();
26375ffd83dbSDimitry Andric
2638e8d8bef9SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Deleted " << ToBeDeletedFunctions.size()
26395ffd83dbSDimitry Andric << " functions after manifest.\n");
26405ffd83dbSDimitry Andric
26415ffd83dbSDimitry Andric #ifdef EXPENSIVE_CHECKS
26425ffd83dbSDimitry Andric for (Function *F : Functions) {
26435ffd83dbSDimitry Andric if (ToBeDeletedFunctions.count(F))
26445ffd83dbSDimitry Andric continue;
26455ffd83dbSDimitry Andric assert(!verifyFunction(*F, &errs()) && "Module verification failed!");
26468bcb0991SDimitry Andric }
26475ffd83dbSDimitry Andric #endif
26488bcb0991SDimitry Andric
26490b57cec5SDimitry Andric return ManifestChange;
26500b57cec5SDimitry Andric }
26510b57cec5SDimitry Andric
run()26525ffd83dbSDimitry Andric ChangeStatus Attributor::run() {
2653e8d8bef9SDimitry Andric TimeTraceScope TimeScope("Attributor::run");
2654fe6060f1SDimitry Andric AttributorCallGraph ACallGraph(*this);
2655fe6060f1SDimitry Andric
2656fe6060f1SDimitry Andric if (PrintCallGraph)
2657fe6060f1SDimitry Andric ACallGraph.populateAll();
2658e8d8bef9SDimitry Andric
2659e8d8bef9SDimitry Andric Phase = AttributorPhase::UPDATE;
26605ffd83dbSDimitry Andric runTillFixpoint();
2661e8d8bef9SDimitry Andric
2662e8d8bef9SDimitry Andric // dump graphs on demand
2663e8d8bef9SDimitry Andric if (DumpDepGraph)
2664e8d8bef9SDimitry Andric DG.dumpGraph();
2665e8d8bef9SDimitry Andric
2666e8d8bef9SDimitry Andric if (ViewDepGraph)
2667e8d8bef9SDimitry Andric DG.viewGraph();
2668e8d8bef9SDimitry Andric
2669e8d8bef9SDimitry Andric if (PrintDependencies)
2670e8d8bef9SDimitry Andric DG.print();
2671e8d8bef9SDimitry Andric
2672e8d8bef9SDimitry Andric Phase = AttributorPhase::MANIFEST;
26735ffd83dbSDimitry Andric ChangeStatus ManifestChange = manifestAttributes();
2674e8d8bef9SDimitry Andric
2675e8d8bef9SDimitry Andric Phase = AttributorPhase::CLEANUP;
26765ffd83dbSDimitry Andric ChangeStatus CleanupChange = cleanupIR();
2677e8d8bef9SDimitry Andric
2678fe6060f1SDimitry Andric if (PrintCallGraph)
2679fe6060f1SDimitry Andric ACallGraph.print();
2680fe6060f1SDimitry Andric
26815ffd83dbSDimitry Andric return ManifestChange | CleanupChange;
26825ffd83dbSDimitry Andric }
26835ffd83dbSDimitry Andric
updateAA(AbstractAttribute & AA)26845ffd83dbSDimitry Andric ChangeStatus Attributor::updateAA(AbstractAttribute &AA) {
268506c3fb27SDimitry Andric TimeTraceScope TimeScope("updateAA", [&]() {
268606c3fb27SDimitry Andric return AA.getName() + std::to_string(AA.getIRPosition().getPositionKind());
268706c3fb27SDimitry Andric });
2688e8d8bef9SDimitry Andric assert(Phase == AttributorPhase::UPDATE &&
2689e8d8bef9SDimitry Andric "We can update AA only in the update stage!");
2690e8d8bef9SDimitry Andric
26915ffd83dbSDimitry Andric // Use a new dependence vector for this update.
26925ffd83dbSDimitry Andric DependenceVector DV;
26935ffd83dbSDimitry Andric DependenceStack.push_back(&DV);
26945ffd83dbSDimitry Andric
26955ffd83dbSDimitry Andric auto &AAState = AA.getState();
26965ffd83dbSDimitry Andric ChangeStatus CS = ChangeStatus::UNCHANGED;
2697fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
2698fe6060f1SDimitry Andric if (!isAssumedDead(AA, nullptr, UsedAssumedInformation,
2699fe6060f1SDimitry Andric /* CheckBBLivenessOnly */ true))
27005ffd83dbSDimitry Andric CS = AA.update(*this);
27015ffd83dbSDimitry Andric
2702bdd1243dSDimitry Andric if (!AA.isQueryAA() && DV.empty() && !AA.getState().isAtFixpoint()) {
2703bdd1243dSDimitry Andric // If the AA did not rely on outside information but changed, we run it
2704bdd1243dSDimitry Andric // again to see if it found a fixpoint. Most AAs do but we don't require
2705bdd1243dSDimitry Andric // them to. Hence, it might take the AA multiple iterations to get to a
2706bdd1243dSDimitry Andric // fixpoint even if it does not rely on outside information, which is fine.
2707bdd1243dSDimitry Andric ChangeStatus RerunCS = ChangeStatus::UNCHANGED;
2708bdd1243dSDimitry Andric if (CS == ChangeStatus::CHANGED)
2709bdd1243dSDimitry Andric RerunCS = AA.update(*this);
2710bdd1243dSDimitry Andric
2711bdd1243dSDimitry Andric // If the attribute did not change during the run or rerun, and it still did
2712bdd1243dSDimitry Andric // not query any non-fix information, the state will not change and we can
2713bdd1243dSDimitry Andric // indicate that right at this point.
2714bdd1243dSDimitry Andric if (RerunCS == ChangeStatus::UNCHANGED && !AA.isQueryAA() && DV.empty())
27155ffd83dbSDimitry Andric AAState.indicateOptimisticFixpoint();
27165ffd83dbSDimitry Andric }
27175ffd83dbSDimitry Andric
27185ffd83dbSDimitry Andric if (!AAState.isAtFixpoint())
27195ffd83dbSDimitry Andric rememberDependences();
27205ffd83dbSDimitry Andric
27215ffd83dbSDimitry Andric // Verify the stack was used properly, that is we pop the dependence vector we
27225ffd83dbSDimitry Andric // put there earlier.
27235ffd83dbSDimitry Andric DependenceVector *PoppedDV = DependenceStack.pop_back_val();
27245ffd83dbSDimitry Andric (void)PoppedDV;
27255ffd83dbSDimitry Andric assert(PoppedDV == &DV && "Inconsistent usage of the dependence stack!");
27265ffd83dbSDimitry Andric
27275ffd83dbSDimitry Andric return CS;
27285ffd83dbSDimitry Andric }
27295ffd83dbSDimitry Andric
createShallowWrapper(Function & F)2730e8d8bef9SDimitry Andric void Attributor::createShallowWrapper(Function &F) {
27315ffd83dbSDimitry Andric assert(!F.isDeclaration() && "Cannot create a wrapper around a declaration!");
27325ffd83dbSDimitry Andric
27335ffd83dbSDimitry Andric Module &M = *F.getParent();
27345ffd83dbSDimitry Andric LLVMContext &Ctx = M.getContext();
27355ffd83dbSDimitry Andric FunctionType *FnTy = F.getFunctionType();
27365ffd83dbSDimitry Andric
27375ffd83dbSDimitry Andric Function *Wrapper =
27385ffd83dbSDimitry Andric Function::Create(FnTy, F.getLinkage(), F.getAddressSpace(), F.getName());
27395ffd83dbSDimitry Andric F.setName(""); // set the inside function anonymous
27405ffd83dbSDimitry Andric M.getFunctionList().insert(F.getIterator(), Wrapper);
2741*0fca6ea1SDimitry Andric // Flag whether the function is using new-debug-info or not.
2742*0fca6ea1SDimitry Andric Wrapper->IsNewDbgInfoFormat = M.IsNewDbgInfoFormat;
27435ffd83dbSDimitry Andric
27445ffd83dbSDimitry Andric F.setLinkage(GlobalValue::InternalLinkage);
27455ffd83dbSDimitry Andric
27465ffd83dbSDimitry Andric F.replaceAllUsesWith(Wrapper);
27475ffd83dbSDimitry Andric assert(F.use_empty() && "Uses remained after wrapper was created!");
27485ffd83dbSDimitry Andric
27495ffd83dbSDimitry Andric // Move the COMDAT section to the wrapper.
27505ffd83dbSDimitry Andric // TODO: Check if we need to keep it for F as well.
27515ffd83dbSDimitry Andric Wrapper->setComdat(F.getComdat());
27525ffd83dbSDimitry Andric F.setComdat(nullptr);
27535ffd83dbSDimitry Andric
27545ffd83dbSDimitry Andric // Copy all metadata and attributes but keep them on F as well.
27555ffd83dbSDimitry Andric SmallVector<std::pair<unsigned, MDNode *>, 1> MDs;
27565ffd83dbSDimitry Andric F.getAllMetadata(MDs);
27575ffd83dbSDimitry Andric for (auto MDIt : MDs)
27585ffd83dbSDimitry Andric Wrapper->addMetadata(MDIt.first, *MDIt.second);
27595ffd83dbSDimitry Andric Wrapper->setAttributes(F.getAttributes());
27605ffd83dbSDimitry Andric
27615ffd83dbSDimitry Andric // Create the call in the wrapper.
27625ffd83dbSDimitry Andric BasicBlock *EntryBB = BasicBlock::Create(Ctx, "entry", Wrapper);
27635ffd83dbSDimitry Andric
27645ffd83dbSDimitry Andric SmallVector<Value *, 8> Args;
2765e8d8bef9SDimitry Andric Argument *FArgIt = F.arg_begin();
27665ffd83dbSDimitry Andric for (Argument &Arg : Wrapper->args()) {
27675ffd83dbSDimitry Andric Args.push_back(&Arg);
27685ffd83dbSDimitry Andric Arg.setName((FArgIt++)->getName());
27695ffd83dbSDimitry Andric }
27705ffd83dbSDimitry Andric
27715ffd83dbSDimitry Andric CallInst *CI = CallInst::Create(&F, Args, "", EntryBB);
27725ffd83dbSDimitry Andric CI->setTailCall(true);
2773349cc55cSDimitry Andric CI->addFnAttr(Attribute::NoInline);
27745ffd83dbSDimitry Andric ReturnInst::Create(Ctx, CI->getType()->isVoidTy() ? nullptr : CI, EntryBB);
27755ffd83dbSDimitry Andric
2776e8d8bef9SDimitry Andric NumFnShallowWrappersCreated++;
2777e8d8bef9SDimitry Andric }
2778e8d8bef9SDimitry Andric
isInternalizable(Function & F)27796e75b2fbSDimitry Andric bool Attributor::isInternalizable(Function &F) {
27806e75b2fbSDimitry Andric if (F.isDeclaration() || F.hasLocalLinkage() ||
27816e75b2fbSDimitry Andric GlobalValue::isInterposableLinkage(F.getLinkage()))
27826e75b2fbSDimitry Andric return false;
27836e75b2fbSDimitry Andric return true;
27846e75b2fbSDimitry Andric }
27856e75b2fbSDimitry Andric
internalizeFunction(Function & F,bool Force)2786fe6060f1SDimitry Andric Function *Attributor::internalizeFunction(Function &F, bool Force) {
2787fe6060f1SDimitry Andric if (!AllowDeepWrapper && !Force)
2788fe6060f1SDimitry Andric return nullptr;
27896e75b2fbSDimitry Andric if (!isInternalizable(F))
2790fe6060f1SDimitry Andric return nullptr;
2791e8d8bef9SDimitry Andric
27926e75b2fbSDimitry Andric SmallPtrSet<Function *, 2> FnSet = {&F};
27936e75b2fbSDimitry Andric DenseMap<Function *, Function *> InternalizedFns;
27946e75b2fbSDimitry Andric internalizeFunctions(FnSet, InternalizedFns);
2795e8d8bef9SDimitry Andric
27966e75b2fbSDimitry Andric return InternalizedFns[&F];
27976e75b2fbSDimitry Andric }
27986e75b2fbSDimitry Andric
internalizeFunctions(SmallPtrSetImpl<Function * > & FnSet,DenseMap<Function *,Function * > & FnMap)27996e75b2fbSDimitry Andric bool Attributor::internalizeFunctions(SmallPtrSetImpl<Function *> &FnSet,
28006e75b2fbSDimitry Andric DenseMap<Function *, Function *> &FnMap) {
28016e75b2fbSDimitry Andric for (Function *F : FnSet)
28026e75b2fbSDimitry Andric if (!Attributor::isInternalizable(*F))
28036e75b2fbSDimitry Andric return false;
28046e75b2fbSDimitry Andric
28056e75b2fbSDimitry Andric FnMap.clear();
28066e75b2fbSDimitry Andric // Generate the internalized version of each function.
28076e75b2fbSDimitry Andric for (Function *F : FnSet) {
28086e75b2fbSDimitry Andric Module &M = *F->getParent();
28096e75b2fbSDimitry Andric FunctionType *FnTy = F->getFunctionType();
28106e75b2fbSDimitry Andric
28116e75b2fbSDimitry Andric // Create a copy of the current function
28126e75b2fbSDimitry Andric Function *Copied =
28136e75b2fbSDimitry Andric Function::Create(FnTy, F->getLinkage(), F->getAddressSpace(),
28146e75b2fbSDimitry Andric F->getName() + ".internalized");
2815e8d8bef9SDimitry Andric ValueToValueMapTy VMap;
2816e8d8bef9SDimitry Andric auto *NewFArgIt = Copied->arg_begin();
28176e75b2fbSDimitry Andric for (auto &Arg : F->args()) {
2818e8d8bef9SDimitry Andric auto ArgName = Arg.getName();
2819e8d8bef9SDimitry Andric NewFArgIt->setName(ArgName);
2820e8d8bef9SDimitry Andric VMap[&Arg] = &(*NewFArgIt++);
2821e8d8bef9SDimitry Andric }
2822e8d8bef9SDimitry Andric SmallVector<ReturnInst *, 8> Returns;
2823*0fca6ea1SDimitry Andric // Flag whether the function is using new-debug-info or not.
2824*0fca6ea1SDimitry Andric Copied->IsNewDbgInfoFormat = F->IsNewDbgInfoFormat;
2825e8d8bef9SDimitry Andric
2826e8d8bef9SDimitry Andric // Copy the body of the original function to the new one
28276e75b2fbSDimitry Andric CloneFunctionInto(Copied, F, VMap,
28286e75b2fbSDimitry Andric CloneFunctionChangeType::LocalChangesOnly, Returns);
2829e8d8bef9SDimitry Andric
28306e75b2fbSDimitry Andric // Set the linakage and visibility late as CloneFunctionInto has some
28316e75b2fbSDimitry Andric // implicit requirements.
2832e8d8bef9SDimitry Andric Copied->setVisibility(GlobalValue::DefaultVisibility);
2833e8d8bef9SDimitry Andric Copied->setLinkage(GlobalValue::PrivateLinkage);
2834e8d8bef9SDimitry Andric
2835e8d8bef9SDimitry Andric // Copy metadata
2836e8d8bef9SDimitry Andric SmallVector<std::pair<unsigned, MDNode *>, 1> MDs;
28376e75b2fbSDimitry Andric F->getAllMetadata(MDs);
2838e8d8bef9SDimitry Andric for (auto MDIt : MDs)
2839fe6060f1SDimitry Andric if (!Copied->hasMetadata())
2840e8d8bef9SDimitry Andric Copied->addMetadata(MDIt.first, *MDIt.second);
2841e8d8bef9SDimitry Andric
28426e75b2fbSDimitry Andric M.getFunctionList().insert(F->getIterator(), Copied);
2843e8d8bef9SDimitry Andric Copied->setDSOLocal(true);
28446e75b2fbSDimitry Andric FnMap[F] = Copied;
28456e75b2fbSDimitry Andric }
2846e8d8bef9SDimitry Andric
28476e75b2fbSDimitry Andric // Replace all uses of the old function with the new internalized function
28486e75b2fbSDimitry Andric // unless the caller is a function that was just internalized.
28496e75b2fbSDimitry Andric for (Function *F : FnSet) {
28506e75b2fbSDimitry Andric auto &InternalizedFn = FnMap[F];
28516e75b2fbSDimitry Andric auto IsNotInternalized = [&](Use &U) -> bool {
28526e75b2fbSDimitry Andric if (auto *CB = dyn_cast<CallBase>(U.getUser()))
28536e75b2fbSDimitry Andric return !FnMap.lookup(CB->getCaller());
28546e75b2fbSDimitry Andric return false;
28556e75b2fbSDimitry Andric };
28566e75b2fbSDimitry Andric F->replaceUsesWithIf(InternalizedFn, IsNotInternalized);
28576e75b2fbSDimitry Andric }
28586e75b2fbSDimitry Andric
28596e75b2fbSDimitry Andric return true;
28605ffd83dbSDimitry Andric }
28615ffd83dbSDimitry Andric
isValidFunctionSignatureRewrite(Argument & Arg,ArrayRef<Type * > ReplacementTypes)28625ffd83dbSDimitry Andric bool Attributor::isValidFunctionSignatureRewrite(
28635ffd83dbSDimitry Andric Argument &Arg, ArrayRef<Type *> ReplacementTypes) {
2864480093f4SDimitry Andric
286581ad6265SDimitry Andric if (!Configuration.RewriteSignatures)
2866fe6060f1SDimitry Andric return false;
2867fe6060f1SDimitry Andric
2868349cc55cSDimitry Andric Function *Fn = Arg.getParent();
2869349cc55cSDimitry Andric auto CallSiteCanBeChanged = [Fn](AbstractCallSite ACS) {
28705ffd83dbSDimitry Andric // Forbid the call site to cast the function return type. If we need to
28715ffd83dbSDimitry Andric // rewrite these functions we need to re-create a cast for the new call site
28725ffd83dbSDimitry Andric // (if the old had uses).
28735ffd83dbSDimitry Andric if (!ACS.getCalledFunction() ||
28745ffd83dbSDimitry Andric ACS.getInstruction()->getType() !=
28755ffd83dbSDimitry Andric ACS.getCalledFunction()->getReturnType())
28765ffd83dbSDimitry Andric return false;
287706c3fb27SDimitry Andric if (cast<CallBase>(ACS.getInstruction())->getCalledOperand()->getType() !=
287806c3fb27SDimitry Andric Fn->getType())
287906c3fb27SDimitry Andric return false;
288006c3fb27SDimitry Andric if (ACS.getNumArgOperands() != Fn->arg_size())
2881349cc55cSDimitry Andric return false;
2882480093f4SDimitry Andric // Forbid must-tail calls for now.
28835ffd83dbSDimitry Andric return !ACS.isCallbackCall() && !ACS.getInstruction()->isMustTailCall();
2884480093f4SDimitry Andric };
2885480093f4SDimitry Andric
2886480093f4SDimitry Andric // Avoid var-arg functions for now.
2887480093f4SDimitry Andric if (Fn->isVarArg()) {
2888480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite var-args functions\n");
2889480093f4SDimitry Andric return false;
2890480093f4SDimitry Andric }
2891480093f4SDimitry Andric
2892480093f4SDimitry Andric // Avoid functions with complicated argument passing semantics.
2893480093f4SDimitry Andric AttributeList FnAttributeList = Fn->getAttributes();
2894480093f4SDimitry Andric if (FnAttributeList.hasAttrSomewhere(Attribute::Nest) ||
2895480093f4SDimitry Andric FnAttributeList.hasAttrSomewhere(Attribute::StructRet) ||
28965ffd83dbSDimitry Andric FnAttributeList.hasAttrSomewhere(Attribute::InAlloca) ||
28975ffd83dbSDimitry Andric FnAttributeList.hasAttrSomewhere(Attribute::Preallocated)) {
2898480093f4SDimitry Andric LLVM_DEBUG(
2899480093f4SDimitry Andric dbgs() << "[Attributor] Cannot rewrite due to complex attribute\n");
2900480093f4SDimitry Andric return false;
2901480093f4SDimitry Andric }
2902480093f4SDimitry Andric
2903480093f4SDimitry Andric // Avoid callbacks for now.
2904d781ede6SDimitry Andric bool UsedAssumedInformation = false;
29055ffd83dbSDimitry Andric if (!checkForAllCallSites(CallSiteCanBeChanged, *Fn, true, nullptr,
290606c3fb27SDimitry Andric UsedAssumedInformation,
290706c3fb27SDimitry Andric /* CheckPotentiallyDead */ true)) {
2908480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite all call sites\n");
2909480093f4SDimitry Andric return false;
2910480093f4SDimitry Andric }
2911480093f4SDimitry Andric
2912480093f4SDimitry Andric auto InstPred = [](Instruction &I) {
2913480093f4SDimitry Andric if (auto *CI = dyn_cast<CallInst>(&I))
2914480093f4SDimitry Andric return !CI->isMustTailCall();
2915480093f4SDimitry Andric return true;
2916480093f4SDimitry Andric };
2917480093f4SDimitry Andric
2918480093f4SDimitry Andric // Forbid must-tail calls for now.
2919480093f4SDimitry Andric // TODO:
2920480093f4SDimitry Andric auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(*Fn);
29215ffd83dbSDimitry Andric if (!checkForAllInstructionsImpl(nullptr, OpcodeInstMap, InstPred, nullptr,
2922fe6060f1SDimitry Andric nullptr, {Instruction::Call},
2923fe6060f1SDimitry Andric UsedAssumedInformation)) {
2924480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Cannot rewrite due to instructions\n");
2925480093f4SDimitry Andric return false;
2926480093f4SDimitry Andric }
2927480093f4SDimitry Andric
29285ffd83dbSDimitry Andric return true;
29295ffd83dbSDimitry Andric }
29305ffd83dbSDimitry Andric
registerFunctionSignatureRewrite(Argument & Arg,ArrayRef<Type * > ReplacementTypes,ArgumentReplacementInfo::CalleeRepairCBTy && CalleeRepairCB,ArgumentReplacementInfo::ACSRepairCBTy && ACSRepairCB)29315ffd83dbSDimitry Andric bool Attributor::registerFunctionSignatureRewrite(
29325ffd83dbSDimitry Andric Argument &Arg, ArrayRef<Type *> ReplacementTypes,
29335ffd83dbSDimitry Andric ArgumentReplacementInfo::CalleeRepairCBTy &&CalleeRepairCB,
29345ffd83dbSDimitry Andric ArgumentReplacementInfo::ACSRepairCBTy &&ACSRepairCB) {
29355ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in "
29365ffd83dbSDimitry Andric << Arg.getParent()->getName() << " with "
29375ffd83dbSDimitry Andric << ReplacementTypes.size() << " replacements\n");
29385ffd83dbSDimitry Andric assert(isValidFunctionSignatureRewrite(Arg, ReplacementTypes) &&
29395ffd83dbSDimitry Andric "Cannot register an invalid rewrite");
29405ffd83dbSDimitry Andric
29415ffd83dbSDimitry Andric Function *Fn = Arg.getParent();
29425ffd83dbSDimitry Andric SmallVectorImpl<std::unique_ptr<ArgumentReplacementInfo>> &ARIs =
29435ffd83dbSDimitry Andric ArgumentReplacementMap[Fn];
29445ffd83dbSDimitry Andric if (ARIs.empty())
2945480093f4SDimitry Andric ARIs.resize(Fn->arg_size());
2946480093f4SDimitry Andric
2947480093f4SDimitry Andric // If we have a replacement already with less than or equal new arguments,
2948480093f4SDimitry Andric // ignore this request.
29495ffd83dbSDimitry Andric std::unique_ptr<ArgumentReplacementInfo> &ARI = ARIs[Arg.getArgNo()];
2950480093f4SDimitry Andric if (ARI && ARI->getNumReplacementArgs() <= ReplacementTypes.size()) {
2951480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Existing rewrite is preferred\n");
2952480093f4SDimitry Andric return false;
2953480093f4SDimitry Andric }
2954480093f4SDimitry Andric
2955480093f4SDimitry Andric // If we have a replacement already but we like the new one better, delete
2956480093f4SDimitry Andric // the old.
29575ffd83dbSDimitry Andric ARI.reset();
29585ffd83dbSDimitry Andric
29595ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Register new rewrite of " << Arg << " in "
29605ffd83dbSDimitry Andric << Arg.getParent()->getName() << " with "
29615ffd83dbSDimitry Andric << ReplacementTypes.size() << " replacements\n");
2962480093f4SDimitry Andric
2963480093f4SDimitry Andric // Remember the replacement.
29645ffd83dbSDimitry Andric ARI.reset(new ArgumentReplacementInfo(*this, Arg, ReplacementTypes,
2965480093f4SDimitry Andric std::move(CalleeRepairCB),
29665ffd83dbSDimitry Andric std::move(ACSRepairCB)));
2967480093f4SDimitry Andric
2968480093f4SDimitry Andric return true;
2969480093f4SDimitry Andric }
2970480093f4SDimitry Andric
shouldSeedAttribute(AbstractAttribute & AA)29715ffd83dbSDimitry Andric bool Attributor::shouldSeedAttribute(AbstractAttribute &AA) {
2972e8d8bef9SDimitry Andric bool Result = true;
2973e8d8bef9SDimitry Andric #ifndef NDEBUG
2974e8d8bef9SDimitry Andric if (SeedAllowList.size() != 0)
29750eae32dcSDimitry Andric Result = llvm::is_contained(SeedAllowList, AA.getName());
2976e8d8bef9SDimitry Andric Function *Fn = AA.getAnchorScope();
2977e8d8bef9SDimitry Andric if (FunctionSeedAllowList.size() != 0 && Fn)
29780eae32dcSDimitry Andric Result &= llvm::is_contained(FunctionSeedAllowList, Fn->getName());
2979e8d8bef9SDimitry Andric #endif
2980e8d8bef9SDimitry Andric return Result;
29815ffd83dbSDimitry Andric }
29825ffd83dbSDimitry Andric
rewriteFunctionSignatures(SmallSetVector<Function *,8> & ModifiedFns)29835ffd83dbSDimitry Andric ChangeStatus Attributor::rewriteFunctionSignatures(
298481ad6265SDimitry Andric SmallSetVector<Function *, 8> &ModifiedFns) {
2985480093f4SDimitry Andric ChangeStatus Changed = ChangeStatus::UNCHANGED;
2986480093f4SDimitry Andric
2987480093f4SDimitry Andric for (auto &It : ArgumentReplacementMap) {
2988480093f4SDimitry Andric Function *OldFn = It.getFirst();
2989480093f4SDimitry Andric
2990480093f4SDimitry Andric // Deleted functions do not require rewrites.
2991e8d8bef9SDimitry Andric if (!Functions.count(OldFn) || ToBeDeletedFunctions.count(OldFn))
2992480093f4SDimitry Andric continue;
2993480093f4SDimitry Andric
29945ffd83dbSDimitry Andric const SmallVectorImpl<std::unique_ptr<ArgumentReplacementInfo>> &ARIs =
29955ffd83dbSDimitry Andric It.getSecond();
2996480093f4SDimitry Andric assert(ARIs.size() == OldFn->arg_size() && "Inconsistent state!");
2997480093f4SDimitry Andric
2998480093f4SDimitry Andric SmallVector<Type *, 16> NewArgumentTypes;
2999480093f4SDimitry Andric SmallVector<AttributeSet, 16> NewArgumentAttributes;
3000480093f4SDimitry Andric
3001480093f4SDimitry Andric // Collect replacement argument types and copy over existing attributes.
3002480093f4SDimitry Andric AttributeList OldFnAttributeList = OldFn->getAttributes();
3003480093f4SDimitry Andric for (Argument &Arg : OldFn->args()) {
30045ffd83dbSDimitry Andric if (const std::unique_ptr<ArgumentReplacementInfo> &ARI =
30055ffd83dbSDimitry Andric ARIs[Arg.getArgNo()]) {
3006480093f4SDimitry Andric NewArgumentTypes.append(ARI->ReplacementTypes.begin(),
3007480093f4SDimitry Andric ARI->ReplacementTypes.end());
3008480093f4SDimitry Andric NewArgumentAttributes.append(ARI->getNumReplacementArgs(),
3009480093f4SDimitry Andric AttributeSet());
3010480093f4SDimitry Andric } else {
3011480093f4SDimitry Andric NewArgumentTypes.push_back(Arg.getType());
3012480093f4SDimitry Andric NewArgumentAttributes.push_back(
3013349cc55cSDimitry Andric OldFnAttributeList.getParamAttrs(Arg.getArgNo()));
3014480093f4SDimitry Andric }
3015480093f4SDimitry Andric }
3016480093f4SDimitry Andric
301781ad6265SDimitry Andric uint64_t LargestVectorWidth = 0;
301881ad6265SDimitry Andric for (auto *I : NewArgumentTypes)
301981ad6265SDimitry Andric if (auto *VT = dyn_cast<llvm::VectorType>(I))
3020bdd1243dSDimitry Andric LargestVectorWidth =
3021bdd1243dSDimitry Andric std::max(LargestVectorWidth,
3022bdd1243dSDimitry Andric VT->getPrimitiveSizeInBits().getKnownMinValue());
302381ad6265SDimitry Andric
3024480093f4SDimitry Andric FunctionType *OldFnTy = OldFn->getFunctionType();
3025480093f4SDimitry Andric Type *RetTy = OldFnTy->getReturnType();
3026480093f4SDimitry Andric
3027480093f4SDimitry Andric // Construct the new function type using the new arguments types.
3028480093f4SDimitry Andric FunctionType *NewFnTy =
3029480093f4SDimitry Andric FunctionType::get(RetTy, NewArgumentTypes, OldFnTy->isVarArg());
3030480093f4SDimitry Andric
3031480093f4SDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Function rewrite '" << OldFn->getName()
3032480093f4SDimitry Andric << "' from " << *OldFn->getFunctionType() << " to "
3033480093f4SDimitry Andric << *NewFnTy << "\n");
3034480093f4SDimitry Andric
3035480093f4SDimitry Andric // Create the new function body and insert it into the module.
3036480093f4SDimitry Andric Function *NewFn = Function::Create(NewFnTy, OldFn->getLinkage(),
3037480093f4SDimitry Andric OldFn->getAddressSpace(), "");
3038fe6060f1SDimitry Andric Functions.insert(NewFn);
3039480093f4SDimitry Andric OldFn->getParent()->getFunctionList().insert(OldFn->getIterator(), NewFn);
3040480093f4SDimitry Andric NewFn->takeName(OldFn);
3041480093f4SDimitry Andric NewFn->copyAttributesFrom(OldFn);
3042*0fca6ea1SDimitry Andric // Flag whether the function is using new-debug-info or not.
3043*0fca6ea1SDimitry Andric NewFn->IsNewDbgInfoFormat = OldFn->IsNewDbgInfoFormat;
3044480093f4SDimitry Andric
3045480093f4SDimitry Andric // Patch the pointer to LLVM function in debug info descriptor.
3046480093f4SDimitry Andric NewFn->setSubprogram(OldFn->getSubprogram());
3047480093f4SDimitry Andric OldFn->setSubprogram(nullptr);
3048480093f4SDimitry Andric
3049480093f4SDimitry Andric // Recompute the parameter attributes list based on the new arguments for
3050480093f4SDimitry Andric // the function.
3051480093f4SDimitry Andric LLVMContext &Ctx = OldFn->getContext();
3052480093f4SDimitry Andric NewFn->setAttributes(AttributeList::get(
3053349cc55cSDimitry Andric Ctx, OldFnAttributeList.getFnAttrs(), OldFnAttributeList.getRetAttrs(),
3054349cc55cSDimitry Andric NewArgumentAttributes));
305581ad6265SDimitry Andric AttributeFuncs::updateMinLegalVectorWidthAttr(*NewFn, LargestVectorWidth);
3056480093f4SDimitry Andric
30575f757f3fSDimitry Andric // Remove argmem from the memory effects if we have no more pointer
30585f757f3fSDimitry Andric // arguments, or they are readnone.
30595f757f3fSDimitry Andric MemoryEffects ME = NewFn->getMemoryEffects();
30605f757f3fSDimitry Andric int ArgNo = -1;
30615f757f3fSDimitry Andric if (ME.doesAccessArgPointees() && all_of(NewArgumentTypes, [&](Type *T) {
30625f757f3fSDimitry Andric ++ArgNo;
30635f757f3fSDimitry Andric return !T->isPtrOrPtrVectorTy() ||
30645f757f3fSDimitry Andric NewFn->hasParamAttribute(ArgNo, Attribute::ReadNone);
30655f757f3fSDimitry Andric })) {
30665f757f3fSDimitry Andric NewFn->setMemoryEffects(ME - MemoryEffects::argMemOnly());
30675f757f3fSDimitry Andric }
30685f757f3fSDimitry Andric
3069480093f4SDimitry Andric // Since we have now created the new function, splice the body of the old
3070480093f4SDimitry Andric // function right into the new function, leaving the old rotting hulk of the
3071480093f4SDimitry Andric // function empty.
3072bdd1243dSDimitry Andric NewFn->splice(NewFn->begin(), OldFn);
3073480093f4SDimitry Andric
30745ffd83dbSDimitry Andric // Fixup block addresses to reference new function.
30755ffd83dbSDimitry Andric SmallVector<BlockAddress *, 8u> BlockAddresses;
30765ffd83dbSDimitry Andric for (User *U : OldFn->users())
30775ffd83dbSDimitry Andric if (auto *BA = dyn_cast<BlockAddress>(U))
30785ffd83dbSDimitry Andric BlockAddresses.push_back(BA);
30795ffd83dbSDimitry Andric for (auto *BA : BlockAddresses)
30805ffd83dbSDimitry Andric BA->replaceAllUsesWith(BlockAddress::get(NewFn, BA->getBasicBlock()));
30815ffd83dbSDimitry Andric
3082480093f4SDimitry Andric // Set of all "call-like" instructions that invoke the old function mapped
3083480093f4SDimitry Andric // to their new replacements.
3084480093f4SDimitry Andric SmallVector<std::pair<CallBase *, CallBase *>, 8> CallSitePairs;
3085480093f4SDimitry Andric
3086480093f4SDimitry Andric // Callback to create a new "call-like" instruction for a given one.
3087480093f4SDimitry Andric auto CallSiteReplacementCreator = [&](AbstractCallSite ACS) {
3088480093f4SDimitry Andric CallBase *OldCB = cast<CallBase>(ACS.getInstruction());
3089480093f4SDimitry Andric const AttributeList &OldCallAttributeList = OldCB->getAttributes();
3090480093f4SDimitry Andric
3091480093f4SDimitry Andric // Collect the new argument operands for the replacement call site.
3092480093f4SDimitry Andric SmallVector<Value *, 16> NewArgOperands;
3093480093f4SDimitry Andric SmallVector<AttributeSet, 16> NewArgOperandAttributes;
3094480093f4SDimitry Andric for (unsigned OldArgNum = 0; OldArgNum < ARIs.size(); ++OldArgNum) {
3095480093f4SDimitry Andric unsigned NewFirstArgNum = NewArgOperands.size();
3096480093f4SDimitry Andric (void)NewFirstArgNum; // only used inside assert.
30975ffd83dbSDimitry Andric if (const std::unique_ptr<ArgumentReplacementInfo> &ARI =
30985ffd83dbSDimitry Andric ARIs[OldArgNum]) {
3099480093f4SDimitry Andric if (ARI->ACSRepairCB)
3100480093f4SDimitry Andric ARI->ACSRepairCB(*ARI, ACS, NewArgOperands);
3101480093f4SDimitry Andric assert(ARI->getNumReplacementArgs() + NewFirstArgNum ==
3102480093f4SDimitry Andric NewArgOperands.size() &&
3103480093f4SDimitry Andric "ACS repair callback did not provide as many operand as new "
3104480093f4SDimitry Andric "types were registered!");
3105480093f4SDimitry Andric // TODO: Exose the attribute set to the ACS repair callback
3106480093f4SDimitry Andric NewArgOperandAttributes.append(ARI->ReplacementTypes.size(),
3107480093f4SDimitry Andric AttributeSet());
3108480093f4SDimitry Andric } else {
3109480093f4SDimitry Andric NewArgOperands.push_back(ACS.getCallArgOperand(OldArgNum));
3110480093f4SDimitry Andric NewArgOperandAttributes.push_back(
3111349cc55cSDimitry Andric OldCallAttributeList.getParamAttrs(OldArgNum));
3112480093f4SDimitry Andric }
3113480093f4SDimitry Andric }
3114480093f4SDimitry Andric
3115480093f4SDimitry Andric assert(NewArgOperands.size() == NewArgOperandAttributes.size() &&
3116480093f4SDimitry Andric "Mismatch # argument operands vs. # argument operand attributes!");
3117480093f4SDimitry Andric assert(NewArgOperands.size() == NewFn->arg_size() &&
3118480093f4SDimitry Andric "Mismatch # argument operands vs. # function arguments!");
3119480093f4SDimitry Andric
3120480093f4SDimitry Andric SmallVector<OperandBundleDef, 4> OperandBundleDefs;
3121480093f4SDimitry Andric OldCB->getOperandBundlesAsDefs(OperandBundleDefs);
3122480093f4SDimitry Andric
3123480093f4SDimitry Andric // Create a new call or invoke instruction to replace the old one.
3124480093f4SDimitry Andric CallBase *NewCB;
3125480093f4SDimitry Andric if (InvokeInst *II = dyn_cast<InvokeInst>(OldCB)) {
3126*0fca6ea1SDimitry Andric NewCB = InvokeInst::Create(NewFn, II->getNormalDest(),
3127*0fca6ea1SDimitry Andric II->getUnwindDest(), NewArgOperands,
3128*0fca6ea1SDimitry Andric OperandBundleDefs, "", OldCB->getIterator());
3129480093f4SDimitry Andric } else {
3130480093f4SDimitry Andric auto *NewCI = CallInst::Create(NewFn, NewArgOperands, OperandBundleDefs,
3131*0fca6ea1SDimitry Andric "", OldCB->getIterator());
3132480093f4SDimitry Andric NewCI->setTailCallKind(cast<CallInst>(OldCB)->getTailCallKind());
3133480093f4SDimitry Andric NewCB = NewCI;
3134480093f4SDimitry Andric }
3135480093f4SDimitry Andric
3136480093f4SDimitry Andric // Copy over various properties and the new attributes.
31375ffd83dbSDimitry Andric NewCB->copyMetadata(*OldCB, {LLVMContext::MD_prof, LLVMContext::MD_dbg});
3138480093f4SDimitry Andric NewCB->setCallingConv(OldCB->getCallingConv());
3139480093f4SDimitry Andric NewCB->takeName(OldCB);
3140480093f4SDimitry Andric NewCB->setAttributes(AttributeList::get(
3141349cc55cSDimitry Andric Ctx, OldCallAttributeList.getFnAttrs(),
3142349cc55cSDimitry Andric OldCallAttributeList.getRetAttrs(), NewArgOperandAttributes));
3143480093f4SDimitry Andric
314481ad6265SDimitry Andric AttributeFuncs::updateMinLegalVectorWidthAttr(*NewCB->getCaller(),
314581ad6265SDimitry Andric LargestVectorWidth);
314681ad6265SDimitry Andric
3147480093f4SDimitry Andric CallSitePairs.push_back({OldCB, NewCB});
3148480093f4SDimitry Andric return true;
3149480093f4SDimitry Andric };
3150480093f4SDimitry Andric
3151480093f4SDimitry Andric // Use the CallSiteReplacementCreator to create replacement call sites.
3152d781ede6SDimitry Andric bool UsedAssumedInformation = false;
31535ffd83dbSDimitry Andric bool Success = checkForAllCallSites(CallSiteReplacementCreator, *OldFn,
3154bdd1243dSDimitry Andric true, nullptr, UsedAssumedInformation,
3155bdd1243dSDimitry Andric /* CheckPotentiallyDead */ true);
3156480093f4SDimitry Andric (void)Success;
3157480093f4SDimitry Andric assert(Success && "Assumed call site replacement to succeed!");
3158480093f4SDimitry Andric
3159480093f4SDimitry Andric // Rewire the arguments.
3160e8d8bef9SDimitry Andric Argument *OldFnArgIt = OldFn->arg_begin();
3161e8d8bef9SDimitry Andric Argument *NewFnArgIt = NewFn->arg_begin();
3162480093f4SDimitry Andric for (unsigned OldArgNum = 0; OldArgNum < ARIs.size();
3163480093f4SDimitry Andric ++OldArgNum, ++OldFnArgIt) {
31645ffd83dbSDimitry Andric if (const std::unique_ptr<ArgumentReplacementInfo> &ARI =
31655ffd83dbSDimitry Andric ARIs[OldArgNum]) {
3166480093f4SDimitry Andric if (ARI->CalleeRepairCB)
3167480093f4SDimitry Andric ARI->CalleeRepairCB(*ARI, *NewFn, NewFnArgIt);
316881ad6265SDimitry Andric if (ARI->ReplacementTypes.empty())
316981ad6265SDimitry Andric OldFnArgIt->replaceAllUsesWith(
317081ad6265SDimitry Andric PoisonValue::get(OldFnArgIt->getType()));
3171480093f4SDimitry Andric NewFnArgIt += ARI->ReplacementTypes.size();
3172480093f4SDimitry Andric } else {
3173480093f4SDimitry Andric NewFnArgIt->takeName(&*OldFnArgIt);
3174480093f4SDimitry Andric OldFnArgIt->replaceAllUsesWith(&*NewFnArgIt);
3175480093f4SDimitry Andric ++NewFnArgIt;
3176480093f4SDimitry Andric }
3177480093f4SDimitry Andric }
3178480093f4SDimitry Andric
3179480093f4SDimitry Andric // Eliminate the instructions *after* we visited all of them.
3180480093f4SDimitry Andric for (auto &CallSitePair : CallSitePairs) {
3181480093f4SDimitry Andric CallBase &OldCB = *CallSitePair.first;
3182480093f4SDimitry Andric CallBase &NewCB = *CallSitePair.second;
31835ffd83dbSDimitry Andric assert(OldCB.getType() == NewCB.getType() &&
31845ffd83dbSDimitry Andric "Cannot handle call sites with different types!");
31855ffd83dbSDimitry Andric ModifiedFns.insert(OldCB.getFunction());
3186480093f4SDimitry Andric OldCB.replaceAllUsesWith(&NewCB);
3187480093f4SDimitry Andric OldCB.eraseFromParent();
3188480093f4SDimitry Andric }
3189480093f4SDimitry Andric
31905ffd83dbSDimitry Andric // Replace the function in the call graph (if any).
319181ad6265SDimitry Andric Configuration.CGUpdater.replaceFunctionWith(*OldFn, *NewFn);
31925ffd83dbSDimitry Andric
31935ffd83dbSDimitry Andric // If the old function was modified and needed to be reanalyzed, the new one
31945ffd83dbSDimitry Andric // does now.
319581ad6265SDimitry Andric if (ModifiedFns.remove(OldFn))
31965ffd83dbSDimitry Andric ModifiedFns.insert(NewFn);
3197480093f4SDimitry Andric
3198480093f4SDimitry Andric Changed = ChangeStatus::CHANGED;
3199480093f4SDimitry Andric }
3200480093f4SDimitry Andric
3201480093f4SDimitry Andric return Changed;
3202480093f4SDimitry Andric }
3203480093f4SDimitry Andric
initializeInformationCache(const Function & CF,FunctionInfo & FI)32045ffd83dbSDimitry Andric void InformationCache::initializeInformationCache(const Function &CF,
32055ffd83dbSDimitry Andric FunctionInfo &FI) {
32065ffd83dbSDimitry Andric // As we do not modify the function here we can remove the const
32075ffd83dbSDimitry Andric // withouth breaking implicit assumptions. At the end of the day, we could
32085ffd83dbSDimitry Andric // initialize the cache eagerly which would look the same to the users.
32095ffd83dbSDimitry Andric Function &F = const_cast<Function &>(CF);
32100b57cec5SDimitry Andric
32118bcb0991SDimitry Andric // Walk all instructions to find interesting instructions that might be
32128bcb0991SDimitry Andric // queried by abstract attributes during their initialization or update.
32138bcb0991SDimitry Andric // This has to happen before we create attributes.
32140b57cec5SDimitry Andric
3215bdd1243dSDimitry Andric DenseMap<const Value *, std::optional<short>> AssumeUsesMap;
321681ad6265SDimitry Andric
321781ad6265SDimitry Andric // Add \p V to the assume uses map which track the number of uses outside of
321881ad6265SDimitry Andric // "visited" assumes. If no outside uses are left the value is added to the
321981ad6265SDimitry Andric // assume only use vector.
322081ad6265SDimitry Andric auto AddToAssumeUsesMap = [&](const Value &V) -> void {
322181ad6265SDimitry Andric SmallVector<const Instruction *> Worklist;
322281ad6265SDimitry Andric if (auto *I = dyn_cast<Instruction>(&V))
322381ad6265SDimitry Andric Worklist.push_back(I);
322481ad6265SDimitry Andric while (!Worklist.empty()) {
322581ad6265SDimitry Andric const Instruction *I = Worklist.pop_back_val();
3226bdd1243dSDimitry Andric std::optional<short> &NumUses = AssumeUsesMap[I];
322781ad6265SDimitry Andric if (!NumUses)
322881ad6265SDimitry Andric NumUses = I->getNumUses();
3229bdd1243dSDimitry Andric NumUses = *NumUses - /* this assume */ 1;
3230bdd1243dSDimitry Andric if (*NumUses != 0)
323181ad6265SDimitry Andric continue;
323281ad6265SDimitry Andric AssumeOnlyValues.insert(I);
323381ad6265SDimitry Andric for (const Value *Op : I->operands())
323481ad6265SDimitry Andric if (auto *OpI = dyn_cast<Instruction>(Op))
323581ad6265SDimitry Andric Worklist.push_back(OpI);
323681ad6265SDimitry Andric }
323781ad6265SDimitry Andric };
323881ad6265SDimitry Andric
32390b57cec5SDimitry Andric for (Instruction &I : instructions(&F)) {
32400b57cec5SDimitry Andric bool IsInterestingOpcode = false;
32410b57cec5SDimitry Andric
32420b57cec5SDimitry Andric // To allow easy access to all instructions in a function with a given
32430b57cec5SDimitry Andric // opcode we store them in the InfoCache. As not all opcodes are interesting
32440b57cec5SDimitry Andric // to concrete attributes we only cache the ones that are as identified in
32450b57cec5SDimitry Andric // the following switch.
32460b57cec5SDimitry Andric // Note: There are no concrete attributes now so this is initially empty.
32470b57cec5SDimitry Andric switch (I.getOpcode()) {
32480b57cec5SDimitry Andric default:
32495ffd83dbSDimitry Andric assert(!isa<CallBase>(&I) &&
32505ffd83dbSDimitry Andric "New call base instruction type needs to be known in the "
32518bcb0991SDimitry Andric "Attributor.");
32520b57cec5SDimitry Andric break;
32530b57cec5SDimitry Andric case Instruction::Call:
32545ffd83dbSDimitry Andric // Calls are interesting on their own, additionally:
32555ffd83dbSDimitry Andric // For `llvm.assume` calls we also fill the KnowledgeMap as we find them.
32565ffd83dbSDimitry Andric // For `must-tail` calls we remember the caller and callee.
3257fe6060f1SDimitry Andric if (auto *Assume = dyn_cast<AssumeInst>(&I)) {
3258bdd1243dSDimitry Andric AssumeOnlyValues.insert(Assume);
32595ffd83dbSDimitry Andric fillMapFromAssume(*Assume, KnowledgeMap);
326081ad6265SDimitry Andric AddToAssumeUsesMap(*Assume->getArgOperand(0));
32615ffd83dbSDimitry Andric } else if (cast<CallInst>(I).isMustTailCall()) {
32625ffd83dbSDimitry Andric FI.ContainsMustTailCall = true;
326306c3fb27SDimitry Andric if (auto *Callee = dyn_cast_if_present<Function>(
326406c3fb27SDimitry Andric cast<CallInst>(I).getCalledOperand()))
32655ffd83dbSDimitry Andric getFunctionInfo(*Callee).CalledViaMustTail = true;
32665ffd83dbSDimitry Andric }
3267bdd1243dSDimitry Andric [[fallthrough]];
32680b57cec5SDimitry Andric case Instruction::CallBr:
32690b57cec5SDimitry Andric case Instruction::Invoke:
32700b57cec5SDimitry Andric case Instruction::CleanupRet:
32710b57cec5SDimitry Andric case Instruction::CatchSwitch:
3272480093f4SDimitry Andric case Instruction::AtomicRMW:
3273480093f4SDimitry Andric case Instruction::AtomicCmpXchg:
3274480093f4SDimitry Andric case Instruction::Br:
32750b57cec5SDimitry Andric case Instruction::Resume:
32760b57cec5SDimitry Andric case Instruction::Ret:
32775ffd83dbSDimitry Andric case Instruction::Load:
32785ffd83dbSDimitry Andric // The alignment of a pointer is interesting for loads.
32795ffd83dbSDimitry Andric case Instruction::Store:
32805ffd83dbSDimitry Andric // The alignment of a pointer is interesting for stores.
3281fe6060f1SDimitry Andric case Instruction::Alloca:
3282fe6060f1SDimitry Andric case Instruction::AddrSpaceCast:
32830b57cec5SDimitry Andric IsInterestingOpcode = true;
32840b57cec5SDimitry Andric }
32855ffd83dbSDimitry Andric if (IsInterestingOpcode) {
32865ffd83dbSDimitry Andric auto *&Insts = FI.OpcodeInstMap[I.getOpcode()];
32875ffd83dbSDimitry Andric if (!Insts)
32885ffd83dbSDimitry Andric Insts = new (Allocator) InstructionVectorTy();
32895ffd83dbSDimitry Andric Insts->push_back(&I);
32908bcb0991SDimitry Andric }
32915ffd83dbSDimitry Andric if (I.mayReadOrWriteMemory())
32925ffd83dbSDimitry Andric FI.RWInsts.push_back(&I);
32935ffd83dbSDimitry Andric }
32945ffd83dbSDimitry Andric
32955ffd83dbSDimitry Andric if (F.hasFnAttribute(Attribute::AlwaysInline) &&
32965ffd83dbSDimitry Andric isInlineViable(F).isSuccess())
32975ffd83dbSDimitry Andric InlineableFunctions.insert(&F);
32985ffd83dbSDimitry Andric }
32995ffd83dbSDimitry Andric
~FunctionInfo()33005ffd83dbSDimitry Andric InformationCache::FunctionInfo::~FunctionInfo() {
33015ffd83dbSDimitry Andric // The instruction vectors are allocated using a BumpPtrAllocator, we need to
33025ffd83dbSDimitry Andric // manually destroy them.
33035ffd83dbSDimitry Andric for (auto &It : OpcodeInstMap)
33045ffd83dbSDimitry Andric It.getSecond()->~InstructionVectorTy();
33058bcb0991SDimitry Andric }
33060b57cec5SDimitry Andric
33075f757f3fSDimitry Andric const ArrayRef<Function *>
getIndirectlyCallableFunctions(Attributor & A) const33085f757f3fSDimitry Andric InformationCache::getIndirectlyCallableFunctions(Attributor &A) const {
33095f757f3fSDimitry Andric assert(A.isClosedWorldModule() && "Cannot see all indirect callees!");
33105f757f3fSDimitry Andric return IndirectlyCallableFunctions;
33115f757f3fSDimitry Andric }
33125f757f3fSDimitry Andric
recordDependence(const AbstractAttribute & FromAA,const AbstractAttribute & ToAA,DepClassTy DepClass)3313480093f4SDimitry Andric void Attributor::recordDependence(const AbstractAttribute &FromAA,
3314480093f4SDimitry Andric const AbstractAttribute &ToAA,
3315480093f4SDimitry Andric DepClassTy DepClass) {
3316fe6060f1SDimitry Andric if (DepClass == DepClassTy::NONE)
3317fe6060f1SDimitry Andric return;
33185ffd83dbSDimitry Andric // If we are outside of an update, thus before the actual fixpoint iteration
33195ffd83dbSDimitry Andric // started (= when we create AAs), we do not track dependences because we will
33205ffd83dbSDimitry Andric // put all AAs into the initial worklist anyway.
33215ffd83dbSDimitry Andric if (DependenceStack.empty())
33225ffd83dbSDimitry Andric return;
3323480093f4SDimitry Andric if (FromAA.getState().isAtFixpoint())
3324480093f4SDimitry Andric return;
33255ffd83dbSDimitry Andric DependenceStack.back()->push_back({&FromAA, &ToAA, DepClass});
33265ffd83dbSDimitry Andric }
3327480093f4SDimitry Andric
rememberDependences()33285ffd83dbSDimitry Andric void Attributor::rememberDependences() {
33295ffd83dbSDimitry Andric assert(!DependenceStack.empty() && "No dependences to remember!");
33305ffd83dbSDimitry Andric
33315ffd83dbSDimitry Andric for (DepInfo &DI : *DependenceStack.back()) {
3332fe6060f1SDimitry Andric assert((DI.DepClass == DepClassTy::REQUIRED ||
3333fe6060f1SDimitry Andric DI.DepClass == DepClassTy::OPTIONAL) &&
3334fe6060f1SDimitry Andric "Expected required or optional dependence (1 bit)!");
33355ffd83dbSDimitry Andric auto &DepAAs = const_cast<AbstractAttribute &>(*DI.FromAA).Deps;
333606c3fb27SDimitry Andric DepAAs.insert(AbstractAttribute::DepTy(
33375ffd83dbSDimitry Andric const_cast<AbstractAttribute *>(DI.ToAA), unsigned(DI.DepClass)));
33385ffd83dbSDimitry Andric }
3339480093f4SDimitry Andric }
3340480093f4SDimitry Andric
334106c3fb27SDimitry Andric template <Attribute::AttrKind AK, typename AAType>
checkAndQueryIRAttr(const IRPosition & IRP,AttributeSet Attrs)334206c3fb27SDimitry Andric void Attributor::checkAndQueryIRAttr(const IRPosition &IRP,
334306c3fb27SDimitry Andric AttributeSet Attrs) {
334406c3fb27SDimitry Andric bool IsKnown;
334506c3fb27SDimitry Andric if (!Attrs.hasAttribute(AK))
33465f757f3fSDimitry Andric if (!Configuration.Allowed || Configuration.Allowed->count(&AAType::ID))
334706c3fb27SDimitry Andric if (!AA::hasAssumedIRAttr<AK>(*this, nullptr, IRP, DepClassTy::NONE,
334806c3fb27SDimitry Andric IsKnown))
334906c3fb27SDimitry Andric getOrCreateAAFor<AAType>(IRP);
335006c3fb27SDimitry Andric }
335106c3fb27SDimitry Andric
identifyDefaultAbstractAttributes(Function & F)33528bcb0991SDimitry Andric void Attributor::identifyDefaultAbstractAttributes(Function &F) {
33538bcb0991SDimitry Andric if (!VisitedFunctions.insert(&F).second)
33548bcb0991SDimitry Andric return;
3355480093f4SDimitry Andric if (F.isDeclaration())
3356480093f4SDimitry Andric return;
33578bcb0991SDimitry Andric
33585ffd83dbSDimitry Andric // In non-module runs we need to look at the call sites of a function to
33595ffd83dbSDimitry Andric // determine if it is part of a must-tail call edge. This will influence what
33605ffd83dbSDimitry Andric // attributes we can derive.
33615ffd83dbSDimitry Andric InformationCache::FunctionInfo &FI = InfoCache.getFunctionInfo(F);
33625ffd83dbSDimitry Andric if (!isModulePass() && !FI.CalledViaMustTail) {
33635ffd83dbSDimitry Andric for (const Use &U : F.uses())
33645ffd83dbSDimitry Andric if (const auto *CB = dyn_cast<CallBase>(U.getUser()))
33655ffd83dbSDimitry Andric if (CB->isCallee(&U) && CB->isMustTailCall())
33665ffd83dbSDimitry Andric FI.CalledViaMustTail = true;
33675ffd83dbSDimitry Andric }
33685ffd83dbSDimitry Andric
33698bcb0991SDimitry Andric IRPosition FPos = IRPosition::function(F);
337006c3fb27SDimitry Andric bool IsIPOAmendable = isFunctionIPOAmendable(F);
337106c3fb27SDimitry Andric auto Attrs = F.getAttributes();
337206c3fb27SDimitry Andric auto FnAttrs = Attrs.getFnAttrs();
33738bcb0991SDimitry Andric
33748bcb0991SDimitry Andric // Check for dead BasicBlocks in every function.
33758bcb0991SDimitry Andric // We need dead instruction detection because we do not want to deal with
33768bcb0991SDimitry Andric // broken IR in which SSA rules do not apply.
33778bcb0991SDimitry Andric getOrCreateAAFor<AAIsDead>(FPos);
33788bcb0991SDimitry Andric
337906c3fb27SDimitry Andric // Every function might contain instructions that cause "undefined
338006c3fb27SDimitry Andric // behavior".
3381480093f4SDimitry Andric getOrCreateAAFor<AAUndefinedBehavior>(FPos);
3382480093f4SDimitry Andric
338306c3fb27SDimitry Andric // Every function might be applicable for Heap-To-Stack conversion.
338406c3fb27SDimitry Andric if (EnableHeapToStack)
338506c3fb27SDimitry Andric getOrCreateAAFor<AAHeapToStack>(FPos);
33868bcb0991SDimitry Andric
338706c3fb27SDimitry Andric // Every function might be "must-progress".
338806c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::MustProgress, AAMustProgress>(FPos, FnAttrs);
33898bcb0991SDimitry Andric
33908bcb0991SDimitry Andric // Every function might be "no-free".
339106c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(FPos, FnAttrs);
339206c3fb27SDimitry Andric
339306c3fb27SDimitry Andric // Every function might be "will-return".
339406c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::WillReturn, AAWillReturn>(FPos, FnAttrs);
339506c3fb27SDimitry Andric
33965f757f3fSDimitry Andric // Every function might be marked "nosync"
33975f757f3fSDimitry Andric checkAndQueryIRAttr<Attribute::NoSync, AANoSync>(FPos, FnAttrs);
33985f757f3fSDimitry Andric
339906c3fb27SDimitry Andric // Everything that is visible from the outside (=function, argument, return
340006c3fb27SDimitry Andric // positions), cannot be changed if the function is not IPO amendable. We can
340106c3fb27SDimitry Andric // however analyse the code inside.
340206c3fb27SDimitry Andric if (IsIPOAmendable) {
340306c3fb27SDimitry Andric
340406c3fb27SDimitry Andric // Every function can be nounwind.
340506c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoUnwind, AANoUnwind>(FPos, FnAttrs);
340606c3fb27SDimitry Andric
34078bcb0991SDimitry Andric // Every function might be "no-return".
340806c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoReturn, AANoReturn>(FPos, FnAttrs);
34098bcb0991SDimitry Andric
34108bcb0991SDimitry Andric // Every function might be "no-recurse".
341106c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoRecurse, AANoRecurse>(FPos, FnAttrs);
341206c3fb27SDimitry Andric
341306c3fb27SDimitry Andric // Every function can be "non-convergent".
341406c3fb27SDimitry Andric if (Attrs.hasFnAttr(Attribute::Convergent))
341506c3fb27SDimitry Andric getOrCreateAAFor<AANonConvergent>(FPos);
34168bcb0991SDimitry Andric
34178bcb0991SDimitry Andric // Every function might be "readnone/readonly/writeonly/...".
34188bcb0991SDimitry Andric getOrCreateAAFor<AAMemoryBehavior>(FPos);
34198bcb0991SDimitry Andric
34205ffd83dbSDimitry Andric // Every function can be "readnone/argmemonly/inaccessiblememonly/...".
34215ffd83dbSDimitry Andric getOrCreateAAFor<AAMemoryLocation>(FPos);
34225ffd83dbSDimitry Andric
3423349cc55cSDimitry Andric // Every function can track active assumptions.
3424349cc55cSDimitry Andric getOrCreateAAFor<AAAssumptionInfo>(FPos);
3425349cc55cSDimitry Andric
34265f757f3fSDimitry Andric // If we're not using a dynamic mode for float, there's nothing worthwhile
34275f757f3fSDimitry Andric // to infer. This misses the edge case denormal-fp-math="dynamic" and
34285f757f3fSDimitry Andric // denormal-fp-math-f32=something, but that likely has no real world use.
34295f757f3fSDimitry Andric DenormalMode Mode = F.getDenormalMode(APFloat::IEEEsingle());
34305f757f3fSDimitry Andric if (Mode.Input == DenormalMode::Dynamic ||
34315f757f3fSDimitry Andric Mode.Output == DenormalMode::Dynamic)
34325f757f3fSDimitry Andric getOrCreateAAFor<AADenormalFPMath>(FPos);
34335f757f3fSDimitry Andric
34348bcb0991SDimitry Andric // Return attributes are only appropriate if the return type is non void.
34358bcb0991SDimitry Andric Type *ReturnType = F.getReturnType();
34368bcb0991SDimitry Andric if (!ReturnType->isVoidTy()) {
34378bcb0991SDimitry Andric IRPosition RetPos = IRPosition::returned(F);
343806c3fb27SDimitry Andric AttributeSet RetAttrs = Attrs.getRetAttrs();
34398bcb0991SDimitry Andric
3440480093f4SDimitry Andric // Every returned value might be dead.
3441480093f4SDimitry Andric getOrCreateAAFor<AAIsDead>(RetPos);
3442480093f4SDimitry Andric
34438bcb0991SDimitry Andric // Every function might be simplified.
344481ad6265SDimitry Andric bool UsedAssumedInformation = false;
3445fcaf7f86SDimitry Andric getAssumedSimplified(RetPos, nullptr, UsedAssumedInformation,
3446fcaf7f86SDimitry Andric AA::Intraprocedural);
34478bcb0991SDimitry Andric
3448e8d8bef9SDimitry Andric // Every returned value might be marked noundef.
344906c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(RetPos, RetAttrs);
3450e8d8bef9SDimitry Andric
34518bcb0991SDimitry Andric if (ReturnType->isPointerTy()) {
34528bcb0991SDimitry Andric
34538bcb0991SDimitry Andric // Every function with pointer return type might be marked align.
34548bcb0991SDimitry Andric getOrCreateAAFor<AAAlign>(RetPos);
34558bcb0991SDimitry Andric
34568bcb0991SDimitry Andric // Every function with pointer return type might be marked nonnull.
345706c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(RetPos, RetAttrs);
34588bcb0991SDimitry Andric
34598bcb0991SDimitry Andric // Every function with pointer return type might be marked noalias.
346006c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(RetPos, RetAttrs);
34618bcb0991SDimitry Andric
34628bcb0991SDimitry Andric // Every function with pointer return type might be marked
34638bcb0991SDimitry Andric // dereferenceable.
34648bcb0991SDimitry Andric getOrCreateAAFor<AADereferenceable>(RetPos);
346506c3fb27SDimitry Andric } else if (AttributeFuncs::isNoFPClassCompatibleType(ReturnType)) {
346606c3fb27SDimitry Andric getOrCreateAAFor<AANoFPClass>(RetPos);
346706c3fb27SDimitry Andric }
34688bcb0991SDimitry Andric }
34698bcb0991SDimitry Andric }
34708bcb0991SDimitry Andric
34718bcb0991SDimitry Andric for (Argument &Arg : F.args()) {
34728bcb0991SDimitry Andric IRPosition ArgPos = IRPosition::argument(Arg);
347306c3fb27SDimitry Andric auto ArgNo = Arg.getArgNo();
347406c3fb27SDimitry Andric AttributeSet ArgAttrs = Attrs.getParamAttrs(ArgNo);
34758bcb0991SDimitry Andric
347606c3fb27SDimitry Andric if (!IsIPOAmendable) {
347706c3fb27SDimitry Andric if (Arg.getType()->isPointerTy())
347806c3fb27SDimitry Andric // Every argument with pointer type might be marked nofree.
347906c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(ArgPos, ArgAttrs);
348006c3fb27SDimitry Andric continue;
348106c3fb27SDimitry Andric }
348206c3fb27SDimitry Andric
348306c3fb27SDimitry Andric // Every argument might be simplified. We have to go through the
348406c3fb27SDimitry Andric // Attributor interface though as outside AAs can register custom
348506c3fb27SDimitry Andric // simplification callbacks.
3486fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
3487fcaf7f86SDimitry Andric getAssumedSimplified(ArgPos, /* AA */ nullptr, UsedAssumedInformation,
3488fcaf7f86SDimitry Andric AA::Intraprocedural);
34898bcb0991SDimitry Andric
34905ffd83dbSDimitry Andric // Every argument might be dead.
34915ffd83dbSDimitry Andric getOrCreateAAFor<AAIsDead>(ArgPos);
34925ffd83dbSDimitry Andric
3493e8d8bef9SDimitry Andric // Every argument might be marked noundef.
349406c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(ArgPos, ArgAttrs);
3495e8d8bef9SDimitry Andric
34968bcb0991SDimitry Andric if (Arg.getType()->isPointerTy()) {
34978bcb0991SDimitry Andric // Every argument with pointer type might be marked nonnull.
349806c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(ArgPos, ArgAttrs);
34998bcb0991SDimitry Andric
35008bcb0991SDimitry Andric // Every argument with pointer type might be marked noalias.
350106c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(ArgPos, ArgAttrs);
35028bcb0991SDimitry Andric
35038bcb0991SDimitry Andric // Every argument with pointer type might be marked dereferenceable.
35048bcb0991SDimitry Andric getOrCreateAAFor<AADereferenceable>(ArgPos);
35058bcb0991SDimitry Andric
35068bcb0991SDimitry Andric // Every argument with pointer type might be marked align.
35078bcb0991SDimitry Andric getOrCreateAAFor<AAAlign>(ArgPos);
35088bcb0991SDimitry Andric
35098bcb0991SDimitry Andric // Every argument with pointer type might be marked nocapture.
351006c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoCapture, AANoCapture>(ArgPos, ArgAttrs);
35118bcb0991SDimitry Andric
35128bcb0991SDimitry Andric // Every argument with pointer type might be marked
35138bcb0991SDimitry Andric // "readnone/readonly/writeonly/..."
35148bcb0991SDimitry Andric getOrCreateAAFor<AAMemoryBehavior>(ArgPos);
3515480093f4SDimitry Andric
3516480093f4SDimitry Andric // Every argument with pointer type might be marked nofree.
351706c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(ArgPos, ArgAttrs);
35185ffd83dbSDimitry Andric
351906c3fb27SDimitry Andric // Every argument with pointer type might be privatizable (or
352006c3fb27SDimitry Andric // promotable)
35215ffd83dbSDimitry Andric getOrCreateAAFor<AAPrivatizablePtr>(ArgPos);
352206c3fb27SDimitry Andric } else if (AttributeFuncs::isNoFPClassCompatibleType(Arg.getType())) {
352306c3fb27SDimitry Andric getOrCreateAAFor<AANoFPClass>(ArgPos);
35248bcb0991SDimitry Andric }
35258bcb0991SDimitry Andric }
35268bcb0991SDimitry Andric
35278bcb0991SDimitry Andric auto CallSitePred = [&](Instruction &I) -> bool {
35285ffd83dbSDimitry Andric auto &CB = cast<CallBase>(I);
35291fd87a68SDimitry Andric IRPosition CBInstPos = IRPosition::inst(CB);
3530349cc55cSDimitry Andric IRPosition CBFnPos = IRPosition::callsite_function(CB);
35315ffd83dbSDimitry Andric
35325ffd83dbSDimitry Andric // Call sites might be dead if they do not have side effects and no live
35335ffd83dbSDimitry Andric // users. The return value might be dead if there are no live users.
35341fd87a68SDimitry Andric getOrCreateAAFor<AAIsDead>(CBInstPos);
35355ffd83dbSDimitry Andric
353606c3fb27SDimitry Andric Function *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand());
35375ffd83dbSDimitry Andric // TODO: Even if the callee is not known now we might be able to simplify
35385ffd83dbSDimitry Andric // the call/callee.
35395f757f3fSDimitry Andric if (!Callee) {
35405f757f3fSDimitry Andric getOrCreateAAFor<AAIndirectCallInfo>(CBFnPos);
35415ffd83dbSDimitry Andric return true;
35425f757f3fSDimitry Andric }
35435ffd83dbSDimitry Andric
3544349cc55cSDimitry Andric // Every call site can track active assumptions.
3545349cc55cSDimitry Andric getOrCreateAAFor<AAAssumptionInfo>(CBFnPos);
3546349cc55cSDimitry Andric
35475ffd83dbSDimitry Andric // Skip declarations except if annotations on their call sites were
3548480093f4SDimitry Andric // explicitly requested.
3549480093f4SDimitry Andric if (!AnnotateDeclarationCallSites && Callee->isDeclaration() &&
3550480093f4SDimitry Andric !Callee->hasMetadata(LLVMContext::MD_callback))
3551480093f4SDimitry Andric return true;
3552480093f4SDimitry Andric
35535ffd83dbSDimitry Andric if (!Callee->getReturnType()->isVoidTy() && !CB.use_empty()) {
35545ffd83dbSDimitry Andric IRPosition CBRetPos = IRPosition::callsite_returned(CB);
355581ad6265SDimitry Andric bool UsedAssumedInformation = false;
3556fcaf7f86SDimitry Andric getAssumedSimplified(CBRetPos, nullptr, UsedAssumedInformation,
3557fcaf7f86SDimitry Andric AA::Intraprocedural);
355806c3fb27SDimitry Andric
355906c3fb27SDimitry Andric if (AttributeFuncs::isNoFPClassCompatibleType(Callee->getReturnType()))
356006c3fb27SDimitry Andric getOrCreateAAFor<AANoFPClass>(CBInstPos);
3561480093f4SDimitry Andric }
3562480093f4SDimitry Andric
356306c3fb27SDimitry Andric const AttributeList &CBAttrs = CBFnPos.getAttrList();
3564349cc55cSDimitry Andric for (int I = 0, E = CB.arg_size(); I < E; ++I) {
35658bcb0991SDimitry Andric
35665ffd83dbSDimitry Andric IRPosition CBArgPos = IRPosition::callsite_argument(CB, I);
356706c3fb27SDimitry Andric AttributeSet CBArgAttrs = CBAttrs.getParamAttrs(I);
35688bcb0991SDimitry Andric
3569480093f4SDimitry Andric // Every call site argument might be dead.
35705ffd83dbSDimitry Andric getOrCreateAAFor<AAIsDead>(CBArgPos);
3571480093f4SDimitry Andric
3572fe6060f1SDimitry Andric // Call site argument might be simplified. We have to go through the
3573fe6060f1SDimitry Andric // Attributor interface though as outside AAs can register custom
3574fe6060f1SDimitry Andric // simplification callbacks.
3575fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
3576fcaf7f86SDimitry Andric getAssumedSimplified(CBArgPos, /* AA */ nullptr, UsedAssumedInformation,
3577fcaf7f86SDimitry Andric AA::Intraprocedural);
35788bcb0991SDimitry Andric
3579e8d8bef9SDimitry Andric // Every call site argument might be marked "noundef".
358006c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoUndef, AANoUndef>(CBArgPos, CBArgAttrs);
3581e8d8bef9SDimitry Andric
358206c3fb27SDimitry Andric Type *ArgTy = CB.getArgOperand(I)->getType();
358306c3fb27SDimitry Andric
358406c3fb27SDimitry Andric if (!ArgTy->isPointerTy()) {
358506c3fb27SDimitry Andric if (AttributeFuncs::isNoFPClassCompatibleType(ArgTy))
358606c3fb27SDimitry Andric getOrCreateAAFor<AANoFPClass>(CBArgPos);
358706c3fb27SDimitry Andric
35880b57cec5SDimitry Andric continue;
358906c3fb27SDimitry Andric }
35900b57cec5SDimitry Andric
35910b57cec5SDimitry Andric // Call site argument attribute "non-null".
359206c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NonNull, AANonNull>(CBArgPos, CBArgAttrs);
35935ffd83dbSDimitry Andric
35945ffd83dbSDimitry Andric // Call site argument attribute "nocapture".
359506c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoCapture, AANoCapture>(CBArgPos,
359606c3fb27SDimitry Andric CBArgAttrs);
35978bcb0991SDimitry Andric
35988bcb0991SDimitry Andric // Call site argument attribute "no-alias".
359906c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoAlias, AANoAlias>(CBArgPos, CBArgAttrs);
36008bcb0991SDimitry Andric
36018bcb0991SDimitry Andric // Call site argument attribute "dereferenceable".
36025ffd83dbSDimitry Andric getOrCreateAAFor<AADereferenceable>(CBArgPos);
36038bcb0991SDimitry Andric
36048bcb0991SDimitry Andric // Call site argument attribute "align".
36055ffd83dbSDimitry Andric getOrCreateAAFor<AAAlign>(CBArgPos);
3606480093f4SDimitry Andric
3607480093f4SDimitry Andric // Call site argument attribute
3608480093f4SDimitry Andric // "readnone/readonly/writeonly/..."
360906c3fb27SDimitry Andric if (!CBAttrs.hasParamAttr(I, Attribute::ReadNone))
36105ffd83dbSDimitry Andric getOrCreateAAFor<AAMemoryBehavior>(CBArgPos);
3611480093f4SDimitry Andric
3612480093f4SDimitry Andric // Call site argument attribute "nofree".
361306c3fb27SDimitry Andric checkAndQueryIRAttr<Attribute::NoFree, AANoFree>(CBArgPos, CBArgAttrs);
36140b57cec5SDimitry Andric }
36158bcb0991SDimitry Andric return true;
36168bcb0991SDimitry Andric };
36178bcb0991SDimitry Andric
36188bcb0991SDimitry Andric auto &OpcodeInstMap = InfoCache.getOpcodeInstMapForFunction(F);
36195f757f3fSDimitry Andric [[maybe_unused]] bool Success;
3620fe6060f1SDimitry Andric bool UsedAssumedInformation = false;
36218bcb0991SDimitry Andric Success = checkForAllInstructionsImpl(
36225ffd83dbSDimitry Andric nullptr, OpcodeInstMap, CallSitePred, nullptr, nullptr,
36238bcb0991SDimitry Andric {(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,
3624fe6060f1SDimitry Andric (unsigned)Instruction::Call},
3625fe6060f1SDimitry Andric UsedAssumedInformation);
36265ffd83dbSDimitry Andric assert(Success && "Expected the check call to be successful!");
36278bcb0991SDimitry Andric
36288bcb0991SDimitry Andric auto LoadStorePred = [&](Instruction &I) -> bool {
362906c3fb27SDimitry Andric if (auto *LI = dyn_cast<LoadInst>(&I)) {
363006c3fb27SDimitry Andric getOrCreateAAFor<AAAlign>(IRPosition::value(*LI->getPointerOperand()));
3631fe6060f1SDimitry Andric if (SimplifyAllLoads)
363281ad6265SDimitry Andric getAssumedSimplified(IRPosition::value(I), nullptr,
3633fcaf7f86SDimitry Andric UsedAssumedInformation, AA::Intraprocedural);
363406c3fb27SDimitry Andric getOrCreateAAFor<AAAddressSpace>(
363506c3fb27SDimitry Andric IRPosition::value(*LI->getPointerOperand()));
363681ad6265SDimitry Andric } else {
363781ad6265SDimitry Andric auto &SI = cast<StoreInst>(I);
363881ad6265SDimitry Andric getOrCreateAAFor<AAIsDead>(IRPosition::inst(I));
363981ad6265SDimitry Andric getAssumedSimplified(IRPosition::value(*SI.getValueOperand()), nullptr,
3640fcaf7f86SDimitry Andric UsedAssumedInformation, AA::Intraprocedural);
364181ad6265SDimitry Andric getOrCreateAAFor<AAAlign>(IRPosition::value(*SI.getPointerOperand()));
364206c3fb27SDimitry Andric getOrCreateAAFor<AAAddressSpace>(
364306c3fb27SDimitry Andric IRPosition::value(*SI.getPointerOperand()));
364481ad6265SDimitry Andric }
36458bcb0991SDimitry Andric return true;
36468bcb0991SDimitry Andric };
36478bcb0991SDimitry Andric Success = checkForAllInstructionsImpl(
36485ffd83dbSDimitry Andric nullptr, OpcodeInstMap, LoadStorePred, nullptr, nullptr,
3649fe6060f1SDimitry Andric {(unsigned)Instruction::Load, (unsigned)Instruction::Store},
3650fe6060f1SDimitry Andric UsedAssumedInformation);
36515ffd83dbSDimitry Andric assert(Success && "Expected the check call to be successful!");
36525f757f3fSDimitry Andric
36535f757f3fSDimitry Andric // AllocaInstPredicate
36545f757f3fSDimitry Andric auto AAAllocationInfoPred = [&](Instruction &I) -> bool {
36555f757f3fSDimitry Andric getOrCreateAAFor<AAAllocationInfo>(IRPosition::value(I));
36565f757f3fSDimitry Andric return true;
36575f757f3fSDimitry Andric };
36585f757f3fSDimitry Andric
36595f757f3fSDimitry Andric Success = checkForAllInstructionsImpl(
36605f757f3fSDimitry Andric nullptr, OpcodeInstMap, AAAllocationInfoPred, nullptr, nullptr,
36615f757f3fSDimitry Andric {(unsigned)Instruction::Alloca}, UsedAssumedInformation);
36625f757f3fSDimitry Andric assert(Success && "Expected the check call to be successful!");
36635f757f3fSDimitry Andric }
36645f757f3fSDimitry Andric
isClosedWorldModule() const36655f757f3fSDimitry Andric bool Attributor::isClosedWorldModule() const {
36665f757f3fSDimitry Andric if (CloseWorldAssumption.getNumOccurrences())
36675f757f3fSDimitry Andric return CloseWorldAssumption;
36685f757f3fSDimitry Andric return isModulePass() && Configuration.IsClosedWorldModule;
36690b57cec5SDimitry Andric }
36700b57cec5SDimitry Andric
36710b57cec5SDimitry Andric /// Helpers to ease debugging through output streams and print calls.
36720b57cec5SDimitry Andric ///
36730b57cec5SDimitry Andric ///{
operator <<(raw_ostream & OS,ChangeStatus S)36740b57cec5SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, ChangeStatus S) {
36750b57cec5SDimitry Andric return OS << (S == ChangeStatus::CHANGED ? "changed" : "unchanged");
36760b57cec5SDimitry Andric }
36770b57cec5SDimitry Andric
operator <<(raw_ostream & OS,IRPosition::Kind AP)36788bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, IRPosition::Kind AP) {
36790b57cec5SDimitry Andric switch (AP) {
36808bcb0991SDimitry Andric case IRPosition::IRP_INVALID:
36818bcb0991SDimitry Andric return OS << "inv";
36828bcb0991SDimitry Andric case IRPosition::IRP_FLOAT:
36838bcb0991SDimitry Andric return OS << "flt";
36848bcb0991SDimitry Andric case IRPosition::IRP_RETURNED:
36850b57cec5SDimitry Andric return OS << "fn_ret";
36868bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE_RETURNED:
36878bcb0991SDimitry Andric return OS << "cs_ret";
36888bcb0991SDimitry Andric case IRPosition::IRP_FUNCTION:
36898bcb0991SDimitry Andric return OS << "fn";
36908bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE:
36918bcb0991SDimitry Andric return OS << "cs";
36928bcb0991SDimitry Andric case IRPosition::IRP_ARGUMENT:
36938bcb0991SDimitry Andric return OS << "arg";
36948bcb0991SDimitry Andric case IRPosition::IRP_CALL_SITE_ARGUMENT:
36958bcb0991SDimitry Andric return OS << "cs_arg";
36960b57cec5SDimitry Andric }
36970b57cec5SDimitry Andric llvm_unreachable("Unknown attribute position!");
36980b57cec5SDimitry Andric }
36990b57cec5SDimitry Andric
operator <<(raw_ostream & OS,const IRPosition & Pos)37008bcb0991SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const IRPosition &Pos) {
37018bcb0991SDimitry Andric const Value &AV = Pos.getAssociatedValue();
3702fe6060f1SDimitry Andric OS << "{" << Pos.getPositionKind() << ":" << AV.getName() << " ["
3703fe6060f1SDimitry Andric << Pos.getAnchorValue().getName() << "@" << Pos.getCallSiteArgNo() << "]";
3704fe6060f1SDimitry Andric
3705fe6060f1SDimitry Andric if (Pos.hasCallBaseContext())
3706fe6060f1SDimitry Andric OS << "[cb_context:" << *Pos.getCallBaseContext() << "]";
3707fe6060f1SDimitry Andric return OS << "}";
37088bcb0991SDimitry Andric }
37098bcb0991SDimitry Andric
operator <<(raw_ostream & OS,const IntegerRangeState & S)3710480093f4SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const IntegerRangeState &S) {
3711480093f4SDimitry Andric OS << "range-state(" << S.getBitWidth() << ")<";
3712480093f4SDimitry Andric S.getKnown().print(OS);
3713480093f4SDimitry Andric OS << " / ";
3714480093f4SDimitry Andric S.getAssumed().print(OS);
3715480093f4SDimitry Andric OS << ">";
3716480093f4SDimitry Andric
3717480093f4SDimitry Andric return OS << static_cast<const AbstractState &>(S);
3718480093f4SDimitry Andric }
3719480093f4SDimitry Andric
operator <<(raw_ostream & OS,const AbstractState & S)37200b57cec5SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractState &S) {
37210b57cec5SDimitry Andric return OS << (!S.isValidState() ? "top" : (S.isAtFixpoint() ? "fix" : ""));
37220b57cec5SDimitry Andric }
37230b57cec5SDimitry Andric
operator <<(raw_ostream & OS,const AbstractAttribute & AA)37240b57cec5SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS, const AbstractAttribute &AA) {
37250b57cec5SDimitry Andric AA.print(OS);
37260b57cec5SDimitry Andric return OS;
37270b57cec5SDimitry Andric }
37280b57cec5SDimitry Andric
operator <<(raw_ostream & OS,const PotentialConstantIntValuesState & S)3729e8d8bef9SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS,
3730e8d8bef9SDimitry Andric const PotentialConstantIntValuesState &S) {
3731e8d8bef9SDimitry Andric OS << "set-state(< {";
3732e8d8bef9SDimitry Andric if (!S.isValidState())
3733e8d8bef9SDimitry Andric OS << "full-set";
3734e8d8bef9SDimitry Andric else {
3735bdd1243dSDimitry Andric for (const auto &It : S.getAssumedSet())
373681ad6265SDimitry Andric OS << It << ", ";
3737e8d8bef9SDimitry Andric if (S.undefIsContained())
3738e8d8bef9SDimitry Andric OS << "undef ";
3739e8d8bef9SDimitry Andric }
3740e8d8bef9SDimitry Andric OS << "} >)";
3741e8d8bef9SDimitry Andric
3742e8d8bef9SDimitry Andric return OS;
3743e8d8bef9SDimitry Andric }
3744e8d8bef9SDimitry Andric
operator <<(raw_ostream & OS,const PotentialLLVMValuesState & S)3745fcaf7f86SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS,
3746fcaf7f86SDimitry Andric const PotentialLLVMValuesState &S) {
3747fcaf7f86SDimitry Andric OS << "set-state(< {";
3748fcaf7f86SDimitry Andric if (!S.isValidState())
3749fcaf7f86SDimitry Andric OS << "full-set";
3750fcaf7f86SDimitry Andric else {
3751bdd1243dSDimitry Andric for (const auto &It : S.getAssumedSet()) {
3752fcaf7f86SDimitry Andric if (auto *F = dyn_cast<Function>(It.first.getValue()))
3753fcaf7f86SDimitry Andric OS << "@" << F->getName() << "[" << int(It.second) << "], ";
3754fcaf7f86SDimitry Andric else
3755fcaf7f86SDimitry Andric OS << *It.first.getValue() << "[" << int(It.second) << "], ";
3756fcaf7f86SDimitry Andric }
3757fcaf7f86SDimitry Andric if (S.undefIsContained())
3758fcaf7f86SDimitry Andric OS << "undef ";
3759fcaf7f86SDimitry Andric }
3760fcaf7f86SDimitry Andric OS << "} >)";
3761fcaf7f86SDimitry Andric
3762fcaf7f86SDimitry Andric return OS;
3763fcaf7f86SDimitry Andric }
3764fcaf7f86SDimitry Andric
print(Attributor * A,raw_ostream & OS) const376506c3fb27SDimitry Andric void AbstractAttribute::print(Attributor *A, raw_ostream &OS) const {
3766e8d8bef9SDimitry Andric OS << "[";
3767e8d8bef9SDimitry Andric OS << getName();
3768e8d8bef9SDimitry Andric OS << "] for CtxI ";
3769e8d8bef9SDimitry Andric
3770e8d8bef9SDimitry Andric if (auto *I = getCtxI()) {
3771e8d8bef9SDimitry Andric OS << "'";
3772e8d8bef9SDimitry Andric I->print(OS);
3773e8d8bef9SDimitry Andric OS << "'";
3774e8d8bef9SDimitry Andric } else
3775e8d8bef9SDimitry Andric OS << "<<null inst>>";
3776e8d8bef9SDimitry Andric
377706c3fb27SDimitry Andric OS << " at position " << getIRPosition() << " with state " << getAsStr(A)
3778e8d8bef9SDimitry Andric << '\n';
3779e8d8bef9SDimitry Andric }
3780e8d8bef9SDimitry Andric
printWithDeps(raw_ostream & OS) const3781e8d8bef9SDimitry Andric void AbstractAttribute::printWithDeps(raw_ostream &OS) const {
3782e8d8bef9SDimitry Andric print(OS);
3783e8d8bef9SDimitry Andric
3784e8d8bef9SDimitry Andric for (const auto &DepAA : Deps) {
3785e8d8bef9SDimitry Andric auto *AA = DepAA.getPointer();
3786e8d8bef9SDimitry Andric OS << " updates ";
3787e8d8bef9SDimitry Andric AA->print(OS);
3788e8d8bef9SDimitry Andric }
3789e8d8bef9SDimitry Andric
3790e8d8bef9SDimitry Andric OS << '\n';
37910b57cec5SDimitry Andric }
3792fe6060f1SDimitry Andric
operator <<(raw_ostream & OS,const AAPointerInfo::Access & Acc)3793fe6060f1SDimitry Andric raw_ostream &llvm::operator<<(raw_ostream &OS,
3794fe6060f1SDimitry Andric const AAPointerInfo::Access &Acc) {
3795fe6060f1SDimitry Andric OS << " [" << Acc.getKind() << "] " << *Acc.getRemoteInst();
3796fe6060f1SDimitry Andric if (Acc.getLocalInst() != Acc.getRemoteInst())
3797fe6060f1SDimitry Andric OS << " via " << *Acc.getLocalInst();
379881ad6265SDimitry Andric if (Acc.getContent()) {
379981ad6265SDimitry Andric if (*Acc.getContent())
380081ad6265SDimitry Andric OS << " [" << **Acc.getContent() << "]";
380181ad6265SDimitry Andric else
380281ad6265SDimitry Andric OS << " [ <unknown> ]";
380381ad6265SDimitry Andric }
3804fe6060f1SDimitry Andric return OS;
3805fe6060f1SDimitry Andric }
38060b57cec5SDimitry Andric ///}
38070b57cec5SDimitry Andric
38080b57cec5SDimitry Andric /// ----------------------------------------------------------------------------
38090b57cec5SDimitry Andric /// Pass (Manager) Boilerplate
38100b57cec5SDimitry Andric /// ----------------------------------------------------------------------------
38110b57cec5SDimitry Andric
runAttributorOnFunctions(InformationCache & InfoCache,SetVector<Function * > & Functions,AnalysisGetter & AG,CallGraphUpdater & CGUpdater,bool DeleteFns,bool IsModulePass)38125ffd83dbSDimitry Andric static bool runAttributorOnFunctions(InformationCache &InfoCache,
38135ffd83dbSDimitry Andric SetVector<Function *> &Functions,
38145ffd83dbSDimitry Andric AnalysisGetter &AG,
3815fe6060f1SDimitry Andric CallGraphUpdater &CGUpdater,
381681ad6265SDimitry Andric bool DeleteFns, bool IsModulePass) {
38175ffd83dbSDimitry Andric if (Functions.empty())
38180b57cec5SDimitry Andric return false;
38190b57cec5SDimitry Andric
3820fe6060f1SDimitry Andric LLVM_DEBUG({
3821fe6060f1SDimitry Andric dbgs() << "[Attributor] Run on module with " << Functions.size()
3822fe6060f1SDimitry Andric << " functions:\n";
3823fe6060f1SDimitry Andric for (Function *Fn : Functions)
3824fe6060f1SDimitry Andric dbgs() << " - " << Fn->getName() << "\n";
3825fe6060f1SDimitry Andric });
38260b57cec5SDimitry Andric
38270b57cec5SDimitry Andric // Create an Attributor and initially empty information cache that is filled
38280b57cec5SDimitry Andric // while we identify default attribute opportunities.
382981ad6265SDimitry Andric AttributorConfig AC(CGUpdater);
383081ad6265SDimitry Andric AC.IsModulePass = IsModulePass;
383181ad6265SDimitry Andric AC.DeleteFns = DeleteFns;
38325f757f3fSDimitry Andric
38335f757f3fSDimitry Andric /// Tracking callback for specialization of indirect calls.
38345f757f3fSDimitry Andric DenseMap<CallBase *, std::unique_ptr<SmallPtrSet<Function *, 8>>>
38355f757f3fSDimitry Andric IndirectCalleeTrackingMap;
38365f757f3fSDimitry Andric if (MaxSpecializationPerCB.getNumOccurrences()) {
38375f757f3fSDimitry Andric AC.IndirectCalleeSpecializationCallback =
38385f757f3fSDimitry Andric [&](Attributor &, const AbstractAttribute &AA, CallBase &CB,
38395f757f3fSDimitry Andric Function &Callee) {
38405f757f3fSDimitry Andric if (MaxSpecializationPerCB == 0)
38415f757f3fSDimitry Andric return false;
38425f757f3fSDimitry Andric auto &Set = IndirectCalleeTrackingMap[&CB];
38435f757f3fSDimitry Andric if (!Set)
38445f757f3fSDimitry Andric Set = std::make_unique<SmallPtrSet<Function *, 8>>();
38455f757f3fSDimitry Andric if (Set->size() >= MaxSpecializationPerCB)
38465f757f3fSDimitry Andric return Set->contains(&Callee);
38475f757f3fSDimitry Andric Set->insert(&Callee);
38485f757f3fSDimitry Andric return true;
38495f757f3fSDimitry Andric };
38505f757f3fSDimitry Andric }
38515f757f3fSDimitry Andric
385281ad6265SDimitry Andric Attributor A(Functions, InfoCache, AC);
38538bcb0991SDimitry Andric
38545ffd83dbSDimitry Andric // Create shallow wrappers for all functions that are not IPO amendable
38555ffd83dbSDimitry Andric if (AllowShallowWrappers)
38565ffd83dbSDimitry Andric for (Function *F : Functions)
38575ffd83dbSDimitry Andric if (!A.isFunctionIPOAmendable(*F))
3858e8d8bef9SDimitry Andric Attributor::createShallowWrapper(*F);
3859e8d8bef9SDimitry Andric
3860e8d8bef9SDimitry Andric // Internalize non-exact functions
3861e8d8bef9SDimitry Andric // TODO: for now we eagerly internalize functions without calculating the
3862e8d8bef9SDimitry Andric // cost, we need a cost interface to determine whether internalizing
3863bdd1243dSDimitry Andric // a function is "beneficial"
3864e8d8bef9SDimitry Andric if (AllowDeepWrapper) {
3865e8d8bef9SDimitry Andric unsigned FunSize = Functions.size();
3866e8d8bef9SDimitry Andric for (unsigned u = 0; u < FunSize; u++) {
3867e8d8bef9SDimitry Andric Function *F = Functions[u];
3868e8d8bef9SDimitry Andric if (!F->isDeclaration() && !F->isDefinitionExact() && F->getNumUses() &&
3869e8d8bef9SDimitry Andric !GlobalValue::isInterposableLinkage(F->getLinkage())) {
3870fe6060f1SDimitry Andric Function *NewF = Attributor::internalizeFunction(*F);
3871fe6060f1SDimitry Andric assert(NewF && "Could not internalize function.");
3872e8d8bef9SDimitry Andric Functions.insert(NewF);
3873e8d8bef9SDimitry Andric
3874e8d8bef9SDimitry Andric // Update call graph
3875e8d8bef9SDimitry Andric CGUpdater.replaceFunctionWith(*F, *NewF);
3876e8d8bef9SDimitry Andric for (const Use &U : NewF->uses())
3877e8d8bef9SDimitry Andric if (CallBase *CB = dyn_cast<CallBase>(U.getUser())) {
3878e8d8bef9SDimitry Andric auto *CallerF = CB->getCaller();
3879e8d8bef9SDimitry Andric CGUpdater.reanalyzeFunction(*CallerF);
3880e8d8bef9SDimitry Andric }
3881e8d8bef9SDimitry Andric }
3882e8d8bef9SDimitry Andric }
3883e8d8bef9SDimitry Andric }
38840b57cec5SDimitry Andric
38855ffd83dbSDimitry Andric for (Function *F : Functions) {
38865ffd83dbSDimitry Andric if (F->hasExactDefinition())
38878bcb0991SDimitry Andric NumFnWithExactDefinition++;
38888bcb0991SDimitry Andric else
38890b57cec5SDimitry Andric NumFnWithoutExactDefinition++;
38908bcb0991SDimitry Andric
38918bcb0991SDimitry Andric // We look at internal functions only on-demand but if any use is not a
3892e8d8bef9SDimitry Andric // direct call or outside the current set of analyzed functions, we have
3893e8d8bef9SDimitry Andric // to do it eagerly.
38945ffd83dbSDimitry Andric if (F->hasLocalLinkage()) {
38955ffd83dbSDimitry Andric if (llvm::all_of(F->uses(), [&Functions](const Use &U) {
38965ffd83dbSDimitry Andric const auto *CB = dyn_cast<CallBase>(U.getUser());
38975ffd83dbSDimitry Andric return CB && CB->isCallee(&U) &&
38985ffd83dbSDimitry Andric Functions.count(const_cast<Function *>(CB->getCaller()));
38998bcb0991SDimitry Andric }))
39000b57cec5SDimitry Andric continue;
39010b57cec5SDimitry Andric }
39020b57cec5SDimitry Andric
39030b57cec5SDimitry Andric // Populate the Attributor with abstract attribute opportunities in the
39040b57cec5SDimitry Andric // function and the information cache with IR information.
39055ffd83dbSDimitry Andric A.identifyDefaultAbstractAttributes(*F);
39060b57cec5SDimitry Andric }
39070b57cec5SDimitry Andric
39085ffd83dbSDimitry Andric ChangeStatus Changed = A.run();
3909e8d8bef9SDimitry Andric
39105ffd83dbSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size()
39115ffd83dbSDimitry Andric << " functions, result: " << Changed << ".\n");
39125ffd83dbSDimitry Andric return Changed == ChangeStatus::CHANGED;
39130b57cec5SDimitry Andric }
39140b57cec5SDimitry Andric
runAttributorLightOnFunctions(InformationCache & InfoCache,SetVector<Function * > & Functions,AnalysisGetter & AG,CallGraphUpdater & CGUpdater,FunctionAnalysisManager & FAM,bool IsModulePass)39155f757f3fSDimitry Andric static bool runAttributorLightOnFunctions(InformationCache &InfoCache,
39165f757f3fSDimitry Andric SetVector<Function *> &Functions,
39175f757f3fSDimitry Andric AnalysisGetter &AG,
39185f757f3fSDimitry Andric CallGraphUpdater &CGUpdater,
39195f757f3fSDimitry Andric FunctionAnalysisManager &FAM,
39205f757f3fSDimitry Andric bool IsModulePass) {
39215f757f3fSDimitry Andric if (Functions.empty())
39225f757f3fSDimitry Andric return false;
39235f757f3fSDimitry Andric
39245f757f3fSDimitry Andric LLVM_DEBUG({
39255f757f3fSDimitry Andric dbgs() << "[AttributorLight] Run on module with " << Functions.size()
39265f757f3fSDimitry Andric << " functions:\n";
39275f757f3fSDimitry Andric for (Function *Fn : Functions)
39285f757f3fSDimitry Andric dbgs() << " - " << Fn->getName() << "\n";
39295f757f3fSDimitry Andric });
39305f757f3fSDimitry Andric
39315f757f3fSDimitry Andric // Create an Attributor and initially empty information cache that is filled
39325f757f3fSDimitry Andric // while we identify default attribute opportunities.
39335f757f3fSDimitry Andric AttributorConfig AC(CGUpdater);
39345f757f3fSDimitry Andric AC.IsModulePass = IsModulePass;
39355f757f3fSDimitry Andric AC.DeleteFns = false;
39365f757f3fSDimitry Andric DenseSet<const char *> Allowed(
39375f757f3fSDimitry Andric {&AAWillReturn::ID, &AANoUnwind::ID, &AANoRecurse::ID, &AANoSync::ID,
39385f757f3fSDimitry Andric &AANoFree::ID, &AANoReturn::ID, &AAMemoryLocation::ID,
39395f757f3fSDimitry Andric &AAMemoryBehavior::ID, &AAUnderlyingObjects::ID, &AANoCapture::ID,
39405f757f3fSDimitry Andric &AAInterFnReachability::ID, &AAIntraFnReachability::ID, &AACallEdges::ID,
39415f757f3fSDimitry Andric &AANoFPClass::ID, &AAMustProgress::ID, &AANonNull::ID});
39425f757f3fSDimitry Andric AC.Allowed = &Allowed;
39435f757f3fSDimitry Andric AC.UseLiveness = false;
39445f757f3fSDimitry Andric
39455f757f3fSDimitry Andric Attributor A(Functions, InfoCache, AC);
39465f757f3fSDimitry Andric
39475f757f3fSDimitry Andric for (Function *F : Functions) {
39485f757f3fSDimitry Andric if (F->hasExactDefinition())
39495f757f3fSDimitry Andric NumFnWithExactDefinition++;
39505f757f3fSDimitry Andric else
39515f757f3fSDimitry Andric NumFnWithoutExactDefinition++;
39525f757f3fSDimitry Andric
39535f757f3fSDimitry Andric // We look at internal functions only on-demand but if any use is not a
39545f757f3fSDimitry Andric // direct call or outside the current set of analyzed functions, we have
39555f757f3fSDimitry Andric // to do it eagerly.
3956*0fca6ea1SDimitry Andric if (AC.UseLiveness && F->hasLocalLinkage()) {
39575f757f3fSDimitry Andric if (llvm::all_of(F->uses(), [&Functions](const Use &U) {
39585f757f3fSDimitry Andric const auto *CB = dyn_cast<CallBase>(U.getUser());
39595f757f3fSDimitry Andric return CB && CB->isCallee(&U) &&
39605f757f3fSDimitry Andric Functions.count(const_cast<Function *>(CB->getCaller()));
39615f757f3fSDimitry Andric }))
39625f757f3fSDimitry Andric continue;
39635f757f3fSDimitry Andric }
39645f757f3fSDimitry Andric
39655f757f3fSDimitry Andric // Populate the Attributor with abstract attribute opportunities in the
39665f757f3fSDimitry Andric // function and the information cache with IR information.
39675f757f3fSDimitry Andric A.identifyDefaultAbstractAttributes(*F);
39685f757f3fSDimitry Andric }
39695f757f3fSDimitry Andric
39705f757f3fSDimitry Andric ChangeStatus Changed = A.run();
39715f757f3fSDimitry Andric
39725f757f3fSDimitry Andric if (Changed == ChangeStatus::CHANGED) {
39735f757f3fSDimitry Andric // Invalidate analyses for modified functions so that we don't have to
39745f757f3fSDimitry Andric // invalidate all analyses for all functions in this SCC.
39755f757f3fSDimitry Andric PreservedAnalyses FuncPA;
39765f757f3fSDimitry Andric // We haven't changed the CFG for modified functions.
39775f757f3fSDimitry Andric FuncPA.preserveSet<CFGAnalyses>();
39785f757f3fSDimitry Andric for (Function *Changed : A.getModifiedFunctions()) {
39795f757f3fSDimitry Andric FAM.invalidate(*Changed, FuncPA);
39805f757f3fSDimitry Andric // Also invalidate any direct callers of changed functions since analyses
39815f757f3fSDimitry Andric // may care about attributes of direct callees. For example, MemorySSA
39825f757f3fSDimitry Andric // cares about whether or not a call's callee modifies memory and queries
39835f757f3fSDimitry Andric // that through function attributes.
39845f757f3fSDimitry Andric for (auto *U : Changed->users()) {
39855f757f3fSDimitry Andric if (auto *Call = dyn_cast<CallBase>(U)) {
39865f757f3fSDimitry Andric if (Call->getCalledFunction() == Changed)
39875f757f3fSDimitry Andric FAM.invalidate(*Call->getFunction(), FuncPA);
39885f757f3fSDimitry Andric }
39895f757f3fSDimitry Andric }
39905f757f3fSDimitry Andric }
39915f757f3fSDimitry Andric }
39925f757f3fSDimitry Andric LLVM_DEBUG(dbgs() << "[Attributor] Done with " << Functions.size()
39935f757f3fSDimitry Andric << " functions, result: " << Changed << ".\n");
39945f757f3fSDimitry Andric return Changed == ChangeStatus::CHANGED;
39955f757f3fSDimitry Andric }
39965f757f3fSDimitry Andric
viewGraph()3997e8d8bef9SDimitry Andric void AADepGraph::viewGraph() { llvm::ViewGraph(this, "Dependency Graph"); }
3998e8d8bef9SDimitry Andric
dumpGraph()3999e8d8bef9SDimitry Andric void AADepGraph::dumpGraph() {
4000e8d8bef9SDimitry Andric static std::atomic<int> CallTimes;
4001e8d8bef9SDimitry Andric std::string Prefix;
4002e8d8bef9SDimitry Andric
4003e8d8bef9SDimitry Andric if (!DepGraphDotFileNamePrefix.empty())
4004e8d8bef9SDimitry Andric Prefix = DepGraphDotFileNamePrefix;
4005e8d8bef9SDimitry Andric else
4006e8d8bef9SDimitry Andric Prefix = "dep_graph";
4007e8d8bef9SDimitry Andric std::string Filename =
4008e8d8bef9SDimitry Andric Prefix + "_" + std::to_string(CallTimes.load()) + ".dot";
4009e8d8bef9SDimitry Andric
4010e8d8bef9SDimitry Andric outs() << "Dependency graph dump to " << Filename << ".\n";
4011e8d8bef9SDimitry Andric
4012e8d8bef9SDimitry Andric std::error_code EC;
4013e8d8bef9SDimitry Andric
4014fe6060f1SDimitry Andric raw_fd_ostream File(Filename, EC, sys::fs::OF_TextWithCRLF);
4015e8d8bef9SDimitry Andric if (!EC)
4016e8d8bef9SDimitry Andric llvm::WriteGraph(File, this);
4017e8d8bef9SDimitry Andric
4018e8d8bef9SDimitry Andric CallTimes++;
4019e8d8bef9SDimitry Andric }
4020e8d8bef9SDimitry Andric
print()4021e8d8bef9SDimitry Andric void AADepGraph::print() {
4022e8d8bef9SDimitry Andric for (auto DepAA : SyntheticRoot.Deps)
4023e8d8bef9SDimitry Andric cast<AbstractAttribute>(DepAA.getPointer())->printWithDeps(outs());
4024e8d8bef9SDimitry Andric }
4025e8d8bef9SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)40260b57cec5SDimitry Andric PreservedAnalyses AttributorPass::run(Module &M, ModuleAnalysisManager &AM) {
40275ffd83dbSDimitry Andric FunctionAnalysisManager &FAM =
40285ffd83dbSDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
40295ffd83dbSDimitry Andric AnalysisGetter AG(FAM);
40305ffd83dbSDimitry Andric
40315ffd83dbSDimitry Andric SetVector<Function *> Functions;
40325ffd83dbSDimitry Andric for (Function &F : M)
40335ffd83dbSDimitry Andric Functions.insert(&F);
40345ffd83dbSDimitry Andric
40355ffd83dbSDimitry Andric CallGraphUpdater CGUpdater;
40365ffd83dbSDimitry Andric BumpPtrAllocator Allocator;
40375ffd83dbSDimitry Andric InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr);
4038fe6060f1SDimitry Andric if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
403981ad6265SDimitry Andric /* DeleteFns */ true, /* IsModulePass */ true)) {
40405ffd83dbSDimitry Andric // FIXME: Think about passes we will preserve and add them here.
40415ffd83dbSDimitry Andric return PreservedAnalyses::none();
40425ffd83dbSDimitry Andric }
40435ffd83dbSDimitry Andric return PreservedAnalyses::all();
40445ffd83dbSDimitry Andric }
40455ffd83dbSDimitry Andric
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM,LazyCallGraph & CG,CGSCCUpdateResult & UR)40465ffd83dbSDimitry Andric PreservedAnalyses AttributorCGSCCPass::run(LazyCallGraph::SCC &C,
40475ffd83dbSDimitry Andric CGSCCAnalysisManager &AM,
40485ffd83dbSDimitry Andric LazyCallGraph &CG,
40495ffd83dbSDimitry Andric CGSCCUpdateResult &UR) {
40505ffd83dbSDimitry Andric FunctionAnalysisManager &FAM =
40515ffd83dbSDimitry Andric AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
40525ffd83dbSDimitry Andric AnalysisGetter AG(FAM);
40535ffd83dbSDimitry Andric
40545ffd83dbSDimitry Andric SetVector<Function *> Functions;
40555ffd83dbSDimitry Andric for (LazyCallGraph::Node &N : C)
40565ffd83dbSDimitry Andric Functions.insert(&N.getFunction());
40575ffd83dbSDimitry Andric
40585ffd83dbSDimitry Andric if (Functions.empty())
40595ffd83dbSDimitry Andric return PreservedAnalyses::all();
40605ffd83dbSDimitry Andric
40615ffd83dbSDimitry Andric Module &M = *Functions.back()->getParent();
40625ffd83dbSDimitry Andric CallGraphUpdater CGUpdater;
40635ffd83dbSDimitry Andric CGUpdater.initialize(CG, C, AM, UR);
40645ffd83dbSDimitry Andric BumpPtrAllocator Allocator;
40655ffd83dbSDimitry Andric InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions);
4066fe6060f1SDimitry Andric if (runAttributorOnFunctions(InfoCache, Functions, AG, CGUpdater,
406781ad6265SDimitry Andric /* DeleteFns */ false,
406881ad6265SDimitry Andric /* IsModulePass */ false)) {
40690b57cec5SDimitry Andric // FIXME: Think about passes we will preserve and add them here.
4070e8d8bef9SDimitry Andric PreservedAnalyses PA;
4071e8d8bef9SDimitry Andric PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
4072e8d8bef9SDimitry Andric return PA;
40730b57cec5SDimitry Andric }
40740b57cec5SDimitry Andric return PreservedAnalyses::all();
40750b57cec5SDimitry Andric }
40760b57cec5SDimitry Andric
run(Module & M,ModuleAnalysisManager & AM)40775f757f3fSDimitry Andric PreservedAnalyses AttributorLightPass::run(Module &M,
40785f757f3fSDimitry Andric ModuleAnalysisManager &AM) {
40795f757f3fSDimitry Andric FunctionAnalysisManager &FAM =
40805f757f3fSDimitry Andric AM.getResult<FunctionAnalysisManagerModuleProxy>(M).getManager();
40815f757f3fSDimitry Andric AnalysisGetter AG(FAM, /* CachedOnly */ true);
40825f757f3fSDimitry Andric
40835f757f3fSDimitry Andric SetVector<Function *> Functions;
40845f757f3fSDimitry Andric for (Function &F : M)
40855f757f3fSDimitry Andric Functions.insert(&F);
40865f757f3fSDimitry Andric
40875f757f3fSDimitry Andric CallGraphUpdater CGUpdater;
40885f757f3fSDimitry Andric BumpPtrAllocator Allocator;
40895f757f3fSDimitry Andric InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ nullptr);
40905f757f3fSDimitry Andric if (runAttributorLightOnFunctions(InfoCache, Functions, AG, CGUpdater, FAM,
40915f757f3fSDimitry Andric /* IsModulePass */ true)) {
40925f757f3fSDimitry Andric PreservedAnalyses PA;
40935f757f3fSDimitry Andric // We have not added or removed functions.
40945f757f3fSDimitry Andric PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
40955f757f3fSDimitry Andric // We already invalidated all relevant function analyses above.
40965f757f3fSDimitry Andric PA.preserveSet<AllAnalysesOn<Function>>();
40975f757f3fSDimitry Andric return PA;
40985f757f3fSDimitry Andric }
40995f757f3fSDimitry Andric return PreservedAnalyses::all();
41005f757f3fSDimitry Andric }
41015f757f3fSDimitry Andric
run(LazyCallGraph::SCC & C,CGSCCAnalysisManager & AM,LazyCallGraph & CG,CGSCCUpdateResult & UR)41025f757f3fSDimitry Andric PreservedAnalyses AttributorLightCGSCCPass::run(LazyCallGraph::SCC &C,
41035f757f3fSDimitry Andric CGSCCAnalysisManager &AM,
41045f757f3fSDimitry Andric LazyCallGraph &CG,
41055f757f3fSDimitry Andric CGSCCUpdateResult &UR) {
41065f757f3fSDimitry Andric FunctionAnalysisManager &FAM =
41075f757f3fSDimitry Andric AM.getResult<FunctionAnalysisManagerCGSCCProxy>(C, CG).getManager();
41085f757f3fSDimitry Andric AnalysisGetter AG(FAM);
41095f757f3fSDimitry Andric
41105f757f3fSDimitry Andric SetVector<Function *> Functions;
41115f757f3fSDimitry Andric for (LazyCallGraph::Node &N : C)
41125f757f3fSDimitry Andric Functions.insert(&N.getFunction());
41135f757f3fSDimitry Andric
41145f757f3fSDimitry Andric if (Functions.empty())
41155f757f3fSDimitry Andric return PreservedAnalyses::all();
41165f757f3fSDimitry Andric
41175f757f3fSDimitry Andric Module &M = *Functions.back()->getParent();
41185f757f3fSDimitry Andric CallGraphUpdater CGUpdater;
41195f757f3fSDimitry Andric CGUpdater.initialize(CG, C, AM, UR);
41205f757f3fSDimitry Andric BumpPtrAllocator Allocator;
41215f757f3fSDimitry Andric InformationCache InfoCache(M, AG, Allocator, /* CGSCC */ &Functions);
41225f757f3fSDimitry Andric if (runAttributorLightOnFunctions(InfoCache, Functions, AG, CGUpdater, FAM,
41235f757f3fSDimitry Andric /* IsModulePass */ false)) {
41245f757f3fSDimitry Andric PreservedAnalyses PA;
41255f757f3fSDimitry Andric // We have not added or removed functions.
41265f757f3fSDimitry Andric PA.preserve<FunctionAnalysisManagerCGSCCProxy>();
41275f757f3fSDimitry Andric // We already invalidated all relevant function analyses above.
41285f757f3fSDimitry Andric PA.preserveSet<AllAnalysesOn<Function>>();
41295f757f3fSDimitry Andric return PA;
41305f757f3fSDimitry Andric }
41315f757f3fSDimitry Andric return PreservedAnalyses::all();
41325f757f3fSDimitry Andric }
4133e8d8bef9SDimitry Andric namespace llvm {
4134e8d8bef9SDimitry Andric
4135e8d8bef9SDimitry Andric template <> struct GraphTraits<AADepGraphNode *> {
4136e8d8bef9SDimitry Andric using NodeRef = AADepGraphNode *;
4137e8d8bef9SDimitry Andric using DepTy = PointerIntPair<AADepGraphNode *, 1>;
4138e8d8bef9SDimitry Andric using EdgeRef = PointerIntPair<AADepGraphNode *, 1>;
4139e8d8bef9SDimitry Andric
getEntryNodellvm::GraphTraits4140e8d8bef9SDimitry Andric static NodeRef getEntryNode(AADepGraphNode *DGN) { return DGN; }
DepGetValllvm::GraphTraits414106c3fb27SDimitry Andric static NodeRef DepGetVal(const DepTy &DT) { return DT.getPointer(); }
4142e8d8bef9SDimitry Andric
4143e8d8bef9SDimitry Andric using ChildIteratorType =
414406c3fb27SDimitry Andric mapped_iterator<AADepGraphNode::DepSetTy::iterator, decltype(&DepGetVal)>;
414506c3fb27SDimitry Andric using ChildEdgeIteratorType = AADepGraphNode::DepSetTy::iterator;
4146e8d8bef9SDimitry Andric
child_beginllvm::GraphTraits4147e8d8bef9SDimitry Andric static ChildIteratorType child_begin(NodeRef N) { return N->child_begin(); }
4148e8d8bef9SDimitry Andric
child_endllvm::GraphTraits4149e8d8bef9SDimitry Andric static ChildIteratorType child_end(NodeRef N) { return N->child_end(); }
4150e8d8bef9SDimitry Andric };
4151e8d8bef9SDimitry Andric
4152e8d8bef9SDimitry Andric template <>
4153e8d8bef9SDimitry Andric struct GraphTraits<AADepGraph *> : public GraphTraits<AADepGraphNode *> {
getEntryNodellvm::GraphTraits4154e8d8bef9SDimitry Andric static NodeRef getEntryNode(AADepGraph *DG) { return DG->GetEntryNode(); }
4155e8d8bef9SDimitry Andric
4156e8d8bef9SDimitry Andric using nodes_iterator =
415706c3fb27SDimitry Andric mapped_iterator<AADepGraphNode::DepSetTy::iterator, decltype(&DepGetVal)>;
4158e8d8bef9SDimitry Andric
nodes_beginllvm::GraphTraits4159e8d8bef9SDimitry Andric static nodes_iterator nodes_begin(AADepGraph *DG) { return DG->begin(); }
4160e8d8bef9SDimitry Andric
nodes_endllvm::GraphTraits4161e8d8bef9SDimitry Andric static nodes_iterator nodes_end(AADepGraph *DG) { return DG->end(); }
4162e8d8bef9SDimitry Andric };
4163e8d8bef9SDimitry Andric
4164e8d8bef9SDimitry Andric template <> struct DOTGraphTraits<AADepGraph *> : public DefaultDOTGraphTraits {
DOTGraphTraitsllvm::DOTGraphTraits4165e8d8bef9SDimitry Andric DOTGraphTraits(bool isSimple = false) : DefaultDOTGraphTraits(isSimple) {}
4166e8d8bef9SDimitry Andric
getNodeLabelllvm::DOTGraphTraits4167e8d8bef9SDimitry Andric static std::string getNodeLabel(const AADepGraphNode *Node,
4168e8d8bef9SDimitry Andric const AADepGraph *DG) {
4169e8d8bef9SDimitry Andric std::string AAString;
4170e8d8bef9SDimitry Andric raw_string_ostream O(AAString);
4171e8d8bef9SDimitry Andric Node->print(O);
4172e8d8bef9SDimitry Andric return AAString;
4173e8d8bef9SDimitry Andric }
4174e8d8bef9SDimitry Andric };
4175e8d8bef9SDimitry Andric
4176e8d8bef9SDimitry Andric } // end namespace llvm
4177