Path: blob/main/contrib/llvm-project/llvm/lib/Transforms/IPO/AttributorAttributes.cpp
35269 views
//===- AttributorAttributes.cpp - Attributes for Attributor deduction -----===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// See the Attributor.h file comment and the class descriptions in that file for9// more information.10//11//===----------------------------------------------------------------------===//1213#include "llvm/Transforms/IPO/Attributor.h"1415#include "llvm/ADT/APInt.h"16#include "llvm/ADT/ArrayRef.h"17#include "llvm/ADT/DenseMapInfo.h"18#include "llvm/ADT/MapVector.h"19#include "llvm/ADT/SCCIterator.h"20#include "llvm/ADT/STLExtras.h"21#include "llvm/ADT/SetOperations.h"22#include "llvm/ADT/SetVector.h"23#include "llvm/ADT/SmallPtrSet.h"24#include "llvm/ADT/SmallVector.h"25#include "llvm/ADT/Statistic.h"26#include "llvm/ADT/StringExtras.h"27#include "llvm/Analysis/AliasAnalysis.h"28#include "llvm/Analysis/AssumeBundleQueries.h"29#include "llvm/Analysis/AssumptionCache.h"30#include "llvm/Analysis/CaptureTracking.h"31#include "llvm/Analysis/CycleAnalysis.h"32#include "llvm/Analysis/InstructionSimplify.h"33#include "llvm/Analysis/LazyValueInfo.h"34#include "llvm/Analysis/MemoryBuiltins.h"35#include "llvm/Analysis/OptimizationRemarkEmitter.h"36#include "llvm/Analysis/ScalarEvolution.h"37#include "llvm/Analysis/TargetTransformInfo.h"38#include "llvm/Analysis/ValueTracking.h"39#include "llvm/IR/Argument.h"40#include "llvm/IR/Assumptions.h"41#include "llvm/IR/Attributes.h"42#include "llvm/IR/BasicBlock.h"43#include "llvm/IR/Constant.h"44#include "llvm/IR/Constants.h"45#include "llvm/IR/DataLayout.h"46#include "llvm/IR/DerivedTypes.h"47#include "llvm/IR/GlobalValue.h"48#include "llvm/IR/IRBuilder.h"49#include "llvm/IR/InlineAsm.h"50#include "llvm/IR/InstrTypes.h"51#include "llvm/IR/Instruction.h"52#include "llvm/IR/Instructions.h"53#include "llvm/IR/IntrinsicInst.h"54#include "llvm/IR/IntrinsicsAMDGPU.h"55#include "llvm/IR/IntrinsicsNVPTX.h"56#include "llvm/IR/LLVMContext.h"57#include "llvm/IR/MDBuilder.h"58#include "llvm/IR/NoFolder.h"59#include "llvm/IR/Value.h"60#include "llvm/IR/ValueHandle.h"61#include "llvm/Support/Alignment.h"62#include "llvm/Support/Casting.h"63#include "llvm/Support/CommandLine.h"64#include "llvm/Support/ErrorHandling.h"65#include "llvm/Support/GraphWriter.h"66#include "llvm/Support/MathExtras.h"67#include "llvm/Support/TypeSize.h"68#include "llvm/Support/raw_ostream.h"69#include "llvm/Transforms/Utils/BasicBlockUtils.h"70#include "llvm/Transforms/Utils/CallPromotionUtils.h"71#include "llvm/Transforms/Utils/Local.h"72#include "llvm/Transforms/Utils/ValueMapper.h"73#include <cassert>74#include <numeric>75#include <optional>76#include <string>7778using namespace llvm;7980#define DEBUG_TYPE "attributor"8182static cl::opt<bool> ManifestInternal(83"attributor-manifest-internal", cl::Hidden,84cl::desc("Manifest Attributor internal string attributes."),85cl::init(false));8687static cl::opt<int> MaxHeapToStackSize("max-heap-to-stack-size", cl::init(128),88cl::Hidden);8990template <>91unsigned llvm::PotentialConstantIntValuesState::MaxPotentialValues = 0;9293template <> unsigned llvm::PotentialLLVMValuesState::MaxPotentialValues = -1;9495static cl::opt<unsigned, true> MaxPotentialValues(96"attributor-max-potential-values", cl::Hidden,97cl::desc("Maximum number of potential values to be "98"tracked for each position."),99cl::location(llvm::PotentialConstantIntValuesState::MaxPotentialValues),100cl::init(7));101102static cl::opt<int> MaxPotentialValuesIterations(103"attributor-max-potential-values-iterations", cl::Hidden,104cl::desc(105"Maximum number of iterations we keep dismantling potential values."),106cl::init(64));107108STATISTIC(NumAAs, "Number of abstract attributes created");109110// Some helper macros to deal with statistics tracking.111//112// Usage:113// For simple IR attribute tracking overload trackStatistics in the abstract114// attribute and choose the right STATS_DECLTRACK_********* macro,115// e.g.,:116// void trackStatistics() const override {117// STATS_DECLTRACK_ARG_ATTR(returned)118// }119// If there is a single "increment" side one can use the macro120// STATS_DECLTRACK with a custom message. If there are multiple increment121// sides, STATS_DECL and STATS_TRACK can also be used separately.122//123#define BUILD_STAT_MSG_IR_ATTR(TYPE, NAME) \124("Number of " #TYPE " marked '" #NAME "'")125#define BUILD_STAT_NAME(NAME, TYPE) NumIR##TYPE##_##NAME126#define STATS_DECL_(NAME, MSG) STATISTIC(NAME, MSG);127#define STATS_DECL(NAME, TYPE, MSG) \128STATS_DECL_(BUILD_STAT_NAME(NAME, TYPE), MSG);129#define STATS_TRACK(NAME, TYPE) ++(BUILD_STAT_NAME(NAME, TYPE));130#define STATS_DECLTRACK(NAME, TYPE, MSG) \131{ \132STATS_DECL(NAME, TYPE, MSG) \133STATS_TRACK(NAME, TYPE) \134}135#define STATS_DECLTRACK_ARG_ATTR(NAME) \136STATS_DECLTRACK(NAME, Arguments, BUILD_STAT_MSG_IR_ATTR(arguments, NAME))137#define STATS_DECLTRACK_CSARG_ATTR(NAME) \138STATS_DECLTRACK(NAME, CSArguments, \139BUILD_STAT_MSG_IR_ATTR(call site arguments, NAME))140#define STATS_DECLTRACK_FN_ATTR(NAME) \141STATS_DECLTRACK(NAME, Function, BUILD_STAT_MSG_IR_ATTR(functions, NAME))142#define STATS_DECLTRACK_CS_ATTR(NAME) \143STATS_DECLTRACK(NAME, CS, BUILD_STAT_MSG_IR_ATTR(call site, NAME))144#define STATS_DECLTRACK_FNRET_ATTR(NAME) \145STATS_DECLTRACK(NAME, FunctionReturn, \146BUILD_STAT_MSG_IR_ATTR(function returns, NAME))147#define STATS_DECLTRACK_CSRET_ATTR(NAME) \148STATS_DECLTRACK(NAME, CSReturn, \149BUILD_STAT_MSG_IR_ATTR(call site returns, NAME))150#define STATS_DECLTRACK_FLOATING_ATTR(NAME) \151STATS_DECLTRACK(NAME, Floating, \152("Number of floating values known to be '" #NAME "'"))153154// Specialization of the operator<< for abstract attributes subclasses. This155// disambiguates situations where multiple operators are applicable.156namespace llvm {157#define PIPE_OPERATOR(CLASS) \158raw_ostream &operator<<(raw_ostream &OS, const CLASS &AA) { \159return OS << static_cast<const AbstractAttribute &>(AA); \160}161162PIPE_OPERATOR(AAIsDead)163PIPE_OPERATOR(AANoUnwind)164PIPE_OPERATOR(AANoSync)165PIPE_OPERATOR(AANoRecurse)166PIPE_OPERATOR(AANonConvergent)167PIPE_OPERATOR(AAWillReturn)168PIPE_OPERATOR(AANoReturn)169PIPE_OPERATOR(AANonNull)170PIPE_OPERATOR(AAMustProgress)171PIPE_OPERATOR(AANoAlias)172PIPE_OPERATOR(AADereferenceable)173PIPE_OPERATOR(AAAlign)174PIPE_OPERATOR(AAInstanceInfo)175PIPE_OPERATOR(AANoCapture)176PIPE_OPERATOR(AAValueSimplify)177PIPE_OPERATOR(AANoFree)178PIPE_OPERATOR(AAHeapToStack)179PIPE_OPERATOR(AAIntraFnReachability)180PIPE_OPERATOR(AAMemoryBehavior)181PIPE_OPERATOR(AAMemoryLocation)182PIPE_OPERATOR(AAValueConstantRange)183PIPE_OPERATOR(AAPrivatizablePtr)184PIPE_OPERATOR(AAUndefinedBehavior)185PIPE_OPERATOR(AAPotentialConstantValues)186PIPE_OPERATOR(AAPotentialValues)187PIPE_OPERATOR(AANoUndef)188PIPE_OPERATOR(AANoFPClass)189PIPE_OPERATOR(AACallEdges)190PIPE_OPERATOR(AAInterFnReachability)191PIPE_OPERATOR(AAPointerInfo)192PIPE_OPERATOR(AAAssumptionInfo)193PIPE_OPERATOR(AAUnderlyingObjects)194PIPE_OPERATOR(AAAddressSpace)195PIPE_OPERATOR(AAAllocationInfo)196PIPE_OPERATOR(AAIndirectCallInfo)197PIPE_OPERATOR(AAGlobalValueInfo)198PIPE_OPERATOR(AADenormalFPMath)199200#undef PIPE_OPERATOR201202template <>203ChangeStatus clampStateAndIndicateChange<DerefState>(DerefState &S,204const DerefState &R) {205ChangeStatus CS0 =206clampStateAndIndicateChange(S.DerefBytesState, R.DerefBytesState);207ChangeStatus CS1 = clampStateAndIndicateChange(S.GlobalState, R.GlobalState);208return CS0 | CS1;209}210211} // namespace llvm212213static bool mayBeInCycle(const CycleInfo *CI, const Instruction *I,214bool HeaderOnly, Cycle **CPtr = nullptr) {215if (!CI)216return true;217auto *BB = I->getParent();218auto *C = CI->getCycle(BB);219if (!C)220return false;221if (CPtr)222*CPtr = C;223return !HeaderOnly || BB == C->getHeader();224}225226/// Checks if a type could have padding bytes.227static bool isDenselyPacked(Type *Ty, const DataLayout &DL) {228// There is no size information, so be conservative.229if (!Ty->isSized())230return false;231232// If the alloc size is not equal to the storage size, then there are padding233// bytes. For x86_fp80 on x86-64, size: 80 alloc size: 128.234if (DL.getTypeSizeInBits(Ty) != DL.getTypeAllocSizeInBits(Ty))235return false;236237// FIXME: This isn't the right way to check for padding in vectors with238// non-byte-size elements.239if (VectorType *SeqTy = dyn_cast<VectorType>(Ty))240return isDenselyPacked(SeqTy->getElementType(), DL);241242// For array types, check for padding within members.243if (ArrayType *SeqTy = dyn_cast<ArrayType>(Ty))244return isDenselyPacked(SeqTy->getElementType(), DL);245246if (!isa<StructType>(Ty))247return true;248249// Check for padding within and between elements of a struct.250StructType *StructTy = cast<StructType>(Ty);251const StructLayout *Layout = DL.getStructLayout(StructTy);252uint64_t StartPos = 0;253for (unsigned I = 0, E = StructTy->getNumElements(); I < E; ++I) {254Type *ElTy = StructTy->getElementType(I);255if (!isDenselyPacked(ElTy, DL))256return false;257if (StartPos != Layout->getElementOffsetInBits(I))258return false;259StartPos += DL.getTypeAllocSizeInBits(ElTy);260}261262return true;263}264265/// Get pointer operand of memory accessing instruction. If \p I is266/// not a memory accessing instruction, return nullptr. If \p AllowVolatile,267/// is set to false and the instruction is volatile, return nullptr.268static const Value *getPointerOperand(const Instruction *I,269bool AllowVolatile) {270if (!AllowVolatile && I->isVolatile())271return nullptr;272273if (auto *LI = dyn_cast<LoadInst>(I)) {274return LI->getPointerOperand();275}276277if (auto *SI = dyn_cast<StoreInst>(I)) {278return SI->getPointerOperand();279}280281if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(I)) {282return CXI->getPointerOperand();283}284285if (auto *RMWI = dyn_cast<AtomicRMWInst>(I)) {286return RMWI->getPointerOperand();287}288289return nullptr;290}291292/// Helper function to create a pointer based on \p Ptr, and advanced by \p293/// Offset bytes.294static Value *constructPointer(Value *Ptr, int64_t Offset,295IRBuilder<NoFolder> &IRB) {296LLVM_DEBUG(dbgs() << "Construct pointer: " << *Ptr << " + " << Offset297<< "-bytes\n");298299if (Offset)300Ptr = IRB.CreatePtrAdd(Ptr, IRB.getInt64(Offset),301Ptr->getName() + ".b" + Twine(Offset));302return Ptr;303}304305static const Value *306stripAndAccumulateOffsets(Attributor &A, const AbstractAttribute &QueryingAA,307const Value *Val, const DataLayout &DL, APInt &Offset,308bool GetMinOffset, bool AllowNonInbounds,309bool UseAssumed = false) {310311auto AttributorAnalysis = [&](Value &V, APInt &ROffset) -> bool {312const IRPosition &Pos = IRPosition::value(V);313// Only track dependence if we are going to use the assumed info.314const AAValueConstantRange *ValueConstantRangeAA =315A.getAAFor<AAValueConstantRange>(QueryingAA, Pos,316UseAssumed ? DepClassTy::OPTIONAL317: DepClassTy::NONE);318if (!ValueConstantRangeAA)319return false;320ConstantRange Range = UseAssumed ? ValueConstantRangeAA->getAssumed()321: ValueConstantRangeAA->getKnown();322if (Range.isFullSet())323return false;324325// We can only use the lower part of the range because the upper part can326// be higher than what the value can really be.327if (GetMinOffset)328ROffset = Range.getSignedMin();329else330ROffset = Range.getSignedMax();331return true;332};333334return Val->stripAndAccumulateConstantOffsets(DL, Offset, AllowNonInbounds,335/* AllowInvariant */ true,336AttributorAnalysis);337}338339static const Value *340getMinimalBaseOfPointer(Attributor &A, const AbstractAttribute &QueryingAA,341const Value *Ptr, int64_t &BytesOffset,342const DataLayout &DL, bool AllowNonInbounds = false) {343APInt OffsetAPInt(DL.getIndexTypeSizeInBits(Ptr->getType()), 0);344const Value *Base =345stripAndAccumulateOffsets(A, QueryingAA, Ptr, DL, OffsetAPInt,346/* GetMinOffset */ true, AllowNonInbounds);347348BytesOffset = OffsetAPInt.getSExtValue();349return Base;350}351352/// Clamp the information known for all returned values of a function353/// (identified by \p QueryingAA) into \p S.354template <typename AAType, typename StateType = typename AAType::StateType,355Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind,356bool RecurseForSelectAndPHI = true>357static void clampReturnedValueStates(358Attributor &A, const AAType &QueryingAA, StateType &S,359const IRPosition::CallBaseContext *CBContext = nullptr) {360LLVM_DEBUG(dbgs() << "[Attributor] Clamp return value states for "361<< QueryingAA << " into " << S << "\n");362363assert((QueryingAA.getIRPosition().getPositionKind() ==364IRPosition::IRP_RETURNED ||365QueryingAA.getIRPosition().getPositionKind() ==366IRPosition::IRP_CALL_SITE_RETURNED) &&367"Can only clamp returned value states for a function returned or call "368"site returned position!");369370// Use an optional state as there might not be any return values and we want371// to join (IntegerState::operator&) the state of all there are.372std::optional<StateType> T;373374// Callback for each possibly returned value.375auto CheckReturnValue = [&](Value &RV) -> bool {376const IRPosition &RVPos = IRPosition::value(RV, CBContext);377// If possible, use the hasAssumedIRAttr interface.378if (Attribute::isEnumAttrKind(IRAttributeKind)) {379bool IsKnown;380return AA::hasAssumedIRAttr<IRAttributeKind>(381A, &QueryingAA, RVPos, DepClassTy::REQUIRED, IsKnown);382}383384const AAType *AA =385A.getAAFor<AAType>(QueryingAA, RVPos, DepClassTy::REQUIRED);386if (!AA)387return false;388LLVM_DEBUG(dbgs() << "[Attributor] RV: " << RV389<< " AA: " << AA->getAsStr(&A) << " @ " << RVPos << "\n");390const StateType &AAS = AA->getState();391if (!T)392T = StateType::getBestState(AAS);393*T &= AAS;394LLVM_DEBUG(dbgs() << "[Attributor] AA State: " << AAS << " RV State: " << T395<< "\n");396return T->isValidState();397};398399if (!A.checkForAllReturnedValues(CheckReturnValue, QueryingAA,400AA::ValueScope::Intraprocedural,401RecurseForSelectAndPHI))402S.indicatePessimisticFixpoint();403else if (T)404S ^= *T;405}406407namespace {408/// Helper class for generic deduction: return value -> returned position.409template <typename AAType, typename BaseType,410typename StateType = typename BaseType::StateType,411bool PropagateCallBaseContext = false,412Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind,413bool RecurseForSelectAndPHI = true>414struct AAReturnedFromReturnedValues : public BaseType {415AAReturnedFromReturnedValues(const IRPosition &IRP, Attributor &A)416: BaseType(IRP, A) {}417418/// See AbstractAttribute::updateImpl(...).419ChangeStatus updateImpl(Attributor &A) override {420StateType S(StateType::getBestState(this->getState()));421clampReturnedValueStates<AAType, StateType, IRAttributeKind,422RecurseForSelectAndPHI>(423A, *this, S,424PropagateCallBaseContext ? this->getCallBaseContext() : nullptr);425// TODO: If we know we visited all returned values, thus no are assumed426// dead, we can take the known information from the state T.427return clampStateAndIndicateChange<StateType>(this->getState(), S);428}429};430431/// Clamp the information known at all call sites for a given argument432/// (identified by \p QueryingAA) into \p S.433template <typename AAType, typename StateType = typename AAType::StateType,434Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind>435static void clampCallSiteArgumentStates(Attributor &A, const AAType &QueryingAA,436StateType &S) {437LLVM_DEBUG(dbgs() << "[Attributor] Clamp call site argument states for "438<< QueryingAA << " into " << S << "\n");439440assert(QueryingAA.getIRPosition().getPositionKind() ==441IRPosition::IRP_ARGUMENT &&442"Can only clamp call site argument states for an argument position!");443444// Use an optional state as there might not be any return values and we want445// to join (IntegerState::operator&) the state of all there are.446std::optional<StateType> T;447448// The argument number which is also the call site argument number.449unsigned ArgNo = QueryingAA.getIRPosition().getCallSiteArgNo();450451auto CallSiteCheck = [&](AbstractCallSite ACS) {452const IRPosition &ACSArgPos = IRPosition::callsite_argument(ACS, ArgNo);453// Check if a coresponding argument was found or if it is on not associated454// (which can happen for callback calls).455if (ACSArgPos.getPositionKind() == IRPosition::IRP_INVALID)456return false;457458// If possible, use the hasAssumedIRAttr interface.459if (Attribute::isEnumAttrKind(IRAttributeKind)) {460bool IsKnown;461return AA::hasAssumedIRAttr<IRAttributeKind>(462A, &QueryingAA, ACSArgPos, DepClassTy::REQUIRED, IsKnown);463}464465const AAType *AA =466A.getAAFor<AAType>(QueryingAA, ACSArgPos, DepClassTy::REQUIRED);467if (!AA)468return false;469LLVM_DEBUG(dbgs() << "[Attributor] ACS: " << *ACS.getInstruction()470<< " AA: " << AA->getAsStr(&A) << " @" << ACSArgPos471<< "\n");472const StateType &AAS = AA->getState();473if (!T)474T = StateType::getBestState(AAS);475*T &= AAS;476LLVM_DEBUG(dbgs() << "[Attributor] AA State: " << AAS << " CSA State: " << T477<< "\n");478return T->isValidState();479};480481bool UsedAssumedInformation = false;482if (!A.checkForAllCallSites(CallSiteCheck, QueryingAA, true,483UsedAssumedInformation))484S.indicatePessimisticFixpoint();485else if (T)486S ^= *T;487}488489/// This function is the bridge between argument position and the call base490/// context.491template <typename AAType, typename BaseType,492typename StateType = typename AAType::StateType,493Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind>494bool getArgumentStateFromCallBaseContext(Attributor &A,495BaseType &QueryingAttribute,496IRPosition &Pos, StateType &State) {497assert((Pos.getPositionKind() == IRPosition::IRP_ARGUMENT) &&498"Expected an 'argument' position !");499const CallBase *CBContext = Pos.getCallBaseContext();500if (!CBContext)501return false;502503int ArgNo = Pos.getCallSiteArgNo();504assert(ArgNo >= 0 && "Invalid Arg No!");505const IRPosition CBArgPos = IRPosition::callsite_argument(*CBContext, ArgNo);506507// If possible, use the hasAssumedIRAttr interface.508if (Attribute::isEnumAttrKind(IRAttributeKind)) {509bool IsKnown;510return AA::hasAssumedIRAttr<IRAttributeKind>(511A, &QueryingAttribute, CBArgPos, DepClassTy::REQUIRED, IsKnown);512}513514const auto *AA =515A.getAAFor<AAType>(QueryingAttribute, CBArgPos, DepClassTy::REQUIRED);516if (!AA)517return false;518const StateType &CBArgumentState =519static_cast<const StateType &>(AA->getState());520521LLVM_DEBUG(dbgs() << "[Attributor] Briding Call site context to argument"522<< "Position:" << Pos << "CB Arg state:" << CBArgumentState523<< "\n");524525// NOTE: If we want to do call site grouping it should happen here.526State ^= CBArgumentState;527return true;528}529530/// Helper class for generic deduction: call site argument -> argument position.531template <typename AAType, typename BaseType,532typename StateType = typename AAType::StateType,533bool BridgeCallBaseContext = false,534Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind>535struct AAArgumentFromCallSiteArguments : public BaseType {536AAArgumentFromCallSiteArguments(const IRPosition &IRP, Attributor &A)537: BaseType(IRP, A) {}538539/// See AbstractAttribute::updateImpl(...).540ChangeStatus updateImpl(Attributor &A) override {541StateType S = StateType::getBestState(this->getState());542543if (BridgeCallBaseContext) {544bool Success =545getArgumentStateFromCallBaseContext<AAType, BaseType, StateType,546IRAttributeKind>(547A, *this, this->getIRPosition(), S);548if (Success)549return clampStateAndIndicateChange<StateType>(this->getState(), S);550}551clampCallSiteArgumentStates<AAType, StateType, IRAttributeKind>(A, *this,552S);553554// TODO: If we know we visited all incoming values, thus no are assumed555// dead, we can take the known information from the state T.556return clampStateAndIndicateChange<StateType>(this->getState(), S);557}558};559560/// Helper class for generic replication: function returned -> cs returned.561template <typename AAType, typename BaseType,562typename StateType = typename BaseType::StateType,563bool IntroduceCallBaseContext = false,564Attribute::AttrKind IRAttributeKind = AAType::IRAttributeKind>565struct AACalleeToCallSite : public BaseType {566AACalleeToCallSite(const IRPosition &IRP, Attributor &A) : BaseType(IRP, A) {}567568/// See AbstractAttribute::updateImpl(...).569ChangeStatus updateImpl(Attributor &A) override {570auto IRPKind = this->getIRPosition().getPositionKind();571assert((IRPKind == IRPosition::IRP_CALL_SITE_RETURNED ||572IRPKind == IRPosition::IRP_CALL_SITE) &&573"Can only wrap function returned positions for call site "574"returned positions!");575auto &S = this->getState();576577CallBase &CB = cast<CallBase>(this->getAnchorValue());578if (IntroduceCallBaseContext)579LLVM_DEBUG(dbgs() << "[Attributor] Introducing call base context:" << CB580<< "\n");581582ChangeStatus Changed = ChangeStatus::UNCHANGED;583auto CalleePred = [&](ArrayRef<const Function *> Callees) {584for (const Function *Callee : Callees) {585IRPosition FnPos =586IRPKind == llvm::IRPosition::IRP_CALL_SITE_RETURNED587? IRPosition::returned(*Callee,588IntroduceCallBaseContext ? &CB : nullptr)589: IRPosition::function(590*Callee, IntroduceCallBaseContext ? &CB : nullptr);591// If possible, use the hasAssumedIRAttr interface.592if (Attribute::isEnumAttrKind(IRAttributeKind)) {593bool IsKnown;594if (!AA::hasAssumedIRAttr<IRAttributeKind>(595A, this, FnPos, DepClassTy::REQUIRED, IsKnown))596return false;597continue;598}599600const AAType *AA =601A.getAAFor<AAType>(*this, FnPos, DepClassTy::REQUIRED);602if (!AA)603return false;604Changed |= clampStateAndIndicateChange(S, AA->getState());605if (S.isAtFixpoint())606return S.isValidState();607}608return true;609};610if (!A.checkForAllCallees(CalleePred, *this, CB))611return S.indicatePessimisticFixpoint();612return Changed;613}614};615616/// Helper function to accumulate uses.617template <class AAType, typename StateType = typename AAType::StateType>618static void followUsesInContext(AAType &AA, Attributor &A,619MustBeExecutedContextExplorer &Explorer,620const Instruction *CtxI,621SetVector<const Use *> &Uses,622StateType &State) {623auto EIt = Explorer.begin(CtxI), EEnd = Explorer.end(CtxI);624for (unsigned u = 0; u < Uses.size(); ++u) {625const Use *U = Uses[u];626if (const Instruction *UserI = dyn_cast<Instruction>(U->getUser())) {627bool Found = Explorer.findInContextOf(UserI, EIt, EEnd);628if (Found && AA.followUseInMBEC(A, U, UserI, State))629for (const Use &Us : UserI->uses())630Uses.insert(&Us);631}632}633}634635/// Use the must-be-executed-context around \p I to add information into \p S.636/// The AAType class is required to have `followUseInMBEC` method with the637/// following signature and behaviour:638///639/// bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I)640/// U - Underlying use.641/// I - The user of the \p U.642/// Returns true if the value should be tracked transitively.643///644template <class AAType, typename StateType = typename AAType::StateType>645static void followUsesInMBEC(AAType &AA, Attributor &A, StateType &S,646Instruction &CtxI) {647MustBeExecutedContextExplorer *Explorer =648A.getInfoCache().getMustBeExecutedContextExplorer();649if (!Explorer)650return;651652// Container for (transitive) uses of the associated value.653SetVector<const Use *> Uses;654for (const Use &U : AA.getIRPosition().getAssociatedValue().uses())655Uses.insert(&U);656657followUsesInContext<AAType>(AA, A, *Explorer, &CtxI, Uses, S);658659if (S.isAtFixpoint())660return;661662SmallVector<const BranchInst *, 4> BrInsts;663auto Pred = [&](const Instruction *I) {664if (const BranchInst *Br = dyn_cast<BranchInst>(I))665if (Br->isConditional())666BrInsts.push_back(Br);667return true;668};669670// Here, accumulate conditional branch instructions in the context. We671// explore the child paths and collect the known states. The disjunction of672// those states can be merged to its own state. Let ParentState_i be a state673// to indicate the known information for an i-th branch instruction in the674// context. ChildStates are created for its successors respectively.675//676// ParentS_1 = ChildS_{1, 1} /\ ChildS_{1, 2} /\ ... /\ ChildS_{1, n_1}677// ParentS_2 = ChildS_{2, 1} /\ ChildS_{2, 2} /\ ... /\ ChildS_{2, n_2}678// ...679// ParentS_m = ChildS_{m, 1} /\ ChildS_{m, 2} /\ ... /\ ChildS_{m, n_m}680//681// Known State |= ParentS_1 \/ ParentS_2 \/... \/ ParentS_m682//683// FIXME: Currently, recursive branches are not handled. For example, we684// can't deduce that ptr must be dereferenced in below function.685//686// void f(int a, int c, int *ptr) {687// if(a)688// if (b) {689// *ptr = 0;690// } else {691// *ptr = 1;692// }693// else {694// if (b) {695// *ptr = 0;696// } else {697// *ptr = 1;698// }699// }700// }701702Explorer->checkForAllContext(&CtxI, Pred);703for (const BranchInst *Br : BrInsts) {704StateType ParentState;705706// The known state of the parent state is a conjunction of children's707// known states so it is initialized with a best state.708ParentState.indicateOptimisticFixpoint();709710for (const BasicBlock *BB : Br->successors()) {711StateType ChildState;712713size_t BeforeSize = Uses.size();714followUsesInContext(AA, A, *Explorer, &BB->front(), Uses, ChildState);715716// Erase uses which only appear in the child.717for (auto It = Uses.begin() + BeforeSize; It != Uses.end();)718It = Uses.erase(It);719720ParentState &= ChildState;721}722723// Use only known state.724S += ParentState;725}726}727} // namespace728729/// ------------------------ PointerInfo ---------------------------------------730731namespace llvm {732namespace AA {733namespace PointerInfo {734735struct State;736737} // namespace PointerInfo738} // namespace AA739740/// Helper for AA::PointerInfo::Access DenseMap/Set usage.741template <>742struct DenseMapInfo<AAPointerInfo::Access> : DenseMapInfo<Instruction *> {743using Access = AAPointerInfo::Access;744static inline Access getEmptyKey();745static inline Access getTombstoneKey();746static unsigned getHashValue(const Access &A);747static bool isEqual(const Access &LHS, const Access &RHS);748};749750/// Helper that allows RangeTy as a key in a DenseMap.751template <> struct DenseMapInfo<AA::RangeTy> {752static inline AA::RangeTy getEmptyKey() {753auto EmptyKey = DenseMapInfo<int64_t>::getEmptyKey();754return AA::RangeTy{EmptyKey, EmptyKey};755}756757static inline AA::RangeTy getTombstoneKey() {758auto TombstoneKey = DenseMapInfo<int64_t>::getTombstoneKey();759return AA::RangeTy{TombstoneKey, TombstoneKey};760}761762static unsigned getHashValue(const AA::RangeTy &Range) {763return detail::combineHashValue(764DenseMapInfo<int64_t>::getHashValue(Range.Offset),765DenseMapInfo<int64_t>::getHashValue(Range.Size));766}767768static bool isEqual(const AA::RangeTy &A, const AA::RangeTy B) {769return A == B;770}771};772773/// Helper for AA::PointerInfo::Access DenseMap/Set usage ignoring everythign774/// but the instruction775struct AccessAsInstructionInfo : DenseMapInfo<Instruction *> {776using Base = DenseMapInfo<Instruction *>;777using Access = AAPointerInfo::Access;778static inline Access getEmptyKey();779static inline Access getTombstoneKey();780static unsigned getHashValue(const Access &A);781static bool isEqual(const Access &LHS, const Access &RHS);782};783784} // namespace llvm785786/// A type to track pointer/struct usage and accesses for AAPointerInfo.787struct AA::PointerInfo::State : public AbstractState {788/// Return the best possible representable state.789static State getBestState(const State &SIS) { return State(); }790791/// Return the worst possible representable state.792static State getWorstState(const State &SIS) {793State R;794R.indicatePessimisticFixpoint();795return R;796}797798State() = default;799State(State &&SIS) = default;800801const State &getAssumed() const { return *this; }802803/// See AbstractState::isValidState().804bool isValidState() const override { return BS.isValidState(); }805806/// See AbstractState::isAtFixpoint().807bool isAtFixpoint() const override { return BS.isAtFixpoint(); }808809/// See AbstractState::indicateOptimisticFixpoint().810ChangeStatus indicateOptimisticFixpoint() override {811BS.indicateOptimisticFixpoint();812return ChangeStatus::UNCHANGED;813}814815/// See AbstractState::indicatePessimisticFixpoint().816ChangeStatus indicatePessimisticFixpoint() override {817BS.indicatePessimisticFixpoint();818return ChangeStatus::CHANGED;819}820821State &operator=(const State &R) {822if (this == &R)823return *this;824BS = R.BS;825AccessList = R.AccessList;826OffsetBins = R.OffsetBins;827RemoteIMap = R.RemoteIMap;828return *this;829}830831State &operator=(State &&R) {832if (this == &R)833return *this;834std::swap(BS, R.BS);835std::swap(AccessList, R.AccessList);836std::swap(OffsetBins, R.OffsetBins);837std::swap(RemoteIMap, R.RemoteIMap);838return *this;839}840841/// Add a new Access to the state at offset \p Offset and with size \p Size.842/// The access is associated with \p I, writes \p Content (if anything), and843/// is of kind \p Kind. If an Access already exists for the same \p I and same844/// \p RemoteI, the two are combined, potentially losing information about845/// offset and size. The resulting access must now be moved from its original846/// OffsetBin to the bin for its new offset.847///848/// \Returns CHANGED, if the state changed, UNCHANGED otherwise.849ChangeStatus addAccess(Attributor &A, const AAPointerInfo::RangeList &Ranges,850Instruction &I, std::optional<Value *> Content,851AAPointerInfo::AccessKind Kind, Type *Ty,852Instruction *RemoteI = nullptr);853854AAPointerInfo::const_bin_iterator begin() const { return OffsetBins.begin(); }855AAPointerInfo::const_bin_iterator end() const { return OffsetBins.end(); }856int64_t numOffsetBins() const { return OffsetBins.size(); }857858const AAPointerInfo::Access &getAccess(unsigned Index) const {859return AccessList[Index];860}861862protected:863// Every memory instruction results in an Access object. We maintain a list of864// all Access objects that we own, along with the following maps:865//866// - OffsetBins: RangeTy -> { Access }867// - RemoteIMap: RemoteI x LocalI -> Access868//869// A RemoteI is any instruction that accesses memory. RemoteI is different870// from LocalI if and only if LocalI is a call; then RemoteI is some871// instruction in the callgraph starting from LocalI. Multiple paths in the872// callgraph from LocalI to RemoteI may produce multiple accesses, but these873// are all combined into a single Access object. This may result in loss of874// information in RangeTy in the Access object.875SmallVector<AAPointerInfo::Access> AccessList;876AAPointerInfo::OffsetBinsTy OffsetBins;877DenseMap<const Instruction *, SmallVector<unsigned>> RemoteIMap;878879/// See AAPointerInfo::forallInterferingAccesses.880bool forallInterferingAccesses(881AA::RangeTy Range,882function_ref<bool(const AAPointerInfo::Access &, bool)> CB) const {883if (!isValidState())884return false;885886for (const auto &It : OffsetBins) {887AA::RangeTy ItRange = It.getFirst();888if (!Range.mayOverlap(ItRange))889continue;890bool IsExact = Range == ItRange && !Range.offsetOrSizeAreUnknown();891for (auto Index : It.getSecond()) {892auto &Access = AccessList[Index];893if (!CB(Access, IsExact))894return false;895}896}897return true;898}899900/// See AAPointerInfo::forallInterferingAccesses.901bool forallInterferingAccesses(902Instruction &I,903function_ref<bool(const AAPointerInfo::Access &, bool)> CB,904AA::RangeTy &Range) const {905if (!isValidState())906return false;907908auto LocalList = RemoteIMap.find(&I);909if (LocalList == RemoteIMap.end()) {910return true;911}912913for (unsigned Index : LocalList->getSecond()) {914for (auto &R : AccessList[Index]) {915Range &= R;916if (Range.offsetAndSizeAreUnknown())917break;918}919}920return forallInterferingAccesses(Range, CB);921}922923private:924/// State to track fixpoint and validity.925BooleanState BS;926};927928ChangeStatus AA::PointerInfo::State::addAccess(929Attributor &A, const AAPointerInfo::RangeList &Ranges, Instruction &I,930std::optional<Value *> Content, AAPointerInfo::AccessKind Kind, Type *Ty,931Instruction *RemoteI) {932RemoteI = RemoteI ? RemoteI : &I;933934// Check if we have an access for this instruction, if not, simply add it.935auto &LocalList = RemoteIMap[RemoteI];936bool AccExists = false;937unsigned AccIndex = AccessList.size();938for (auto Index : LocalList) {939auto &A = AccessList[Index];940if (A.getLocalInst() == &I) {941AccExists = true;942AccIndex = Index;943break;944}945}946947auto AddToBins = [&](const AAPointerInfo::RangeList &ToAdd) {948LLVM_DEBUG(if (ToAdd.size()) dbgs()949<< "[AAPointerInfo] Inserting access in new offset bins\n";);950951for (auto Key : ToAdd) {952LLVM_DEBUG(dbgs() << " key " << Key << "\n");953OffsetBins[Key].insert(AccIndex);954}955};956957if (!AccExists) {958AccessList.emplace_back(&I, RemoteI, Ranges, Content, Kind, Ty);959assert((AccessList.size() == AccIndex + 1) &&960"New Access should have been at AccIndex");961LocalList.push_back(AccIndex);962AddToBins(AccessList[AccIndex].getRanges());963return ChangeStatus::CHANGED;964}965966// Combine the new Access with the existing Access, and then update the967// mapping in the offset bins.968AAPointerInfo::Access Acc(&I, RemoteI, Ranges, Content, Kind, Ty);969auto &Current = AccessList[AccIndex];970auto Before = Current;971Current &= Acc;972if (Current == Before)973return ChangeStatus::UNCHANGED;974975auto &ExistingRanges = Before.getRanges();976auto &NewRanges = Current.getRanges();977978// Ranges that are in the old access but not the new access need to be removed979// from the offset bins.980AAPointerInfo::RangeList ToRemove;981AAPointerInfo::RangeList::set_difference(ExistingRanges, NewRanges, ToRemove);982LLVM_DEBUG(if (ToRemove.size()) dbgs()983<< "[AAPointerInfo] Removing access from old offset bins\n";);984985for (auto Key : ToRemove) {986LLVM_DEBUG(dbgs() << " key " << Key << "\n");987assert(OffsetBins.count(Key) && "Existing Access must be in some bin.");988auto &Bin = OffsetBins[Key];989assert(Bin.count(AccIndex) &&990"Expected bin to actually contain the Access.");991Bin.erase(AccIndex);992}993994// Ranges that are in the new access but not the old access need to be added995// to the offset bins.996AAPointerInfo::RangeList ToAdd;997AAPointerInfo::RangeList::set_difference(NewRanges, ExistingRanges, ToAdd);998AddToBins(ToAdd);999return ChangeStatus::CHANGED;1000}10011002namespace {10031004/// A helper containing a list of offsets computed for a Use. Ideally this1005/// list should be strictly ascending, but we ensure that only when we1006/// actually translate the list of offsets to a RangeList.1007struct OffsetInfo {1008using VecTy = SmallVector<int64_t>;1009using const_iterator = VecTy::const_iterator;1010VecTy Offsets;10111012const_iterator begin() const { return Offsets.begin(); }1013const_iterator end() const { return Offsets.end(); }10141015bool operator==(const OffsetInfo &RHS) const {1016return Offsets == RHS.Offsets;1017}10181019bool operator!=(const OffsetInfo &RHS) const { return !(*this == RHS); }10201021void insert(int64_t Offset) { Offsets.push_back(Offset); }1022bool isUnassigned() const { return Offsets.size() == 0; }10231024bool isUnknown() const {1025if (isUnassigned())1026return false;1027if (Offsets.size() == 1)1028return Offsets.front() == AA::RangeTy::Unknown;1029return false;1030}10311032void setUnknown() {1033Offsets.clear();1034Offsets.push_back(AA::RangeTy::Unknown);1035}10361037void addToAll(int64_t Inc) {1038for (auto &Offset : Offsets) {1039Offset += Inc;1040}1041}10421043/// Copy offsets from \p R into the current list.1044///1045/// Ideally all lists should be strictly ascending, but we defer that to the1046/// actual use of the list. So we just blindly append here.1047void merge(const OffsetInfo &R) { Offsets.append(R.Offsets); }1048};10491050#ifndef NDEBUG1051static raw_ostream &operator<<(raw_ostream &OS, const OffsetInfo &OI) {1052ListSeparator LS;1053OS << "[";1054for (auto Offset : OI) {1055OS << LS << Offset;1056}1057OS << "]";1058return OS;1059}1060#endif // NDEBUG10611062struct AAPointerInfoImpl1063: public StateWrapper<AA::PointerInfo::State, AAPointerInfo> {1064using BaseTy = StateWrapper<AA::PointerInfo::State, AAPointerInfo>;1065AAPointerInfoImpl(const IRPosition &IRP, Attributor &A) : BaseTy(IRP) {}10661067/// See AbstractAttribute::getAsStr().1068const std::string getAsStr(Attributor *A) const override {1069return std::string("PointerInfo ") +1070(isValidState() ? (std::string("#") +1071std::to_string(OffsetBins.size()) + " bins")1072: "<invalid>");1073}10741075/// See AbstractAttribute::manifest(...).1076ChangeStatus manifest(Attributor &A) override {1077return AAPointerInfo::manifest(A);1078}10791080virtual const_bin_iterator begin() const override { return State::begin(); }1081virtual const_bin_iterator end() const override { return State::end(); }1082virtual int64_t numOffsetBins() const override {1083return State::numOffsetBins();1084}10851086bool forallInterferingAccesses(1087AA::RangeTy Range,1088function_ref<bool(const AAPointerInfo::Access &, bool)> CB)1089const override {1090return State::forallInterferingAccesses(Range, CB);1091}10921093bool forallInterferingAccesses(1094Attributor &A, const AbstractAttribute &QueryingAA, Instruction &I,1095bool FindInterferingWrites, bool FindInterferingReads,1096function_ref<bool(const Access &, bool)> UserCB, bool &HasBeenWrittenTo,1097AA::RangeTy &Range,1098function_ref<bool(const Access &)> SkipCB) const override {1099HasBeenWrittenTo = false;11001101SmallPtrSet<const Access *, 8> DominatingWrites;1102SmallVector<std::pair<const Access *, bool>, 8> InterferingAccesses;11031104Function &Scope = *I.getFunction();1105bool IsKnownNoSync;1106bool IsAssumedNoSync = AA::hasAssumedIRAttr<Attribute::NoSync>(1107A, &QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL,1108IsKnownNoSync);1109const auto *ExecDomainAA = A.lookupAAFor<AAExecutionDomain>(1110IRPosition::function(Scope), &QueryingAA, DepClassTy::NONE);1111bool AllInSameNoSyncFn = IsAssumedNoSync;1112bool InstIsExecutedByInitialThreadOnly =1113ExecDomainAA && ExecDomainAA->isExecutedByInitialThreadOnly(I);11141115// If the function is not ending in aligned barriers, we need the stores to1116// be in aligned barriers. The load being in one is not sufficient since the1117// store might be executed by a thread that disappears after, causing the1118// aligned barrier guarding the load to unblock and the load to read a value1119// that has no CFG path to the load.1120bool InstIsExecutedInAlignedRegion =1121FindInterferingReads && ExecDomainAA &&1122ExecDomainAA->isExecutedInAlignedRegion(A, I);11231124if (InstIsExecutedInAlignedRegion || InstIsExecutedByInitialThreadOnly)1125A.recordDependence(*ExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);11261127InformationCache &InfoCache = A.getInfoCache();1128bool IsThreadLocalObj =1129AA::isAssumedThreadLocalObject(A, getAssociatedValue(), *this);11301131// Helper to determine if we need to consider threading, which we cannot1132// right now. However, if the function is (assumed) nosync or the thread1133// executing all instructions is the main thread only we can ignore1134// threading. Also, thread-local objects do not require threading reasoning.1135// Finally, we can ignore threading if either access is executed in an1136// aligned region.1137auto CanIgnoreThreadingForInst = [&](const Instruction &I) -> bool {1138if (IsThreadLocalObj || AllInSameNoSyncFn)1139return true;1140const auto *FnExecDomainAA =1141I.getFunction() == &Scope1142? ExecDomainAA1143: A.lookupAAFor<AAExecutionDomain>(1144IRPosition::function(*I.getFunction()), &QueryingAA,1145DepClassTy::NONE);1146if (!FnExecDomainAA)1147return false;1148if (InstIsExecutedInAlignedRegion ||1149(FindInterferingWrites &&1150FnExecDomainAA->isExecutedInAlignedRegion(A, I))) {1151A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);1152return true;1153}1154if (InstIsExecutedByInitialThreadOnly &&1155FnExecDomainAA->isExecutedByInitialThreadOnly(I)) {1156A.recordDependence(*FnExecDomainAA, QueryingAA, DepClassTy::OPTIONAL);1157return true;1158}1159return false;1160};11611162// Helper to determine if the access is executed by the same thread as the1163// given instruction, for now it is sufficient to avoid any potential1164// threading effects as we cannot deal with them anyway.1165auto CanIgnoreThreading = [&](const Access &Acc) -> bool {1166return CanIgnoreThreadingForInst(*Acc.getRemoteInst()) ||1167(Acc.getRemoteInst() != Acc.getLocalInst() &&1168CanIgnoreThreadingForInst(*Acc.getLocalInst()));1169};11701171// TODO: Use inter-procedural reachability and dominance.1172bool IsKnownNoRecurse;1173AA::hasAssumedIRAttr<Attribute::NoRecurse>(1174A, this, IRPosition::function(Scope), DepClassTy::OPTIONAL,1175IsKnownNoRecurse);11761177// TODO: Use reaching kernels from AAKernelInfo (or move it to1178// AAExecutionDomain) such that we allow scopes other than kernels as long1179// as the reaching kernels are disjoint.1180bool InstInKernel = Scope.hasFnAttribute("kernel");1181bool ObjHasKernelLifetime = false;1182const bool UseDominanceReasoning =1183FindInterferingWrites && IsKnownNoRecurse;1184const DominatorTree *DT =1185InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(Scope);11861187// Helper to check if a value has "kernel lifetime", that is it will not1188// outlive a GPU kernel. This is true for shared, constant, and local1189// globals on AMD and NVIDIA GPUs.1190auto HasKernelLifetime = [&](Value *V, Module &M) {1191if (!AA::isGPU(M))1192return false;1193switch (AA::GPUAddressSpace(V->getType()->getPointerAddressSpace())) {1194case AA::GPUAddressSpace::Shared:1195case AA::GPUAddressSpace::Constant:1196case AA::GPUAddressSpace::Local:1197return true;1198default:1199return false;1200};1201};12021203// The IsLiveInCalleeCB will be used by the AA::isPotentiallyReachable query1204// to determine if we should look at reachability from the callee. For1205// certain pointers we know the lifetime and we do not have to step into the1206// callee to determine reachability as the pointer would be dead in the1207// callee. See the conditional initialization below.1208std::function<bool(const Function &)> IsLiveInCalleeCB;12091210if (auto *AI = dyn_cast<AllocaInst>(&getAssociatedValue())) {1211// If the alloca containing function is not recursive the alloca1212// must be dead in the callee.1213const Function *AIFn = AI->getFunction();1214ObjHasKernelLifetime = AIFn->hasFnAttribute("kernel");1215bool IsKnownNoRecurse;1216if (AA::hasAssumedIRAttr<Attribute::NoRecurse>(1217A, this, IRPosition::function(*AIFn), DepClassTy::OPTIONAL,1218IsKnownNoRecurse)) {1219IsLiveInCalleeCB = [AIFn](const Function &Fn) { return AIFn != &Fn; };1220}1221} else if (auto *GV = dyn_cast<GlobalValue>(&getAssociatedValue())) {1222// If the global has kernel lifetime we can stop if we reach a kernel1223// as it is "dead" in the (unknown) callees.1224ObjHasKernelLifetime = HasKernelLifetime(GV, *GV->getParent());1225if (ObjHasKernelLifetime)1226IsLiveInCalleeCB = [](const Function &Fn) {1227return !Fn.hasFnAttribute("kernel");1228};1229}12301231// Set of accesses/instructions that will overwrite the result and are1232// therefore blockers in the reachability traversal.1233AA::InstExclusionSetTy ExclusionSet;12341235auto AccessCB = [&](const Access &Acc, bool Exact) {1236Function *AccScope = Acc.getRemoteInst()->getFunction();1237bool AccInSameScope = AccScope == &Scope;12381239// If the object has kernel lifetime we can ignore accesses only reachable1240// by other kernels. For now we only skip accesses *in* other kernels.1241if (InstInKernel && ObjHasKernelLifetime && !AccInSameScope &&1242AccScope->hasFnAttribute("kernel"))1243return true;12441245if (Exact && Acc.isMustAccess() && Acc.getRemoteInst() != &I) {1246if (Acc.isWrite() || (isa<LoadInst>(I) && Acc.isWriteOrAssumption()))1247ExclusionSet.insert(Acc.getRemoteInst());1248}12491250if ((!FindInterferingWrites || !Acc.isWriteOrAssumption()) &&1251(!FindInterferingReads || !Acc.isRead()))1252return true;12531254bool Dominates = FindInterferingWrites && DT && Exact &&1255Acc.isMustAccess() && AccInSameScope &&1256DT->dominates(Acc.getRemoteInst(), &I);1257if (Dominates)1258DominatingWrites.insert(&Acc);12591260// Track if all interesting accesses are in the same `nosync` function as1261// the given instruction.1262AllInSameNoSyncFn &= Acc.getRemoteInst()->getFunction() == &Scope;12631264InterferingAccesses.push_back({&Acc, Exact});1265return true;1266};1267if (!State::forallInterferingAccesses(I, AccessCB, Range))1268return false;12691270HasBeenWrittenTo = !DominatingWrites.empty();12711272// Dominating writes form a chain, find the least/lowest member.1273Instruction *LeastDominatingWriteInst = nullptr;1274for (const Access *Acc : DominatingWrites) {1275if (!LeastDominatingWriteInst) {1276LeastDominatingWriteInst = Acc->getRemoteInst();1277} else if (DT->dominates(LeastDominatingWriteInst,1278Acc->getRemoteInst())) {1279LeastDominatingWriteInst = Acc->getRemoteInst();1280}1281}12821283// Helper to determine if we can skip a specific write access.1284auto CanSkipAccess = [&](const Access &Acc, bool Exact) {1285if (SkipCB && SkipCB(Acc))1286return true;1287if (!CanIgnoreThreading(Acc))1288return false;12891290// Check read (RAW) dependences and write (WAR) dependences as necessary.1291// If we successfully excluded all effects we are interested in, the1292// access can be skipped.1293bool ReadChecked = !FindInterferingReads;1294bool WriteChecked = !FindInterferingWrites;12951296// If the instruction cannot reach the access, the former does not1297// interfere with what the access reads.1298if (!ReadChecked) {1299if (!AA::isPotentiallyReachable(A, I, *Acc.getRemoteInst(), QueryingAA,1300&ExclusionSet, IsLiveInCalleeCB))1301ReadChecked = true;1302}1303// If the instruction cannot be reach from the access, the latter does not1304// interfere with what the instruction reads.1305if (!WriteChecked) {1306if (!AA::isPotentiallyReachable(A, *Acc.getRemoteInst(), I, QueryingAA,1307&ExclusionSet, IsLiveInCalleeCB))1308WriteChecked = true;1309}13101311// If we still might be affected by the write of the access but there are1312// dominating writes in the function of the instruction1313// (HasBeenWrittenTo), we can try to reason that the access is overwritten1314// by them. This would have happend above if they are all in the same1315// function, so we only check the inter-procedural case. Effectively, we1316// want to show that there is no call after the dominting write that might1317// reach the access, and when it returns reach the instruction with the1318// updated value. To this end, we iterate all call sites, check if they1319// might reach the instruction without going through another access1320// (ExclusionSet) and at the same time might reach the access. However,1321// that is all part of AAInterFnReachability.1322if (!WriteChecked && HasBeenWrittenTo &&1323Acc.getRemoteInst()->getFunction() != &Scope) {13241325const auto *FnReachabilityAA = A.getAAFor<AAInterFnReachability>(1326QueryingAA, IRPosition::function(Scope), DepClassTy::OPTIONAL);13271328// Without going backwards in the call tree, can we reach the access1329// from the least dominating write. Do not allow to pass the instruction1330// itself either.1331bool Inserted = ExclusionSet.insert(&I).second;13321333if (!FnReachabilityAA ||1334!FnReachabilityAA->instructionCanReach(1335A, *LeastDominatingWriteInst,1336*Acc.getRemoteInst()->getFunction(), &ExclusionSet))1337WriteChecked = true;13381339if (Inserted)1340ExclusionSet.erase(&I);1341}13421343if (ReadChecked && WriteChecked)1344return true;13451346if (!DT || !UseDominanceReasoning)1347return false;1348if (!DominatingWrites.count(&Acc))1349return false;1350return LeastDominatingWriteInst != Acc.getRemoteInst();1351};13521353// Run the user callback on all accesses we cannot skip and return if1354// that succeeded for all or not.1355for (auto &It : InterferingAccesses) {1356if ((!AllInSameNoSyncFn && !IsThreadLocalObj && !ExecDomainAA) ||1357!CanSkipAccess(*It.first, It.second)) {1358if (!UserCB(*It.first, It.second))1359return false;1360}1361}1362return true;1363}13641365ChangeStatus translateAndAddStateFromCallee(Attributor &A,1366const AAPointerInfo &OtherAA,1367CallBase &CB) {1368using namespace AA::PointerInfo;1369if (!OtherAA.getState().isValidState() || !isValidState())1370return indicatePessimisticFixpoint();13711372const auto &OtherAAImpl = static_cast<const AAPointerInfoImpl &>(OtherAA);1373bool IsByval = OtherAAImpl.getAssociatedArgument()->hasByValAttr();13741375// Combine the accesses bin by bin.1376ChangeStatus Changed = ChangeStatus::UNCHANGED;1377const auto &State = OtherAAImpl.getState();1378for (const auto &It : State) {1379for (auto Index : It.getSecond()) {1380const auto &RAcc = State.getAccess(Index);1381if (IsByval && !RAcc.isRead())1382continue;1383bool UsedAssumedInformation = false;1384AccessKind AK = RAcc.getKind();1385auto Content = A.translateArgumentToCallSiteContent(1386RAcc.getContent(), CB, *this, UsedAssumedInformation);1387AK = AccessKind(AK & (IsByval ? AccessKind::AK_R : AccessKind::AK_RW));1388AK = AccessKind(AK | (RAcc.isMayAccess() ? AK_MAY : AK_MUST));13891390Changed |= addAccess(A, RAcc.getRanges(), CB, Content, AK,1391RAcc.getType(), RAcc.getRemoteInst());1392}1393}1394return Changed;1395}13961397ChangeStatus translateAndAddState(Attributor &A, const AAPointerInfo &OtherAA,1398const OffsetInfo &Offsets, CallBase &CB) {1399using namespace AA::PointerInfo;1400if (!OtherAA.getState().isValidState() || !isValidState())1401return indicatePessimisticFixpoint();14021403const auto &OtherAAImpl = static_cast<const AAPointerInfoImpl &>(OtherAA);14041405// Combine the accesses bin by bin.1406ChangeStatus Changed = ChangeStatus::UNCHANGED;1407const auto &State = OtherAAImpl.getState();1408for (const auto &It : State) {1409for (auto Index : It.getSecond()) {1410const auto &RAcc = State.getAccess(Index);1411for (auto Offset : Offsets) {1412auto NewRanges = Offset == AA::RangeTy::Unknown1413? AA::RangeTy::getUnknown()1414: RAcc.getRanges();1415if (!NewRanges.isUnknown()) {1416NewRanges.addToAllOffsets(Offset);1417}1418Changed |=1419addAccess(A, NewRanges, CB, RAcc.getContent(), RAcc.getKind(),1420RAcc.getType(), RAcc.getRemoteInst());1421}1422}1423}1424return Changed;1425}14261427/// Statistic tracking for all AAPointerInfo implementations.1428/// See AbstractAttribute::trackStatistics().1429void trackPointerInfoStatistics(const IRPosition &IRP) const {}14301431/// Dump the state into \p O.1432void dumpState(raw_ostream &O) {1433for (auto &It : OffsetBins) {1434O << "[" << It.first.Offset << "-" << It.first.Offset + It.first.Size1435<< "] : " << It.getSecond().size() << "\n";1436for (auto AccIndex : It.getSecond()) {1437auto &Acc = AccessList[AccIndex];1438O << " - " << Acc.getKind() << " - " << *Acc.getLocalInst() << "\n";1439if (Acc.getLocalInst() != Acc.getRemoteInst())1440O << " --> " << *Acc.getRemoteInst()1441<< "\n";1442if (!Acc.isWrittenValueYetUndetermined()) {1443if (isa_and_nonnull<Function>(Acc.getWrittenValue()))1444O << " - c: func " << Acc.getWrittenValue()->getName()1445<< "\n";1446else if (Acc.getWrittenValue())1447O << " - c: " << *Acc.getWrittenValue() << "\n";1448else1449O << " - c: <unknown>\n";1450}1451}1452}1453}1454};14551456struct AAPointerInfoFloating : public AAPointerInfoImpl {1457using AccessKind = AAPointerInfo::AccessKind;1458AAPointerInfoFloating(const IRPosition &IRP, Attributor &A)1459: AAPointerInfoImpl(IRP, A) {}14601461/// Deal with an access and signal if it was handled successfully.1462bool handleAccess(Attributor &A, Instruction &I,1463std::optional<Value *> Content, AccessKind Kind,1464SmallVectorImpl<int64_t> &Offsets, ChangeStatus &Changed,1465Type &Ty) {1466using namespace AA::PointerInfo;1467auto Size = AA::RangeTy::Unknown;1468const DataLayout &DL = A.getDataLayout();1469TypeSize AccessSize = DL.getTypeStoreSize(&Ty);1470if (!AccessSize.isScalable())1471Size = AccessSize.getFixedValue();14721473// Make a strictly ascending list of offsets as required by addAccess()1474llvm::sort(Offsets);1475auto *Last = llvm::unique(Offsets);1476Offsets.erase(Last, Offsets.end());14771478VectorType *VT = dyn_cast<VectorType>(&Ty);1479if (!VT || VT->getElementCount().isScalable() ||1480!Content.value_or(nullptr) || !isa<Constant>(*Content) ||1481(*Content)->getType() != VT ||1482DL.getTypeStoreSize(VT->getElementType()).isScalable()) {1483Changed = Changed | addAccess(A, {Offsets, Size}, I, Content, Kind, &Ty);1484} else {1485// Handle vector stores with constant content element-wise.1486// TODO: We could look for the elements or create instructions1487// representing them.1488// TODO: We need to push the Content into the range abstraction1489// (AA::RangeTy) to allow different content values for different1490// ranges. ranges. Hence, support vectors storing different values.1491Type *ElementType = VT->getElementType();1492int64_t ElementSize = DL.getTypeStoreSize(ElementType).getFixedValue();1493auto *ConstContent = cast<Constant>(*Content);1494Type *Int32Ty = Type::getInt32Ty(ElementType->getContext());1495SmallVector<int64_t> ElementOffsets(Offsets.begin(), Offsets.end());14961497for (int i = 0, e = VT->getElementCount().getFixedValue(); i != e; ++i) {1498Value *ElementContent = ConstantExpr::getExtractElement(1499ConstContent, ConstantInt::get(Int32Ty, i));15001501// Add the element access.1502Changed = Changed | addAccess(A, {ElementOffsets, ElementSize}, I,1503ElementContent, Kind, ElementType);15041505// Advance the offsets for the next element.1506for (auto &ElementOffset : ElementOffsets)1507ElementOffset += ElementSize;1508}1509}1510return true;1511};15121513/// See AbstractAttribute::updateImpl(...).1514ChangeStatus updateImpl(Attributor &A) override;15151516/// If the indices to \p GEP can be traced to constants, incorporate all1517/// of these into \p UsrOI.1518///1519/// \return true iff \p UsrOI is updated.1520bool collectConstantsForGEP(Attributor &A, const DataLayout &DL,1521OffsetInfo &UsrOI, const OffsetInfo &PtrOI,1522const GEPOperator *GEP);15231524/// See AbstractAttribute::trackStatistics()1525void trackStatistics() const override {1526AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());1527}1528};15291530bool AAPointerInfoFloating::collectConstantsForGEP(Attributor &A,1531const DataLayout &DL,1532OffsetInfo &UsrOI,1533const OffsetInfo &PtrOI,1534const GEPOperator *GEP) {1535unsigned BitWidth = DL.getIndexTypeSizeInBits(GEP->getType());1536MapVector<Value *, APInt> VariableOffsets;1537APInt ConstantOffset(BitWidth, 0);15381539assert(!UsrOI.isUnknown() && !PtrOI.isUnknown() &&1540"Don't look for constant values if the offset has already been "1541"determined to be unknown.");15421543if (!GEP->collectOffset(DL, BitWidth, VariableOffsets, ConstantOffset)) {1544UsrOI.setUnknown();1545return true;1546}15471548LLVM_DEBUG(dbgs() << "[AAPointerInfo] GEP offset is "1549<< (VariableOffsets.empty() ? "" : "not") << " constant "1550<< *GEP << "\n");15511552auto Union = PtrOI;1553Union.addToAll(ConstantOffset.getSExtValue());15541555// Each VI in VariableOffsets has a set of potential constant values. Every1556// combination of elements, picked one each from these sets, is separately1557// added to the original set of offsets, thus resulting in more offsets.1558for (const auto &VI : VariableOffsets) {1559auto *PotentialConstantsAA = A.getAAFor<AAPotentialConstantValues>(1560*this, IRPosition::value(*VI.first), DepClassTy::OPTIONAL);1561if (!PotentialConstantsAA || !PotentialConstantsAA->isValidState()) {1562UsrOI.setUnknown();1563return true;1564}15651566// UndefValue is treated as a zero, which leaves Union as is.1567if (PotentialConstantsAA->undefIsContained())1568continue;15691570// We need at least one constant in every set to compute an actual offset.1571// Otherwise, we end up pessimizing AAPointerInfo by respecting offsets that1572// don't actually exist. In other words, the absence of constant values1573// implies that the operation can be assumed dead for now.1574auto &AssumedSet = PotentialConstantsAA->getAssumedSet();1575if (AssumedSet.empty())1576return false;15771578OffsetInfo Product;1579for (const auto &ConstOffset : AssumedSet) {1580auto CopyPerOffset = Union;1581CopyPerOffset.addToAll(ConstOffset.getSExtValue() *1582VI.second.getZExtValue());1583Product.merge(CopyPerOffset);1584}1585Union = Product;1586}15871588UsrOI = std::move(Union);1589return true;1590}15911592ChangeStatus AAPointerInfoFloating::updateImpl(Attributor &A) {1593using namespace AA::PointerInfo;1594ChangeStatus Changed = ChangeStatus::UNCHANGED;1595const DataLayout &DL = A.getDataLayout();1596Value &AssociatedValue = getAssociatedValue();15971598DenseMap<Value *, OffsetInfo> OffsetInfoMap;1599OffsetInfoMap[&AssociatedValue].insert(0);16001601auto HandlePassthroughUser = [&](Value *Usr, Value *CurPtr, bool &Follow) {1602// One does not simply walk into a map and assign a reference to a possibly1603// new location. That can cause an invalidation before the assignment1604// happens, like so:1605//1606// OffsetInfoMap[Usr] = OffsetInfoMap[CurPtr]; /* bad idea! */1607//1608// The RHS is a reference that may be invalidated by an insertion caused by1609// the LHS. So we ensure that the side-effect of the LHS happens first.16101611assert(OffsetInfoMap.contains(CurPtr) &&1612"CurPtr does not exist in the map!");16131614auto &UsrOI = OffsetInfoMap[Usr];1615auto &PtrOI = OffsetInfoMap[CurPtr];1616assert(!PtrOI.isUnassigned() &&1617"Cannot pass through if the input Ptr was not visited!");1618UsrOI.merge(PtrOI);1619Follow = true;1620return true;1621};16221623auto UsePred = [&](const Use &U, bool &Follow) -> bool {1624Value *CurPtr = U.get();1625User *Usr = U.getUser();1626LLVM_DEBUG(dbgs() << "[AAPointerInfo] Analyze " << *CurPtr << " in " << *Usr1627<< "\n");1628assert(OffsetInfoMap.count(CurPtr) &&1629"The current pointer offset should have been seeded!");16301631if (ConstantExpr *CE = dyn_cast<ConstantExpr>(Usr)) {1632if (CE->isCast())1633return HandlePassthroughUser(Usr, CurPtr, Follow);1634if (!isa<GEPOperator>(CE)) {1635LLVM_DEBUG(dbgs() << "[AAPointerInfo] Unhandled constant user " << *CE1636<< "\n");1637return false;1638}1639}1640if (auto *GEP = dyn_cast<GEPOperator>(Usr)) {1641// Note the order here, the Usr access might change the map, CurPtr is1642// already in it though.1643auto &UsrOI = OffsetInfoMap[Usr];1644auto &PtrOI = OffsetInfoMap[CurPtr];16451646if (UsrOI.isUnknown())1647return true;16481649if (PtrOI.isUnknown()) {1650Follow = true;1651UsrOI.setUnknown();1652return true;1653}16541655Follow = collectConstantsForGEP(A, DL, UsrOI, PtrOI, GEP);1656return true;1657}1658if (isa<PtrToIntInst>(Usr))1659return false;1660if (isa<CastInst>(Usr) || isa<SelectInst>(Usr) || isa<ReturnInst>(Usr))1661return HandlePassthroughUser(Usr, CurPtr, Follow);16621663// For PHIs we need to take care of the recurrence explicitly as the value1664// might change while we iterate through a loop. For now, we give up if1665// the PHI is not invariant.1666if (auto *PHI = dyn_cast<PHINode>(Usr)) {1667// Note the order here, the Usr access might change the map, CurPtr is1668// already in it though.1669bool IsFirstPHIUser = !OffsetInfoMap.count(PHI);1670auto &UsrOI = OffsetInfoMap[PHI];1671auto &PtrOI = OffsetInfoMap[CurPtr];16721673// Check if the PHI operand has already an unknown offset as we can't1674// improve on that anymore.1675if (PtrOI.isUnknown()) {1676LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI operand offset unknown "1677<< *CurPtr << " in " << *PHI << "\n");1678Follow = !UsrOI.isUnknown();1679UsrOI.setUnknown();1680return true;1681}16821683// Check if the PHI is invariant (so far).1684if (UsrOI == PtrOI) {1685assert(!PtrOI.isUnassigned() &&1686"Cannot assign if the current Ptr was not visited!");1687LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI is invariant (so far)");1688return true;1689}16901691// Check if the PHI operand can be traced back to AssociatedValue.1692APInt Offset(1693DL.getIndexSizeInBits(CurPtr->getType()->getPointerAddressSpace()),16940);1695Value *CurPtrBase = CurPtr->stripAndAccumulateConstantOffsets(1696DL, Offset, /* AllowNonInbounds */ true);1697auto It = OffsetInfoMap.find(CurPtrBase);1698if (It == OffsetInfoMap.end()) {1699LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI operand is too complex "1700<< *CurPtr << " in " << *PHI1701<< " (base: " << *CurPtrBase << ")\n");1702UsrOI.setUnknown();1703Follow = true;1704return true;1705}17061707// Check if the PHI operand is not dependent on the PHI itself. Every1708// recurrence is a cyclic net of PHIs in the data flow, and has an1709// equivalent Cycle in the control flow. One of those PHIs must be in the1710// header of that control flow Cycle. This is independent of the choice of1711// Cycles reported by CycleInfo. It is sufficient to check the PHIs in1712// every Cycle header; if such a node is marked unknown, this will1713// eventually propagate through the whole net of PHIs in the recurrence.1714const auto *CI =1715A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(1716*PHI->getFunction());1717if (mayBeInCycle(CI, cast<Instruction>(Usr), /* HeaderOnly */ true)) {1718auto BaseOI = It->getSecond();1719BaseOI.addToAll(Offset.getZExtValue());1720if (IsFirstPHIUser || BaseOI == UsrOI) {1721LLVM_DEBUG(dbgs() << "[AAPointerInfo] PHI is invariant " << *CurPtr1722<< " in " << *Usr << "\n");1723return HandlePassthroughUser(Usr, CurPtr, Follow);1724}17251726LLVM_DEBUG(1727dbgs() << "[AAPointerInfo] PHI operand pointer offset mismatch "1728<< *CurPtr << " in " << *PHI << "\n");1729UsrOI.setUnknown();1730Follow = true;1731return true;1732}17331734UsrOI.merge(PtrOI);1735Follow = true;1736return true;1737}17381739if (auto *LoadI = dyn_cast<LoadInst>(Usr)) {1740// If the access is to a pointer that may or may not be the associated1741// value, e.g. due to a PHI, we cannot assume it will be read.1742AccessKind AK = AccessKind::AK_R;1743if (getUnderlyingObject(CurPtr) == &AssociatedValue)1744AK = AccessKind(AK | AccessKind::AK_MUST);1745else1746AK = AccessKind(AK | AccessKind::AK_MAY);1747if (!handleAccess(A, *LoadI, /* Content */ nullptr, AK,1748OffsetInfoMap[CurPtr].Offsets, Changed,1749*LoadI->getType()))1750return false;17511752auto IsAssumption = [](Instruction &I) {1753if (auto *II = dyn_cast<IntrinsicInst>(&I))1754return II->isAssumeLikeIntrinsic();1755return false;1756};17571758auto IsImpactedInRange = [&](Instruction *FromI, Instruction *ToI) {1759// Check if the assumption and the load are executed together without1760// memory modification.1761do {1762if (FromI->mayWriteToMemory() && !IsAssumption(*FromI))1763return true;1764FromI = FromI->getNextNonDebugInstruction();1765} while (FromI && FromI != ToI);1766return false;1767};17681769BasicBlock *BB = LoadI->getParent();1770auto IsValidAssume = [&](IntrinsicInst &IntrI) {1771if (IntrI.getIntrinsicID() != Intrinsic::assume)1772return false;1773BasicBlock *IntrBB = IntrI.getParent();1774if (IntrI.getParent() == BB) {1775if (IsImpactedInRange(LoadI->getNextNonDebugInstruction(), &IntrI))1776return false;1777} else {1778auto PredIt = pred_begin(IntrBB);1779if (PredIt == pred_end(IntrBB))1780return false;1781if ((*PredIt) != BB)1782return false;1783if (++PredIt != pred_end(IntrBB))1784return false;1785for (auto *SuccBB : successors(BB)) {1786if (SuccBB == IntrBB)1787continue;1788if (isa<UnreachableInst>(SuccBB->getTerminator()))1789continue;1790return false;1791}1792if (IsImpactedInRange(LoadI->getNextNonDebugInstruction(),1793BB->getTerminator()))1794return false;1795if (IsImpactedInRange(&IntrBB->front(), &IntrI))1796return false;1797}1798return true;1799};18001801std::pair<Value *, IntrinsicInst *> Assumption;1802for (const Use &LoadU : LoadI->uses()) {1803if (auto *CmpI = dyn_cast<CmpInst>(LoadU.getUser())) {1804if (!CmpI->isEquality() || !CmpI->isTrueWhenEqual())1805continue;1806for (const Use &CmpU : CmpI->uses()) {1807if (auto *IntrI = dyn_cast<IntrinsicInst>(CmpU.getUser())) {1808if (!IsValidAssume(*IntrI))1809continue;1810int Idx = CmpI->getOperandUse(0) == LoadU;1811Assumption = {CmpI->getOperand(Idx), IntrI};1812break;1813}1814}1815}1816if (Assumption.first)1817break;1818}18191820// Check if we found an assumption associated with this load.1821if (!Assumption.first || !Assumption.second)1822return true;18231824LLVM_DEBUG(dbgs() << "[AAPointerInfo] Assumption found "1825<< *Assumption.second << ": " << *LoadI1826<< " == " << *Assumption.first << "\n");1827bool UsedAssumedInformation = false;1828std::optional<Value *> Content = nullptr;1829if (Assumption.first)1830Content =1831A.getAssumedSimplified(*Assumption.first, *this,1832UsedAssumedInformation, AA::Interprocedural);1833return handleAccess(1834A, *Assumption.second, Content, AccessKind::AK_ASSUMPTION,1835OffsetInfoMap[CurPtr].Offsets, Changed, *LoadI->getType());1836}18371838auto HandleStoreLike = [&](Instruction &I, Value *ValueOp, Type &ValueTy,1839ArrayRef<Value *> OtherOps, AccessKind AK) {1840for (auto *OtherOp : OtherOps) {1841if (OtherOp == CurPtr) {1842LLVM_DEBUG(1843dbgs()1844<< "[AAPointerInfo] Escaping use in store like instruction " << I1845<< "\n");1846return false;1847}1848}18491850// If the access is to a pointer that may or may not be the associated1851// value, e.g. due to a PHI, we cannot assume it will be written.1852if (getUnderlyingObject(CurPtr) == &AssociatedValue)1853AK = AccessKind(AK | AccessKind::AK_MUST);1854else1855AK = AccessKind(AK | AccessKind::AK_MAY);1856bool UsedAssumedInformation = false;1857std::optional<Value *> Content = nullptr;1858if (ValueOp)1859Content = A.getAssumedSimplified(1860*ValueOp, *this, UsedAssumedInformation, AA::Interprocedural);1861return handleAccess(A, I, Content, AK, OffsetInfoMap[CurPtr].Offsets,1862Changed, ValueTy);1863};18641865if (auto *StoreI = dyn_cast<StoreInst>(Usr))1866return HandleStoreLike(*StoreI, StoreI->getValueOperand(),1867*StoreI->getValueOperand()->getType(),1868{StoreI->getValueOperand()}, AccessKind::AK_W);1869if (auto *RMWI = dyn_cast<AtomicRMWInst>(Usr))1870return HandleStoreLike(*RMWI, nullptr, *RMWI->getValOperand()->getType(),1871{RMWI->getValOperand()}, AccessKind::AK_RW);1872if (auto *CXI = dyn_cast<AtomicCmpXchgInst>(Usr))1873return HandleStoreLike(1874*CXI, nullptr, *CXI->getNewValOperand()->getType(),1875{CXI->getCompareOperand(), CXI->getNewValOperand()},1876AccessKind::AK_RW);18771878if (auto *CB = dyn_cast<CallBase>(Usr)) {1879if (CB->isLifetimeStartOrEnd())1880return true;1881const auto *TLI =1882A.getInfoCache().getTargetLibraryInfoForFunction(*CB->getFunction());1883if (getFreedOperand(CB, TLI) == U)1884return true;1885if (CB->isArgOperand(&U)) {1886unsigned ArgNo = CB->getArgOperandNo(&U);1887const auto *CSArgPI = A.getAAFor<AAPointerInfo>(1888*this, IRPosition::callsite_argument(*CB, ArgNo),1889DepClassTy::REQUIRED);1890if (!CSArgPI)1891return false;1892Changed =1893translateAndAddState(A, *CSArgPI, OffsetInfoMap[CurPtr], *CB) |1894Changed;1895return isValidState();1896}1897LLVM_DEBUG(dbgs() << "[AAPointerInfo] Call user not handled " << *CB1898<< "\n");1899// TODO: Allow some call uses1900return false;1901}19021903LLVM_DEBUG(dbgs() << "[AAPointerInfo] User not handled " << *Usr << "\n");1904return false;1905};1906auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) {1907assert(OffsetInfoMap.count(OldU) && "Old use should be known already!");1908if (OffsetInfoMap.count(NewU)) {1909LLVM_DEBUG({1910if (!(OffsetInfoMap[NewU] == OffsetInfoMap[OldU])) {1911dbgs() << "[AAPointerInfo] Equivalent use callback failed: "1912<< OffsetInfoMap[NewU] << " vs " << OffsetInfoMap[OldU]1913<< "\n";1914}1915});1916return OffsetInfoMap[NewU] == OffsetInfoMap[OldU];1917}1918OffsetInfoMap[NewU] = OffsetInfoMap[OldU];1919return true;1920};1921if (!A.checkForAllUses(UsePred, *this, AssociatedValue,1922/* CheckBBLivenessOnly */ true, DepClassTy::OPTIONAL,1923/* IgnoreDroppableUses */ true, EquivalentUseCB)) {1924LLVM_DEBUG(dbgs() << "[AAPointerInfo] Check for all uses failed, abort!\n");1925return indicatePessimisticFixpoint();1926}19271928LLVM_DEBUG({1929dbgs() << "Accesses by bin after update:\n";1930dumpState(dbgs());1931});19321933return Changed;1934}19351936struct AAPointerInfoReturned final : AAPointerInfoImpl {1937AAPointerInfoReturned(const IRPosition &IRP, Attributor &A)1938: AAPointerInfoImpl(IRP, A) {}19391940/// See AbstractAttribute::updateImpl(...).1941ChangeStatus updateImpl(Attributor &A) override {1942return indicatePessimisticFixpoint();1943}19441945/// See AbstractAttribute::trackStatistics()1946void trackStatistics() const override {1947AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());1948}1949};19501951struct AAPointerInfoArgument final : AAPointerInfoFloating {1952AAPointerInfoArgument(const IRPosition &IRP, Attributor &A)1953: AAPointerInfoFloating(IRP, A) {}19541955/// See AbstractAttribute::trackStatistics()1956void trackStatistics() const override {1957AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());1958}1959};19601961struct AAPointerInfoCallSiteArgument final : AAPointerInfoFloating {1962AAPointerInfoCallSiteArgument(const IRPosition &IRP, Attributor &A)1963: AAPointerInfoFloating(IRP, A) {}19641965/// See AbstractAttribute::updateImpl(...).1966ChangeStatus updateImpl(Attributor &A) override {1967using namespace AA::PointerInfo;1968// We handle memory intrinsics explicitly, at least the first (=1969// destination) and second (=source) arguments as we know how they are1970// accessed.1971if (auto *MI = dyn_cast_or_null<MemIntrinsic>(getCtxI())) {1972ConstantInt *Length = dyn_cast<ConstantInt>(MI->getLength());1973int64_t LengthVal = AA::RangeTy::Unknown;1974if (Length)1975LengthVal = Length->getSExtValue();1976unsigned ArgNo = getIRPosition().getCallSiteArgNo();1977ChangeStatus Changed = ChangeStatus::UNCHANGED;1978if (ArgNo > 1) {1979LLVM_DEBUG(dbgs() << "[AAPointerInfo] Unhandled memory intrinsic "1980<< *MI << "\n");1981return indicatePessimisticFixpoint();1982} else {1983auto Kind =1984ArgNo == 0 ? AccessKind::AK_MUST_WRITE : AccessKind::AK_MUST_READ;1985Changed =1986Changed | addAccess(A, {0, LengthVal}, *MI, nullptr, Kind, nullptr);1987}1988LLVM_DEBUG({1989dbgs() << "Accesses by bin after update:\n";1990dumpState(dbgs());1991});19921993return Changed;1994}19951996// TODO: Once we have call site specific value information we can provide1997// call site specific liveness information and then it makes1998// sense to specialize attributes for call sites arguments instead of1999// redirecting requests to the callee argument.2000Argument *Arg = getAssociatedArgument();2001if (Arg) {2002const IRPosition &ArgPos = IRPosition::argument(*Arg);2003auto *ArgAA =2004A.getAAFor<AAPointerInfo>(*this, ArgPos, DepClassTy::REQUIRED);2005if (ArgAA && ArgAA->getState().isValidState())2006return translateAndAddStateFromCallee(A, *ArgAA,2007*cast<CallBase>(getCtxI()));2008if (!Arg->getParent()->isDeclaration())2009return indicatePessimisticFixpoint();2010}20112012bool IsKnownNoCapture;2013if (!AA::hasAssumedIRAttr<Attribute::NoCapture>(2014A, this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoCapture))2015return indicatePessimisticFixpoint();20162017bool IsKnown = false;2018if (AA::isAssumedReadNone(A, getIRPosition(), *this, IsKnown))2019return ChangeStatus::UNCHANGED;2020bool ReadOnly = AA::isAssumedReadOnly(A, getIRPosition(), *this, IsKnown);2021auto Kind =2022ReadOnly ? AccessKind::AK_MAY_READ : AccessKind::AK_MAY_READ_WRITE;2023return addAccess(A, AA::RangeTy::getUnknown(), *getCtxI(), nullptr, Kind,2024nullptr);2025}20262027/// See AbstractAttribute::trackStatistics()2028void trackStatistics() const override {2029AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());2030}2031};20322033struct AAPointerInfoCallSiteReturned final : AAPointerInfoFloating {2034AAPointerInfoCallSiteReturned(const IRPosition &IRP, Attributor &A)2035: AAPointerInfoFloating(IRP, A) {}20362037/// See AbstractAttribute::trackStatistics()2038void trackStatistics() const override {2039AAPointerInfoImpl::trackPointerInfoStatistics(getIRPosition());2040}2041};2042} // namespace20432044/// -----------------------NoUnwind Function Attribute--------------------------20452046namespace {2047struct AANoUnwindImpl : AANoUnwind {2048AANoUnwindImpl(const IRPosition &IRP, Attributor &A) : AANoUnwind(IRP, A) {}20492050/// See AbstractAttribute::initialize(...).2051void initialize(Attributor &A) override {2052bool IsKnown;2053assert(!AA::hasAssumedIRAttr<Attribute::NoUnwind>(2054A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));2055(void)IsKnown;2056}20572058const std::string getAsStr(Attributor *A) const override {2059return getAssumed() ? "nounwind" : "may-unwind";2060}20612062/// See AbstractAttribute::updateImpl(...).2063ChangeStatus updateImpl(Attributor &A) override {2064auto Opcodes = {2065(unsigned)Instruction::Invoke, (unsigned)Instruction::CallBr,2066(unsigned)Instruction::Call, (unsigned)Instruction::CleanupRet,2067(unsigned)Instruction::CatchSwitch, (unsigned)Instruction::Resume};20682069auto CheckForNoUnwind = [&](Instruction &I) {2070if (!I.mayThrow(/* IncludePhaseOneUnwind */ true))2071return true;20722073if (const auto *CB = dyn_cast<CallBase>(&I)) {2074bool IsKnownNoUnwind;2075return AA::hasAssumedIRAttr<Attribute::NoUnwind>(2076A, this, IRPosition::callsite_function(*CB), DepClassTy::REQUIRED,2077IsKnownNoUnwind);2078}2079return false;2080};20812082bool UsedAssumedInformation = false;2083if (!A.checkForAllInstructions(CheckForNoUnwind, *this, Opcodes,2084UsedAssumedInformation))2085return indicatePessimisticFixpoint();20862087return ChangeStatus::UNCHANGED;2088}2089};20902091struct AANoUnwindFunction final : public AANoUnwindImpl {2092AANoUnwindFunction(const IRPosition &IRP, Attributor &A)2093: AANoUnwindImpl(IRP, A) {}20942095/// See AbstractAttribute::trackStatistics()2096void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nounwind) }2097};20982099/// NoUnwind attribute deduction for a call sites.2100struct AANoUnwindCallSite final2101: AACalleeToCallSite<AANoUnwind, AANoUnwindImpl> {2102AANoUnwindCallSite(const IRPosition &IRP, Attributor &A)2103: AACalleeToCallSite<AANoUnwind, AANoUnwindImpl>(IRP, A) {}21042105/// See AbstractAttribute::trackStatistics()2106void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nounwind); }2107};2108} // namespace21092110/// ------------------------ NoSync Function Attribute -------------------------21112112bool AANoSync::isAlignedBarrier(const CallBase &CB, bool ExecutedAligned) {2113switch (CB.getIntrinsicID()) {2114case Intrinsic::nvvm_barrier0:2115case Intrinsic::nvvm_barrier0_and:2116case Intrinsic::nvvm_barrier0_or:2117case Intrinsic::nvvm_barrier0_popc:2118return true;2119case Intrinsic::amdgcn_s_barrier:2120if (ExecutedAligned)2121return true;2122break;2123default:2124break;2125}2126return hasAssumption(CB, KnownAssumptionString("ompx_aligned_barrier"));2127}21282129bool AANoSync::isNonRelaxedAtomic(const Instruction *I) {2130if (!I->isAtomic())2131return false;21322133if (auto *FI = dyn_cast<FenceInst>(I))2134// All legal orderings for fence are stronger than monotonic.2135return FI->getSyncScopeID() != SyncScope::SingleThread;2136if (auto *AI = dyn_cast<AtomicCmpXchgInst>(I)) {2137// Unordered is not a legal ordering for cmpxchg.2138return (AI->getSuccessOrdering() != AtomicOrdering::Monotonic ||2139AI->getFailureOrdering() != AtomicOrdering::Monotonic);2140}21412142AtomicOrdering Ordering;2143switch (I->getOpcode()) {2144case Instruction::AtomicRMW:2145Ordering = cast<AtomicRMWInst>(I)->getOrdering();2146break;2147case Instruction::Store:2148Ordering = cast<StoreInst>(I)->getOrdering();2149break;2150case Instruction::Load:2151Ordering = cast<LoadInst>(I)->getOrdering();2152break;2153default:2154llvm_unreachable(2155"New atomic operations need to be known in the attributor.");2156}21572158return (Ordering != AtomicOrdering::Unordered &&2159Ordering != AtomicOrdering::Monotonic);2160}21612162/// Return true if this intrinsic is nosync. This is only used for intrinsics2163/// which would be nosync except that they have a volatile flag. All other2164/// intrinsics are simply annotated with the nosync attribute in Intrinsics.td.2165bool AANoSync::isNoSyncIntrinsic(const Instruction *I) {2166if (auto *MI = dyn_cast<MemIntrinsic>(I))2167return !MI->isVolatile();2168return false;2169}21702171namespace {2172struct AANoSyncImpl : AANoSync {2173AANoSyncImpl(const IRPosition &IRP, Attributor &A) : AANoSync(IRP, A) {}21742175/// See AbstractAttribute::initialize(...).2176void initialize(Attributor &A) override {2177bool IsKnown;2178assert(!AA::hasAssumedIRAttr<Attribute::NoSync>(A, nullptr, getIRPosition(),2179DepClassTy::NONE, IsKnown));2180(void)IsKnown;2181}21822183const std::string getAsStr(Attributor *A) const override {2184return getAssumed() ? "nosync" : "may-sync";2185}21862187/// See AbstractAttribute::updateImpl(...).2188ChangeStatus updateImpl(Attributor &A) override;2189};21902191ChangeStatus AANoSyncImpl::updateImpl(Attributor &A) {21922193auto CheckRWInstForNoSync = [&](Instruction &I) {2194return AA::isNoSyncInst(A, I, *this);2195};21962197auto CheckForNoSync = [&](Instruction &I) {2198// At this point we handled all read/write effects and they are all2199// nosync, so they can be skipped.2200if (I.mayReadOrWriteMemory())2201return true;22022203bool IsKnown;2204CallBase &CB = cast<CallBase>(I);2205if (AA::hasAssumedIRAttr<Attribute::NoSync>(2206A, this, IRPosition::callsite_function(CB), DepClassTy::OPTIONAL,2207IsKnown))2208return true;22092210// non-convergent and readnone imply nosync.2211return !CB.isConvergent();2212};22132214bool UsedAssumedInformation = false;2215if (!A.checkForAllReadWriteInstructions(CheckRWInstForNoSync, *this,2216UsedAssumedInformation) ||2217!A.checkForAllCallLikeInstructions(CheckForNoSync, *this,2218UsedAssumedInformation))2219return indicatePessimisticFixpoint();22202221return ChangeStatus::UNCHANGED;2222}22232224struct AANoSyncFunction final : public AANoSyncImpl {2225AANoSyncFunction(const IRPosition &IRP, Attributor &A)2226: AANoSyncImpl(IRP, A) {}22272228/// See AbstractAttribute::trackStatistics()2229void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nosync) }2230};22312232/// NoSync attribute deduction for a call sites.2233struct AANoSyncCallSite final : AACalleeToCallSite<AANoSync, AANoSyncImpl> {2234AANoSyncCallSite(const IRPosition &IRP, Attributor &A)2235: AACalleeToCallSite<AANoSync, AANoSyncImpl>(IRP, A) {}22362237/// See AbstractAttribute::trackStatistics()2238void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nosync); }2239};2240} // namespace22412242/// ------------------------ No-Free Attributes ----------------------------22432244namespace {2245struct AANoFreeImpl : public AANoFree {2246AANoFreeImpl(const IRPosition &IRP, Attributor &A) : AANoFree(IRP, A) {}22472248/// See AbstractAttribute::initialize(...).2249void initialize(Attributor &A) override {2250bool IsKnown;2251assert(!AA::hasAssumedIRAttr<Attribute::NoFree>(A, nullptr, getIRPosition(),2252DepClassTy::NONE, IsKnown));2253(void)IsKnown;2254}22552256/// See AbstractAttribute::updateImpl(...).2257ChangeStatus updateImpl(Attributor &A) override {2258auto CheckForNoFree = [&](Instruction &I) {2259bool IsKnown;2260return AA::hasAssumedIRAttr<Attribute::NoFree>(2261A, this, IRPosition::callsite_function(cast<CallBase>(I)),2262DepClassTy::REQUIRED, IsKnown);2263};22642265bool UsedAssumedInformation = false;2266if (!A.checkForAllCallLikeInstructions(CheckForNoFree, *this,2267UsedAssumedInformation))2268return indicatePessimisticFixpoint();2269return ChangeStatus::UNCHANGED;2270}22712272/// See AbstractAttribute::getAsStr().2273const std::string getAsStr(Attributor *A) const override {2274return getAssumed() ? "nofree" : "may-free";2275}2276};22772278struct AANoFreeFunction final : public AANoFreeImpl {2279AANoFreeFunction(const IRPosition &IRP, Attributor &A)2280: AANoFreeImpl(IRP, A) {}22812282/// See AbstractAttribute::trackStatistics()2283void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(nofree) }2284};22852286/// NoFree attribute deduction for a call sites.2287struct AANoFreeCallSite final : AACalleeToCallSite<AANoFree, AANoFreeImpl> {2288AANoFreeCallSite(const IRPosition &IRP, Attributor &A)2289: AACalleeToCallSite<AANoFree, AANoFreeImpl>(IRP, A) {}22902291/// See AbstractAttribute::trackStatistics()2292void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(nofree); }2293};22942295/// NoFree attribute for floating values.2296struct AANoFreeFloating : AANoFreeImpl {2297AANoFreeFloating(const IRPosition &IRP, Attributor &A)2298: AANoFreeImpl(IRP, A) {}22992300/// See AbstractAttribute::trackStatistics()2301void trackStatistics() const override{STATS_DECLTRACK_FLOATING_ATTR(nofree)}23022303/// See Abstract Attribute::updateImpl(...).2304ChangeStatus updateImpl(Attributor &A) override {2305const IRPosition &IRP = getIRPosition();23062307bool IsKnown;2308if (AA::hasAssumedIRAttr<Attribute::NoFree>(A, this,2309IRPosition::function_scope(IRP),2310DepClassTy::OPTIONAL, IsKnown))2311return ChangeStatus::UNCHANGED;23122313Value &AssociatedValue = getIRPosition().getAssociatedValue();2314auto Pred = [&](const Use &U, bool &Follow) -> bool {2315Instruction *UserI = cast<Instruction>(U.getUser());2316if (auto *CB = dyn_cast<CallBase>(UserI)) {2317if (CB->isBundleOperand(&U))2318return false;2319if (!CB->isArgOperand(&U))2320return true;2321unsigned ArgNo = CB->getArgOperandNo(&U);23222323bool IsKnown;2324return AA::hasAssumedIRAttr<Attribute::NoFree>(2325A, this, IRPosition::callsite_argument(*CB, ArgNo),2326DepClassTy::REQUIRED, IsKnown);2327}23282329if (isa<GetElementPtrInst>(UserI) || isa<BitCastInst>(UserI) ||2330isa<PHINode>(UserI) || isa<SelectInst>(UserI)) {2331Follow = true;2332return true;2333}2334if (isa<StoreInst>(UserI) || isa<LoadInst>(UserI) ||2335isa<ReturnInst>(UserI))2336return true;23372338// Unknown user.2339return false;2340};2341if (!A.checkForAllUses(Pred, *this, AssociatedValue))2342return indicatePessimisticFixpoint();23432344return ChangeStatus::UNCHANGED;2345}2346};23472348/// NoFree attribute for a call site argument.2349struct AANoFreeArgument final : AANoFreeFloating {2350AANoFreeArgument(const IRPosition &IRP, Attributor &A)2351: AANoFreeFloating(IRP, A) {}23522353/// See AbstractAttribute::trackStatistics()2354void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nofree) }2355};23562357/// NoFree attribute for call site arguments.2358struct AANoFreeCallSiteArgument final : AANoFreeFloating {2359AANoFreeCallSiteArgument(const IRPosition &IRP, Attributor &A)2360: AANoFreeFloating(IRP, A) {}23612362/// See AbstractAttribute::updateImpl(...).2363ChangeStatus updateImpl(Attributor &A) override {2364// TODO: Once we have call site specific value information we can provide2365// call site specific liveness information and then it makes2366// sense to specialize attributes for call sites arguments instead of2367// redirecting requests to the callee argument.2368Argument *Arg = getAssociatedArgument();2369if (!Arg)2370return indicatePessimisticFixpoint();2371const IRPosition &ArgPos = IRPosition::argument(*Arg);2372bool IsKnown;2373if (AA::hasAssumedIRAttr<Attribute::NoFree>(A, this, ArgPos,2374DepClassTy::REQUIRED, IsKnown))2375return ChangeStatus::UNCHANGED;2376return indicatePessimisticFixpoint();2377}23782379/// See AbstractAttribute::trackStatistics()2380void trackStatistics() const override{STATS_DECLTRACK_CSARG_ATTR(nofree)};2381};23822383/// NoFree attribute for function return value.2384struct AANoFreeReturned final : AANoFreeFloating {2385AANoFreeReturned(const IRPosition &IRP, Attributor &A)2386: AANoFreeFloating(IRP, A) {2387llvm_unreachable("NoFree is not applicable to function returns!");2388}23892390/// See AbstractAttribute::initialize(...).2391void initialize(Attributor &A) override {2392llvm_unreachable("NoFree is not applicable to function returns!");2393}23942395/// See AbstractAttribute::updateImpl(...).2396ChangeStatus updateImpl(Attributor &A) override {2397llvm_unreachable("NoFree is not applicable to function returns!");2398}23992400/// See AbstractAttribute::trackStatistics()2401void trackStatistics() const override {}2402};24032404/// NoFree attribute deduction for a call site return value.2405struct AANoFreeCallSiteReturned final : AANoFreeFloating {2406AANoFreeCallSiteReturned(const IRPosition &IRP, Attributor &A)2407: AANoFreeFloating(IRP, A) {}24082409ChangeStatus manifest(Attributor &A) override {2410return ChangeStatus::UNCHANGED;2411}2412/// See AbstractAttribute::trackStatistics()2413void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nofree) }2414};2415} // namespace24162417/// ------------------------ NonNull Argument Attribute ------------------------24182419bool AANonNull::isImpliedByIR(Attributor &A, const IRPosition &IRP,2420Attribute::AttrKind ImpliedAttributeKind,2421bool IgnoreSubsumingPositions) {2422SmallVector<Attribute::AttrKind, 2> AttrKinds;2423AttrKinds.push_back(Attribute::NonNull);2424if (!NullPointerIsDefined(IRP.getAnchorScope(),2425IRP.getAssociatedType()->getPointerAddressSpace()))2426AttrKinds.push_back(Attribute::Dereferenceable);2427if (A.hasAttr(IRP, AttrKinds, IgnoreSubsumingPositions, Attribute::NonNull))2428return true;24292430DominatorTree *DT = nullptr;2431AssumptionCache *AC = nullptr;2432InformationCache &InfoCache = A.getInfoCache();2433if (const Function *Fn = IRP.getAnchorScope()) {2434if (!Fn->isDeclaration()) {2435DT = InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*Fn);2436AC = InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*Fn);2437}2438}24392440SmallVector<AA::ValueAndContext> Worklist;2441if (IRP.getPositionKind() != IRP_RETURNED) {2442Worklist.push_back({IRP.getAssociatedValue(), IRP.getCtxI()});2443} else {2444bool UsedAssumedInformation = false;2445if (!A.checkForAllInstructions(2446[&](Instruction &I) {2447Worklist.push_back({*cast<ReturnInst>(I).getReturnValue(), &I});2448return true;2449},2450IRP.getAssociatedFunction(), nullptr, {Instruction::Ret},2451UsedAssumedInformation, false, /*CheckPotentiallyDead=*/true))2452return false;2453}24542455if (llvm::any_of(Worklist, [&](AA::ValueAndContext VAC) {2456return !isKnownNonZero(2457VAC.getValue(),2458SimplifyQuery(A.getDataLayout(), DT, AC, VAC.getCtxI()));2459}))2460return false;24612462A.manifestAttrs(IRP, {Attribute::get(IRP.getAnchorValue().getContext(),2463Attribute::NonNull)});2464return true;2465}24662467namespace {2468static int64_t getKnownNonNullAndDerefBytesForUse(2469Attributor &A, const AbstractAttribute &QueryingAA, Value &AssociatedValue,2470const Use *U, const Instruction *I, bool &IsNonNull, bool &TrackUse) {2471TrackUse = false;24722473const Value *UseV = U->get();2474if (!UseV->getType()->isPointerTy())2475return 0;24762477// We need to follow common pointer manipulation uses to the accesses they2478// feed into. We can try to be smart to avoid looking through things we do not2479// like for now, e.g., non-inbounds GEPs.2480if (isa<CastInst>(I)) {2481TrackUse = true;2482return 0;2483}24842485if (isa<GetElementPtrInst>(I)) {2486TrackUse = true;2487return 0;2488}24892490Type *PtrTy = UseV->getType();2491const Function *F = I->getFunction();2492bool NullPointerIsDefined =2493F ? llvm::NullPointerIsDefined(F, PtrTy->getPointerAddressSpace()) : true;2494const DataLayout &DL = A.getInfoCache().getDL();2495if (const auto *CB = dyn_cast<CallBase>(I)) {2496if (CB->isBundleOperand(U)) {2497if (RetainedKnowledge RK = getKnowledgeFromUse(2498U, {Attribute::NonNull, Attribute::Dereferenceable})) {2499IsNonNull |=2500(RK.AttrKind == Attribute::NonNull || !NullPointerIsDefined);2501return RK.ArgValue;2502}2503return 0;2504}25052506if (CB->isCallee(U)) {2507IsNonNull |= !NullPointerIsDefined;2508return 0;2509}25102511unsigned ArgNo = CB->getArgOperandNo(U);2512IRPosition IRP = IRPosition::callsite_argument(*CB, ArgNo);2513// As long as we only use known information there is no need to track2514// dependences here.2515bool IsKnownNonNull;2516AA::hasAssumedIRAttr<Attribute::NonNull>(A, &QueryingAA, IRP,2517DepClassTy::NONE, IsKnownNonNull);2518IsNonNull |= IsKnownNonNull;2519auto *DerefAA =2520A.getAAFor<AADereferenceable>(QueryingAA, IRP, DepClassTy::NONE);2521return DerefAA ? DerefAA->getKnownDereferenceableBytes() : 0;2522}25232524std::optional<MemoryLocation> Loc = MemoryLocation::getOrNone(I);2525if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() ||2526Loc->Size.isScalable() || I->isVolatile())2527return 0;25282529int64_t Offset;2530const Value *Base =2531getMinimalBaseOfPointer(A, QueryingAA, Loc->Ptr, Offset, DL);2532if (Base && Base == &AssociatedValue) {2533int64_t DerefBytes = Loc->Size.getValue() + Offset;2534IsNonNull |= !NullPointerIsDefined;2535return std::max(int64_t(0), DerefBytes);2536}25372538/// Corner case when an offset is 0.2539Base = GetPointerBaseWithConstantOffset(Loc->Ptr, Offset, DL,2540/*AllowNonInbounds*/ true);2541if (Base && Base == &AssociatedValue && Offset == 0) {2542int64_t DerefBytes = Loc->Size.getValue();2543IsNonNull |= !NullPointerIsDefined;2544return std::max(int64_t(0), DerefBytes);2545}25462547return 0;2548}25492550struct AANonNullImpl : AANonNull {2551AANonNullImpl(const IRPosition &IRP, Attributor &A) : AANonNull(IRP, A) {}25522553/// See AbstractAttribute::initialize(...).2554void initialize(Attributor &A) override {2555Value &V = *getAssociatedValue().stripPointerCasts();2556if (isa<ConstantPointerNull>(V)) {2557indicatePessimisticFixpoint();2558return;2559}25602561if (Instruction *CtxI = getCtxI())2562followUsesInMBEC(*this, A, getState(), *CtxI);2563}25642565/// See followUsesInMBEC2566bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I,2567AANonNull::StateType &State) {2568bool IsNonNull = false;2569bool TrackUse = false;2570getKnownNonNullAndDerefBytesForUse(A, *this, getAssociatedValue(), U, I,2571IsNonNull, TrackUse);2572State.setKnown(IsNonNull);2573return TrackUse;2574}25752576/// See AbstractAttribute::getAsStr().2577const std::string getAsStr(Attributor *A) const override {2578return getAssumed() ? "nonnull" : "may-null";2579}2580};25812582/// NonNull attribute for a floating value.2583struct AANonNullFloating : public AANonNullImpl {2584AANonNullFloating(const IRPosition &IRP, Attributor &A)2585: AANonNullImpl(IRP, A) {}25862587/// See AbstractAttribute::updateImpl(...).2588ChangeStatus updateImpl(Attributor &A) override {2589auto CheckIRP = [&](const IRPosition &IRP) {2590bool IsKnownNonNull;2591return AA::hasAssumedIRAttr<Attribute::NonNull>(2592A, *this, IRP, DepClassTy::OPTIONAL, IsKnownNonNull);2593};25942595bool Stripped;2596bool UsedAssumedInformation = false;2597Value *AssociatedValue = &getAssociatedValue();2598SmallVector<AA::ValueAndContext> Values;2599if (!A.getAssumedSimplifiedValues(getIRPosition(), *this, Values,2600AA::AnyScope, UsedAssumedInformation))2601Stripped = false;2602else2603Stripped =2604Values.size() != 1 || Values.front().getValue() != AssociatedValue;26052606if (!Stripped) {2607bool IsKnown;2608if (auto *PHI = dyn_cast<PHINode>(AssociatedValue))2609if (llvm::all_of(PHI->incoming_values(), [&](Value *Op) {2610return AA::hasAssumedIRAttr<Attribute::NonNull>(2611A, this, IRPosition::value(*Op), DepClassTy::OPTIONAL,2612IsKnown);2613}))2614return ChangeStatus::UNCHANGED;2615if (auto *Select = dyn_cast<SelectInst>(AssociatedValue))2616if (AA::hasAssumedIRAttr<Attribute::NonNull>(2617A, this, IRPosition::value(*Select->getFalseValue()),2618DepClassTy::OPTIONAL, IsKnown) &&2619AA::hasAssumedIRAttr<Attribute::NonNull>(2620A, this, IRPosition::value(*Select->getTrueValue()),2621DepClassTy::OPTIONAL, IsKnown))2622return ChangeStatus::UNCHANGED;26232624// If we haven't stripped anything we might still be able to use a2625// different AA, but only if the IRP changes. Effectively when we2626// interpret this not as a call site value but as a floating/argument2627// value.2628const IRPosition AVIRP = IRPosition::value(*AssociatedValue);2629if (AVIRP == getIRPosition() || !CheckIRP(AVIRP))2630return indicatePessimisticFixpoint();2631return ChangeStatus::UNCHANGED;2632}26332634for (const auto &VAC : Values)2635if (!CheckIRP(IRPosition::value(*VAC.getValue())))2636return indicatePessimisticFixpoint();26372638return ChangeStatus::UNCHANGED;2639}26402641/// See AbstractAttribute::trackStatistics()2642void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) }2643};26442645/// NonNull attribute for function return value.2646struct AANonNullReturned final2647: AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,2648false, AANonNull::IRAttributeKind, false> {2649AANonNullReturned(const IRPosition &IRP, Attributor &A)2650: AAReturnedFromReturnedValues<AANonNull, AANonNull, AANonNull::StateType,2651false, Attribute::NonNull, false>(IRP, A) {2652}26532654/// See AbstractAttribute::getAsStr().2655const std::string getAsStr(Attributor *A) const override {2656return getAssumed() ? "nonnull" : "may-null";2657}26582659/// See AbstractAttribute::trackStatistics()2660void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(nonnull) }2661};26622663/// NonNull attribute for function argument.2664struct AANonNullArgument final2665: AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl> {2666AANonNullArgument(const IRPosition &IRP, Attributor &A)2667: AAArgumentFromCallSiteArguments<AANonNull, AANonNullImpl>(IRP, A) {}26682669/// See AbstractAttribute::trackStatistics()2670void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nonnull) }2671};26722673struct AANonNullCallSiteArgument final : AANonNullFloating {2674AANonNullCallSiteArgument(const IRPosition &IRP, Attributor &A)2675: AANonNullFloating(IRP, A) {}26762677/// See AbstractAttribute::trackStatistics()2678void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(nonnull) }2679};26802681/// NonNull attribute for a call site return position.2682struct AANonNullCallSiteReturned final2683: AACalleeToCallSite<AANonNull, AANonNullImpl> {2684AANonNullCallSiteReturned(const IRPosition &IRP, Attributor &A)2685: AACalleeToCallSite<AANonNull, AANonNullImpl>(IRP, A) {}26862687/// See AbstractAttribute::trackStatistics()2688void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(nonnull) }2689};2690} // namespace26912692/// ------------------------ Must-Progress Attributes --------------------------2693namespace {2694struct AAMustProgressImpl : public AAMustProgress {2695AAMustProgressImpl(const IRPosition &IRP, Attributor &A)2696: AAMustProgress(IRP, A) {}26972698/// See AbstractAttribute::initialize(...).2699void initialize(Attributor &A) override {2700bool IsKnown;2701assert(!AA::hasAssumedIRAttr<Attribute::MustProgress>(2702A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));2703(void)IsKnown;2704}27052706/// See AbstractAttribute::getAsStr()2707const std::string getAsStr(Attributor *A) const override {2708return getAssumed() ? "mustprogress" : "may-not-progress";2709}2710};27112712struct AAMustProgressFunction final : AAMustProgressImpl {2713AAMustProgressFunction(const IRPosition &IRP, Attributor &A)2714: AAMustProgressImpl(IRP, A) {}27152716/// See AbstractAttribute::updateImpl(...).2717ChangeStatus updateImpl(Attributor &A) override {2718bool IsKnown;2719if (AA::hasAssumedIRAttr<Attribute::WillReturn>(2720A, this, getIRPosition(), DepClassTy::OPTIONAL, IsKnown)) {2721if (IsKnown)2722return indicateOptimisticFixpoint();2723return ChangeStatus::UNCHANGED;2724}27252726auto CheckForMustProgress = [&](AbstractCallSite ACS) {2727IRPosition IPos = IRPosition::callsite_function(*ACS.getInstruction());2728bool IsKnownMustProgress;2729return AA::hasAssumedIRAttr<Attribute::MustProgress>(2730A, this, IPos, DepClassTy::REQUIRED, IsKnownMustProgress,2731/* IgnoreSubsumingPositions */ true);2732};27332734bool AllCallSitesKnown = true;2735if (!A.checkForAllCallSites(CheckForMustProgress, *this,2736/* RequireAllCallSites */ true,2737AllCallSitesKnown))2738return indicatePessimisticFixpoint();27392740return ChangeStatus::UNCHANGED;2741}27422743/// See AbstractAttribute::trackStatistics()2744void trackStatistics() const override {2745STATS_DECLTRACK_FN_ATTR(mustprogress)2746}2747};27482749/// MustProgress attribute deduction for a call sites.2750struct AAMustProgressCallSite final : AAMustProgressImpl {2751AAMustProgressCallSite(const IRPosition &IRP, Attributor &A)2752: AAMustProgressImpl(IRP, A) {}27532754/// See AbstractAttribute::updateImpl(...).2755ChangeStatus updateImpl(Attributor &A) override {2756// TODO: Once we have call site specific value information we can provide2757// call site specific liveness information and then it makes2758// sense to specialize attributes for call sites arguments instead of2759// redirecting requests to the callee argument.2760const IRPosition &FnPos = IRPosition::function(*getAnchorScope());2761bool IsKnownMustProgress;2762if (!AA::hasAssumedIRAttr<Attribute::MustProgress>(2763A, this, FnPos, DepClassTy::REQUIRED, IsKnownMustProgress))2764return indicatePessimisticFixpoint();2765return ChangeStatus::UNCHANGED;2766}27672768/// See AbstractAttribute::trackStatistics()2769void trackStatistics() const override {2770STATS_DECLTRACK_CS_ATTR(mustprogress);2771}2772};2773} // namespace27742775/// ------------------------ No-Recurse Attributes ----------------------------27762777namespace {2778struct AANoRecurseImpl : public AANoRecurse {2779AANoRecurseImpl(const IRPosition &IRP, Attributor &A) : AANoRecurse(IRP, A) {}27802781/// See AbstractAttribute::initialize(...).2782void initialize(Attributor &A) override {2783bool IsKnown;2784assert(!AA::hasAssumedIRAttr<Attribute::NoRecurse>(2785A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));2786(void)IsKnown;2787}27882789/// See AbstractAttribute::getAsStr()2790const std::string getAsStr(Attributor *A) const override {2791return getAssumed() ? "norecurse" : "may-recurse";2792}2793};27942795struct AANoRecurseFunction final : AANoRecurseImpl {2796AANoRecurseFunction(const IRPosition &IRP, Attributor &A)2797: AANoRecurseImpl(IRP, A) {}27982799/// See AbstractAttribute::updateImpl(...).2800ChangeStatus updateImpl(Attributor &A) override {28012802// If all live call sites are known to be no-recurse, we are as well.2803auto CallSitePred = [&](AbstractCallSite ACS) {2804bool IsKnownNoRecurse;2805if (!AA::hasAssumedIRAttr<Attribute::NoRecurse>(2806A, this,2807IRPosition::function(*ACS.getInstruction()->getFunction()),2808DepClassTy::NONE, IsKnownNoRecurse))2809return false;2810return IsKnownNoRecurse;2811};2812bool UsedAssumedInformation = false;2813if (A.checkForAllCallSites(CallSitePred, *this, true,2814UsedAssumedInformation)) {2815// If we know all call sites and all are known no-recurse, we are done.2816// If all known call sites, which might not be all that exist, are known2817// to be no-recurse, we are not done but we can continue to assume2818// no-recurse. If one of the call sites we have not visited will become2819// live, another update is triggered.2820if (!UsedAssumedInformation)2821indicateOptimisticFixpoint();2822return ChangeStatus::UNCHANGED;2823}28242825const AAInterFnReachability *EdgeReachability =2826A.getAAFor<AAInterFnReachability>(*this, getIRPosition(),2827DepClassTy::REQUIRED);2828if (EdgeReachability && EdgeReachability->canReach(A, *getAnchorScope()))2829return indicatePessimisticFixpoint();2830return ChangeStatus::UNCHANGED;2831}28322833void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(norecurse) }2834};28352836/// NoRecurse attribute deduction for a call sites.2837struct AANoRecurseCallSite final2838: AACalleeToCallSite<AANoRecurse, AANoRecurseImpl> {2839AANoRecurseCallSite(const IRPosition &IRP, Attributor &A)2840: AACalleeToCallSite<AANoRecurse, AANoRecurseImpl>(IRP, A) {}28412842/// See AbstractAttribute::trackStatistics()2843void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(norecurse); }2844};2845} // namespace28462847/// ------------------------ No-Convergent Attribute --------------------------28482849namespace {2850struct AANonConvergentImpl : public AANonConvergent {2851AANonConvergentImpl(const IRPosition &IRP, Attributor &A)2852: AANonConvergent(IRP, A) {}28532854/// See AbstractAttribute::getAsStr()2855const std::string getAsStr(Attributor *A) const override {2856return getAssumed() ? "non-convergent" : "may-be-convergent";2857}2858};28592860struct AANonConvergentFunction final : AANonConvergentImpl {2861AANonConvergentFunction(const IRPosition &IRP, Attributor &A)2862: AANonConvergentImpl(IRP, A) {}28632864/// See AbstractAttribute::updateImpl(...).2865ChangeStatus updateImpl(Attributor &A) override {2866// If all function calls are known to not be convergent, we are not2867// convergent.2868auto CalleeIsNotConvergent = [&](Instruction &Inst) {2869CallBase &CB = cast<CallBase>(Inst);2870auto *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand());2871if (!Callee || Callee->isIntrinsic()) {2872return false;2873}2874if (Callee->isDeclaration()) {2875return !Callee->hasFnAttribute(Attribute::Convergent);2876}2877const auto *ConvergentAA = A.getAAFor<AANonConvergent>(2878*this, IRPosition::function(*Callee), DepClassTy::REQUIRED);2879return ConvergentAA && ConvergentAA->isAssumedNotConvergent();2880};28812882bool UsedAssumedInformation = false;2883if (!A.checkForAllCallLikeInstructions(CalleeIsNotConvergent, *this,2884UsedAssumedInformation)) {2885return indicatePessimisticFixpoint();2886}2887return ChangeStatus::UNCHANGED;2888}28892890ChangeStatus manifest(Attributor &A) override {2891if (isKnownNotConvergent() &&2892A.hasAttr(getIRPosition(), Attribute::Convergent)) {2893A.removeAttrs(getIRPosition(), {Attribute::Convergent});2894return ChangeStatus::CHANGED;2895}2896return ChangeStatus::UNCHANGED;2897}28982899void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(convergent) }2900};2901} // namespace29022903/// -------------------- Undefined-Behavior Attributes ------------------------29042905namespace {2906struct AAUndefinedBehaviorImpl : public AAUndefinedBehavior {2907AAUndefinedBehaviorImpl(const IRPosition &IRP, Attributor &A)2908: AAUndefinedBehavior(IRP, A) {}29092910/// See AbstractAttribute::updateImpl(...).2911// through a pointer (i.e. also branches etc.)2912ChangeStatus updateImpl(Attributor &A) override {2913const size_t UBPrevSize = KnownUBInsts.size();2914const size_t NoUBPrevSize = AssumedNoUBInsts.size();29152916auto InspectMemAccessInstForUB = [&](Instruction &I) {2917// Lang ref now states volatile store is not UB, let's skip them.2918if (I.isVolatile() && I.mayWriteToMemory())2919return true;29202921// Skip instructions that are already saved.2922if (AssumedNoUBInsts.count(&I) || KnownUBInsts.count(&I))2923return true;29242925// If we reach here, we know we have an instruction2926// that accesses memory through a pointer operand,2927// for which getPointerOperand() should give it to us.2928Value *PtrOp =2929const_cast<Value *>(getPointerOperand(&I, /* AllowVolatile */ true));2930assert(PtrOp &&2931"Expected pointer operand of memory accessing instruction");29322933// Either we stopped and the appropriate action was taken,2934// or we got back a simplified value to continue.2935std::optional<Value *> SimplifiedPtrOp =2936stopOnUndefOrAssumed(A, PtrOp, &I);2937if (!SimplifiedPtrOp || !*SimplifiedPtrOp)2938return true;2939const Value *PtrOpVal = *SimplifiedPtrOp;29402941// A memory access through a pointer is considered UB2942// only if the pointer has constant null value.2943// TODO: Expand it to not only check constant values.2944if (!isa<ConstantPointerNull>(PtrOpVal)) {2945AssumedNoUBInsts.insert(&I);2946return true;2947}2948const Type *PtrTy = PtrOpVal->getType();29492950// Because we only consider instructions inside functions,2951// assume that a parent function exists.2952const Function *F = I.getFunction();29532954// A memory access using constant null pointer is only considered UB2955// if null pointer is _not_ defined for the target platform.2956if (llvm::NullPointerIsDefined(F, PtrTy->getPointerAddressSpace()))2957AssumedNoUBInsts.insert(&I);2958else2959KnownUBInsts.insert(&I);2960return true;2961};29622963auto InspectBrInstForUB = [&](Instruction &I) {2964// A conditional branch instruction is considered UB if it has `undef`2965// condition.29662967// Skip instructions that are already saved.2968if (AssumedNoUBInsts.count(&I) || KnownUBInsts.count(&I))2969return true;29702971// We know we have a branch instruction.2972auto *BrInst = cast<BranchInst>(&I);29732974// Unconditional branches are never considered UB.2975if (BrInst->isUnconditional())2976return true;29772978// Either we stopped and the appropriate action was taken,2979// or we got back a simplified value to continue.2980std::optional<Value *> SimplifiedCond =2981stopOnUndefOrAssumed(A, BrInst->getCondition(), BrInst);2982if (!SimplifiedCond || !*SimplifiedCond)2983return true;2984AssumedNoUBInsts.insert(&I);2985return true;2986};29872988auto InspectCallSiteForUB = [&](Instruction &I) {2989// Check whether a callsite always cause UB or not29902991// Skip instructions that are already saved.2992if (AssumedNoUBInsts.count(&I) || KnownUBInsts.count(&I))2993return true;29942995// Check nonnull and noundef argument attribute violation for each2996// callsite.2997CallBase &CB = cast<CallBase>(I);2998auto *Callee = dyn_cast_if_present<Function>(CB.getCalledOperand());2999if (!Callee)3000return true;3001for (unsigned idx = 0; idx < CB.arg_size(); idx++) {3002// If current argument is known to be simplified to null pointer and the3003// corresponding argument position is known to have nonnull attribute,3004// the argument is poison. Furthermore, if the argument is poison and3005// the position is known to have noundef attriubte, this callsite is3006// considered UB.3007if (idx >= Callee->arg_size())3008break;3009Value *ArgVal = CB.getArgOperand(idx);3010if (!ArgVal)3011continue;3012// Here, we handle three cases.3013// (1) Not having a value means it is dead. (we can replace the value3014// with undef)3015// (2) Simplified to undef. The argument violate noundef attriubte.3016// (3) Simplified to null pointer where known to be nonnull.3017// The argument is a poison value and violate noundef attribute.3018IRPosition CalleeArgumentIRP = IRPosition::callsite_argument(CB, idx);3019bool IsKnownNoUndef;3020AA::hasAssumedIRAttr<Attribute::NoUndef>(3021A, this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNoUndef);3022if (!IsKnownNoUndef)3023continue;3024bool UsedAssumedInformation = false;3025std::optional<Value *> SimplifiedVal =3026A.getAssumedSimplified(IRPosition::value(*ArgVal), *this,3027UsedAssumedInformation, AA::Interprocedural);3028if (UsedAssumedInformation)3029continue;3030if (SimplifiedVal && !*SimplifiedVal)3031return true;3032if (!SimplifiedVal || isa<UndefValue>(**SimplifiedVal)) {3033KnownUBInsts.insert(&I);3034continue;3035}3036if (!ArgVal->getType()->isPointerTy() ||3037!isa<ConstantPointerNull>(**SimplifiedVal))3038continue;3039bool IsKnownNonNull;3040AA::hasAssumedIRAttr<Attribute::NonNull>(3041A, this, CalleeArgumentIRP, DepClassTy::NONE, IsKnownNonNull);3042if (IsKnownNonNull)3043KnownUBInsts.insert(&I);3044}3045return true;3046};30473048auto InspectReturnInstForUB = [&](Instruction &I) {3049auto &RI = cast<ReturnInst>(I);3050// Either we stopped and the appropriate action was taken,3051// or we got back a simplified return value to continue.3052std::optional<Value *> SimplifiedRetValue =3053stopOnUndefOrAssumed(A, RI.getReturnValue(), &I);3054if (!SimplifiedRetValue || !*SimplifiedRetValue)3055return true;30563057// Check if a return instruction always cause UB or not3058// Note: It is guaranteed that the returned position of the anchor3059// scope has noundef attribute when this is called.3060// We also ensure the return position is not "assumed dead"3061// because the returned value was then potentially simplified to3062// `undef` in AAReturnedValues without removing the `noundef`3063// attribute yet.30643065// When the returned position has noundef attriubte, UB occurs in the3066// following cases.3067// (1) Returned value is known to be undef.3068// (2) The value is known to be a null pointer and the returned3069// position has nonnull attribute (because the returned value is3070// poison).3071if (isa<ConstantPointerNull>(*SimplifiedRetValue)) {3072bool IsKnownNonNull;3073AA::hasAssumedIRAttr<Attribute::NonNull>(3074A, this, IRPosition::returned(*getAnchorScope()), DepClassTy::NONE,3075IsKnownNonNull);3076if (IsKnownNonNull)3077KnownUBInsts.insert(&I);3078}30793080return true;3081};30823083bool UsedAssumedInformation = false;3084A.checkForAllInstructions(InspectMemAccessInstForUB, *this,3085{Instruction::Load, Instruction::Store,3086Instruction::AtomicCmpXchg,3087Instruction::AtomicRMW},3088UsedAssumedInformation,3089/* CheckBBLivenessOnly */ true);3090A.checkForAllInstructions(InspectBrInstForUB, *this, {Instruction::Br},3091UsedAssumedInformation,3092/* CheckBBLivenessOnly */ true);3093A.checkForAllCallLikeInstructions(InspectCallSiteForUB, *this,3094UsedAssumedInformation);30953096// If the returned position of the anchor scope has noundef attriubte, check3097// all returned instructions.3098if (!getAnchorScope()->getReturnType()->isVoidTy()) {3099const IRPosition &ReturnIRP = IRPosition::returned(*getAnchorScope());3100if (!A.isAssumedDead(ReturnIRP, this, nullptr, UsedAssumedInformation)) {3101bool IsKnownNoUndef;3102AA::hasAssumedIRAttr<Attribute::NoUndef>(3103A, this, ReturnIRP, DepClassTy::NONE, IsKnownNoUndef);3104if (IsKnownNoUndef)3105A.checkForAllInstructions(InspectReturnInstForUB, *this,3106{Instruction::Ret}, UsedAssumedInformation,3107/* CheckBBLivenessOnly */ true);3108}3109}31103111if (NoUBPrevSize != AssumedNoUBInsts.size() ||3112UBPrevSize != KnownUBInsts.size())3113return ChangeStatus::CHANGED;3114return ChangeStatus::UNCHANGED;3115}31163117bool isKnownToCauseUB(Instruction *I) const override {3118return KnownUBInsts.count(I);3119}31203121bool isAssumedToCauseUB(Instruction *I) const override {3122// In simple words, if an instruction is not in the assumed to _not_3123// cause UB, then it is assumed UB (that includes those3124// in the KnownUBInsts set). The rest is boilerplate3125// is to ensure that it is one of the instructions we test3126// for UB.31273128switch (I->getOpcode()) {3129case Instruction::Load:3130case Instruction::Store:3131case Instruction::AtomicCmpXchg:3132case Instruction::AtomicRMW:3133return !AssumedNoUBInsts.count(I);3134case Instruction::Br: {3135auto *BrInst = cast<BranchInst>(I);3136if (BrInst->isUnconditional())3137return false;3138return !AssumedNoUBInsts.count(I);3139} break;3140default:3141return false;3142}3143return false;3144}31453146ChangeStatus manifest(Attributor &A) override {3147if (KnownUBInsts.empty())3148return ChangeStatus::UNCHANGED;3149for (Instruction *I : KnownUBInsts)3150A.changeToUnreachableAfterManifest(I);3151return ChangeStatus::CHANGED;3152}31533154/// See AbstractAttribute::getAsStr()3155const std::string getAsStr(Attributor *A) const override {3156return getAssumed() ? "undefined-behavior" : "no-ub";3157}31583159/// Note: The correctness of this analysis depends on the fact that the3160/// following 2 sets will stop changing after some point.3161/// "Change" here means that their size changes.3162/// The size of each set is monotonically increasing3163/// (we only add items to them) and it is upper bounded by the number of3164/// instructions in the processed function (we can never save more3165/// elements in either set than this number). Hence, at some point,3166/// they will stop increasing.3167/// Consequently, at some point, both sets will have stopped3168/// changing, effectively making the analysis reach a fixpoint.31693170/// Note: These 2 sets are disjoint and an instruction can be considered3171/// one of 3 things:3172/// 1) Known to cause UB (AAUndefinedBehavior could prove it) and put it in3173/// the KnownUBInsts set.3174/// 2) Assumed to cause UB (in every updateImpl, AAUndefinedBehavior3175/// has a reason to assume it).3176/// 3) Assumed to not cause UB. very other instruction - AAUndefinedBehavior3177/// could not find a reason to assume or prove that it can cause UB,3178/// hence it assumes it doesn't. We have a set for these instructions3179/// so that we don't reprocess them in every update.3180/// Note however that instructions in this set may cause UB.31813182protected:3183/// A set of all live instructions _known_ to cause UB.3184SmallPtrSet<Instruction *, 8> KnownUBInsts;31853186private:3187/// A set of all the (live) instructions that are assumed to _not_ cause UB.3188SmallPtrSet<Instruction *, 8> AssumedNoUBInsts;31893190// Should be called on updates in which if we're processing an instruction3191// \p I that depends on a value \p V, one of the following has to happen:3192// - If the value is assumed, then stop.3193// - If the value is known but undef, then consider it UB.3194// - Otherwise, do specific processing with the simplified value.3195// We return std::nullopt in the first 2 cases to signify that an appropriate3196// action was taken and the caller should stop.3197// Otherwise, we return the simplified value that the caller should3198// use for specific processing.3199std::optional<Value *> stopOnUndefOrAssumed(Attributor &A, Value *V,3200Instruction *I) {3201bool UsedAssumedInformation = false;3202std::optional<Value *> SimplifiedV =3203A.getAssumedSimplified(IRPosition::value(*V), *this,3204UsedAssumedInformation, AA::Interprocedural);3205if (!UsedAssumedInformation) {3206// Don't depend on assumed values.3207if (!SimplifiedV) {3208// If it is known (which we tested above) but it doesn't have a value,3209// then we can assume `undef` and hence the instruction is UB.3210KnownUBInsts.insert(I);3211return std::nullopt;3212}3213if (!*SimplifiedV)3214return nullptr;3215V = *SimplifiedV;3216}3217if (isa<UndefValue>(V)) {3218KnownUBInsts.insert(I);3219return std::nullopt;3220}3221return V;3222}3223};32243225struct AAUndefinedBehaviorFunction final : AAUndefinedBehaviorImpl {3226AAUndefinedBehaviorFunction(const IRPosition &IRP, Attributor &A)3227: AAUndefinedBehaviorImpl(IRP, A) {}32283229/// See AbstractAttribute::trackStatistics()3230void trackStatistics() const override {3231STATS_DECL(UndefinedBehaviorInstruction, Instruction,3232"Number of instructions known to have UB");3233BUILD_STAT_NAME(UndefinedBehaviorInstruction, Instruction) +=3234KnownUBInsts.size();3235}3236};3237} // namespace32383239/// ------------------------ Will-Return Attributes ----------------------------32403241namespace {3242// Helper function that checks whether a function has any cycle which we don't3243// know if it is bounded or not.3244// Loops with maximum trip count are considered bounded, any other cycle not.3245static bool mayContainUnboundedCycle(Function &F, Attributor &A) {3246ScalarEvolution *SE =3247A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(F);3248LoopInfo *LI = A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(F);3249// If either SCEV or LoopInfo is not available for the function then we assume3250// any cycle to be unbounded cycle.3251// We use scc_iterator which uses Tarjan algorithm to find all the maximal3252// SCCs.To detect if there's a cycle, we only need to find the maximal ones.3253if (!SE || !LI) {3254for (scc_iterator<Function *> SCCI = scc_begin(&F); !SCCI.isAtEnd(); ++SCCI)3255if (SCCI.hasCycle())3256return true;3257return false;3258}32593260// If there's irreducible control, the function may contain non-loop cycles.3261if (mayContainIrreducibleControl(F, LI))3262return true;32633264// Any loop that does not have a max trip count is considered unbounded cycle.3265for (auto *L : LI->getLoopsInPreorder()) {3266if (!SE->getSmallConstantMaxTripCount(L))3267return true;3268}3269return false;3270}32713272struct AAWillReturnImpl : public AAWillReturn {3273AAWillReturnImpl(const IRPosition &IRP, Attributor &A)3274: AAWillReturn(IRP, A) {}32753276/// See AbstractAttribute::initialize(...).3277void initialize(Attributor &A) override {3278bool IsKnown;3279assert(!AA::hasAssumedIRAttr<Attribute::WillReturn>(3280A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));3281(void)IsKnown;3282}32833284/// Check for `mustprogress` and `readonly` as they imply `willreturn`.3285bool isImpliedByMustprogressAndReadonly(Attributor &A, bool KnownOnly) {3286if (!A.hasAttr(getIRPosition(), {Attribute::MustProgress}))3287return false;32883289bool IsKnown;3290if (AA::isAssumedReadOnly(A, getIRPosition(), *this, IsKnown))3291return IsKnown || !KnownOnly;3292return false;3293}32943295/// See AbstractAttribute::updateImpl(...).3296ChangeStatus updateImpl(Attributor &A) override {3297if (isImpliedByMustprogressAndReadonly(A, /* KnownOnly */ false))3298return ChangeStatus::UNCHANGED;32993300auto CheckForWillReturn = [&](Instruction &I) {3301IRPosition IPos = IRPosition::callsite_function(cast<CallBase>(I));3302bool IsKnown;3303if (AA::hasAssumedIRAttr<Attribute::WillReturn>(3304A, this, IPos, DepClassTy::REQUIRED, IsKnown)) {3305if (IsKnown)3306return true;3307} else {3308return false;3309}3310bool IsKnownNoRecurse;3311return AA::hasAssumedIRAttr<Attribute::NoRecurse>(3312A, this, IPos, DepClassTy::REQUIRED, IsKnownNoRecurse);3313};33143315bool UsedAssumedInformation = false;3316if (!A.checkForAllCallLikeInstructions(CheckForWillReturn, *this,3317UsedAssumedInformation))3318return indicatePessimisticFixpoint();33193320return ChangeStatus::UNCHANGED;3321}33223323/// See AbstractAttribute::getAsStr()3324const std::string getAsStr(Attributor *A) const override {3325return getAssumed() ? "willreturn" : "may-noreturn";3326}3327};33283329struct AAWillReturnFunction final : AAWillReturnImpl {3330AAWillReturnFunction(const IRPosition &IRP, Attributor &A)3331: AAWillReturnImpl(IRP, A) {}33323333/// See AbstractAttribute::initialize(...).3334void initialize(Attributor &A) override {3335AAWillReturnImpl::initialize(A);33363337Function *F = getAnchorScope();3338assert(F && "Did expect an anchor function");3339if (F->isDeclaration() || mayContainUnboundedCycle(*F, A))3340indicatePessimisticFixpoint();3341}33423343/// See AbstractAttribute::trackStatistics()3344void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(willreturn) }3345};33463347/// WillReturn attribute deduction for a call sites.3348struct AAWillReturnCallSite final3349: AACalleeToCallSite<AAWillReturn, AAWillReturnImpl> {3350AAWillReturnCallSite(const IRPosition &IRP, Attributor &A)3351: AACalleeToCallSite<AAWillReturn, AAWillReturnImpl>(IRP, A) {}33523353/// See AbstractAttribute::updateImpl(...).3354ChangeStatus updateImpl(Attributor &A) override {3355if (isImpliedByMustprogressAndReadonly(A, /* KnownOnly */ false))3356return ChangeStatus::UNCHANGED;33573358return AACalleeToCallSite::updateImpl(A);3359}33603361/// See AbstractAttribute::trackStatistics()3362void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(willreturn); }3363};3364} // namespace33653366/// -------------------AAIntraFnReachability Attribute--------------------------33673368/// All information associated with a reachability query. This boilerplate code3369/// is used by both AAIntraFnReachability and AAInterFnReachability, with3370/// different \p ToTy values.3371template <typename ToTy> struct ReachabilityQueryInfo {3372enum class Reachable {3373No,3374Yes,3375};33763377/// Start here,3378const Instruction *From = nullptr;3379/// reach this place,3380const ToTy *To = nullptr;3381/// without going through any of these instructions,3382const AA::InstExclusionSetTy *ExclusionSet = nullptr;3383/// and remember if it worked:3384Reachable Result = Reachable::No;33853386/// Precomputed hash for this RQI.3387unsigned Hash = 0;33883389unsigned computeHashValue() const {3390assert(Hash == 0 && "Computed hash twice!");3391using InstSetDMI = DenseMapInfo<const AA::InstExclusionSetTy *>;3392using PairDMI = DenseMapInfo<std::pair<const Instruction *, const ToTy *>>;3393return const_cast<ReachabilityQueryInfo<ToTy> *>(this)->Hash =3394detail::combineHashValue(PairDMI ::getHashValue({From, To}),3395InstSetDMI::getHashValue(ExclusionSet));3396}33973398ReachabilityQueryInfo(const Instruction *From, const ToTy *To)3399: From(From), To(To) {}34003401/// Constructor replacement to ensure unique and stable sets are used for the3402/// cache.3403ReachabilityQueryInfo(Attributor &A, const Instruction &From, const ToTy &To,3404const AA::InstExclusionSetTy *ES, bool MakeUnique)3405: From(&From), To(&To), ExclusionSet(ES) {34063407if (!ES || ES->empty()) {3408ExclusionSet = nullptr;3409} else if (MakeUnique) {3410ExclusionSet = A.getInfoCache().getOrCreateUniqueBlockExecutionSet(ES);3411}3412}34133414ReachabilityQueryInfo(const ReachabilityQueryInfo &RQI)3415: From(RQI.From), To(RQI.To), ExclusionSet(RQI.ExclusionSet) {}3416};34173418namespace llvm {3419template <typename ToTy> struct DenseMapInfo<ReachabilityQueryInfo<ToTy> *> {3420using InstSetDMI = DenseMapInfo<const AA::InstExclusionSetTy *>;3421using PairDMI = DenseMapInfo<std::pair<const Instruction *, const ToTy *>>;34223423static ReachabilityQueryInfo<ToTy> EmptyKey;3424static ReachabilityQueryInfo<ToTy> TombstoneKey;34253426static inline ReachabilityQueryInfo<ToTy> *getEmptyKey() { return &EmptyKey; }3427static inline ReachabilityQueryInfo<ToTy> *getTombstoneKey() {3428return &TombstoneKey;3429}3430static unsigned getHashValue(const ReachabilityQueryInfo<ToTy> *RQI) {3431return RQI->Hash ? RQI->Hash : RQI->computeHashValue();3432}3433static bool isEqual(const ReachabilityQueryInfo<ToTy> *LHS,3434const ReachabilityQueryInfo<ToTy> *RHS) {3435if (!PairDMI::isEqual({LHS->From, LHS->To}, {RHS->From, RHS->To}))3436return false;3437return InstSetDMI::isEqual(LHS->ExclusionSet, RHS->ExclusionSet);3438}3439};34403441#define DefineKeys(ToTy) \3442template <> \3443ReachabilityQueryInfo<ToTy> \3444DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::EmptyKey = \3445ReachabilityQueryInfo<ToTy>( \3446DenseMapInfo<const Instruction *>::getEmptyKey(), \3447DenseMapInfo<const ToTy *>::getEmptyKey()); \3448template <> \3449ReachabilityQueryInfo<ToTy> \3450DenseMapInfo<ReachabilityQueryInfo<ToTy> *>::TombstoneKey = \3451ReachabilityQueryInfo<ToTy>( \3452DenseMapInfo<const Instruction *>::getTombstoneKey(), \3453DenseMapInfo<const ToTy *>::getTombstoneKey());34543455DefineKeys(Instruction) DefineKeys(Function)3456#undef DefineKeys34573458} // namespace llvm34593460namespace {34613462template <typename BaseTy, typename ToTy>3463struct CachedReachabilityAA : public BaseTy {3464using RQITy = ReachabilityQueryInfo<ToTy>;34653466CachedReachabilityAA(const IRPosition &IRP, Attributor &A) : BaseTy(IRP, A) {}34673468/// See AbstractAttribute::isQueryAA.3469bool isQueryAA() const override { return true; }34703471/// See AbstractAttribute::updateImpl(...).3472ChangeStatus updateImpl(Attributor &A) override {3473ChangeStatus Changed = ChangeStatus::UNCHANGED;3474for (unsigned u = 0, e = QueryVector.size(); u < e; ++u) {3475RQITy *RQI = QueryVector[u];3476if (RQI->Result == RQITy::Reachable::No &&3477isReachableImpl(A, *RQI, /*IsTemporaryRQI=*/false))3478Changed = ChangeStatus::CHANGED;3479}3480return Changed;3481}34823483virtual bool isReachableImpl(Attributor &A, RQITy &RQI,3484bool IsTemporaryRQI) = 0;34853486bool rememberResult(Attributor &A, typename RQITy::Reachable Result,3487RQITy &RQI, bool UsedExclusionSet, bool IsTemporaryRQI) {3488RQI.Result = Result;34893490// Remove the temporary RQI from the cache.3491if (IsTemporaryRQI)3492QueryCache.erase(&RQI);34933494// Insert a plain RQI (w/o exclusion set) if that makes sense. Two options:3495// 1) If it is reachable, it doesn't matter if we have an exclusion set for3496// this query. 2) We did not use the exclusion set, potentially because3497// there is none.3498if (Result == RQITy::Reachable::Yes || !UsedExclusionSet) {3499RQITy PlainRQI(RQI.From, RQI.To);3500if (!QueryCache.count(&PlainRQI)) {3501RQITy *RQIPtr = new (A.Allocator) RQITy(RQI.From, RQI.To);3502RQIPtr->Result = Result;3503QueryVector.push_back(RQIPtr);3504QueryCache.insert(RQIPtr);3505}3506}35073508// Check if we need to insert a new permanent RQI with the exclusion set.3509if (IsTemporaryRQI && Result != RQITy::Reachable::Yes && UsedExclusionSet) {3510assert((!RQI.ExclusionSet || !RQI.ExclusionSet->empty()) &&3511"Did not expect empty set!");3512RQITy *RQIPtr = new (A.Allocator)3513RQITy(A, *RQI.From, *RQI.To, RQI.ExclusionSet, true);3514assert(RQIPtr->Result == RQITy::Reachable::No && "Already reachable?");3515RQIPtr->Result = Result;3516assert(!QueryCache.count(RQIPtr));3517QueryVector.push_back(RQIPtr);3518QueryCache.insert(RQIPtr);3519}35203521if (Result == RQITy::Reachable::No && IsTemporaryRQI)3522A.registerForUpdate(*this);3523return Result == RQITy::Reachable::Yes;3524}35253526const std::string getAsStr(Attributor *A) const override {3527// TODO: Return the number of reachable queries.3528return "#queries(" + std::to_string(QueryVector.size()) + ")";3529}35303531bool checkQueryCache(Attributor &A, RQITy &StackRQI,3532typename RQITy::Reachable &Result) {3533if (!this->getState().isValidState()) {3534Result = RQITy::Reachable::Yes;3535return true;3536}35373538// If we have an exclusion set we might be able to find our answer by3539// ignoring it first.3540if (StackRQI.ExclusionSet) {3541RQITy PlainRQI(StackRQI.From, StackRQI.To);3542auto It = QueryCache.find(&PlainRQI);3543if (It != QueryCache.end() && (*It)->Result == RQITy::Reachable::No) {3544Result = RQITy::Reachable::No;3545return true;3546}3547}35483549auto It = QueryCache.find(&StackRQI);3550if (It != QueryCache.end()) {3551Result = (*It)->Result;3552return true;3553}35543555// Insert a temporary for recursive queries. We will replace it with a3556// permanent entry later.3557QueryCache.insert(&StackRQI);3558return false;3559}35603561private:3562SmallVector<RQITy *> QueryVector;3563DenseSet<RQITy *> QueryCache;3564};35653566struct AAIntraFnReachabilityFunction final3567: public CachedReachabilityAA<AAIntraFnReachability, Instruction> {3568using Base = CachedReachabilityAA<AAIntraFnReachability, Instruction>;3569AAIntraFnReachabilityFunction(const IRPosition &IRP, Attributor &A)3570: Base(IRP, A) {3571DT = A.getInfoCache().getAnalysisResultForFunction<DominatorTreeAnalysis>(3572*IRP.getAssociatedFunction());3573}35743575bool isAssumedReachable(3576Attributor &A, const Instruction &From, const Instruction &To,3577const AA::InstExclusionSetTy *ExclusionSet) const override {3578auto *NonConstThis = const_cast<AAIntraFnReachabilityFunction *>(this);3579if (&From == &To)3580return true;35813582RQITy StackRQI(A, From, To, ExclusionSet, false);3583typename RQITy::Reachable Result;3584if (!NonConstThis->checkQueryCache(A, StackRQI, Result))3585return NonConstThis->isReachableImpl(A, StackRQI,3586/*IsTemporaryRQI=*/true);3587return Result == RQITy::Reachable::Yes;3588}35893590ChangeStatus updateImpl(Attributor &A) override {3591// We only depend on liveness. DeadEdges is all we care about, check if any3592// of them changed.3593auto *LivenessAA =3594A.getAAFor<AAIsDead>(*this, getIRPosition(), DepClassTy::OPTIONAL);3595if (LivenessAA &&3596llvm::all_of(DeadEdges,3597[&](const auto &DeadEdge) {3598return LivenessAA->isEdgeDead(DeadEdge.first,3599DeadEdge.second);3600}) &&3601llvm::all_of(DeadBlocks, [&](const BasicBlock *BB) {3602return LivenessAA->isAssumedDead(BB);3603})) {3604return ChangeStatus::UNCHANGED;3605}3606DeadEdges.clear();3607DeadBlocks.clear();3608return Base::updateImpl(A);3609}36103611bool isReachableImpl(Attributor &A, RQITy &RQI,3612bool IsTemporaryRQI) override {3613const Instruction *Origin = RQI.From;3614bool UsedExclusionSet = false;36153616auto WillReachInBlock = [&](const Instruction &From, const Instruction &To,3617const AA::InstExclusionSetTy *ExclusionSet) {3618const Instruction *IP = &From;3619while (IP && IP != &To) {3620if (ExclusionSet && IP != Origin && ExclusionSet->count(IP)) {3621UsedExclusionSet = true;3622break;3623}3624IP = IP->getNextNode();3625}3626return IP == &To;3627};36283629const BasicBlock *FromBB = RQI.From->getParent();3630const BasicBlock *ToBB = RQI.To->getParent();3631assert(FromBB->getParent() == ToBB->getParent() &&3632"Not an intra-procedural query!");36333634// Check intra-block reachability, however, other reaching paths are still3635// possible.3636if (FromBB == ToBB &&3637WillReachInBlock(*RQI.From, *RQI.To, RQI.ExclusionSet))3638return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,3639IsTemporaryRQI);36403641// Check if reaching the ToBB block is sufficient or if even that would not3642// ensure reaching the target. In the latter case we are done.3643if (!WillReachInBlock(ToBB->front(), *RQI.To, RQI.ExclusionSet))3644return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,3645IsTemporaryRQI);36463647const Function *Fn = FromBB->getParent();3648SmallPtrSet<const BasicBlock *, 16> ExclusionBlocks;3649if (RQI.ExclusionSet)3650for (auto *I : *RQI.ExclusionSet)3651if (I->getFunction() == Fn)3652ExclusionBlocks.insert(I->getParent());36533654// Check if we make it out of the FromBB block at all.3655if (ExclusionBlocks.count(FromBB) &&3656!WillReachInBlock(*RQI.From, *FromBB->getTerminator(),3657RQI.ExclusionSet))3658return rememberResult(A, RQITy::Reachable::No, RQI, true, IsTemporaryRQI);36593660auto *LivenessAA =3661A.getAAFor<AAIsDead>(*this, getIRPosition(), DepClassTy::OPTIONAL);3662if (LivenessAA && LivenessAA->isAssumedDead(ToBB)) {3663DeadBlocks.insert(ToBB);3664return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,3665IsTemporaryRQI);3666}36673668SmallPtrSet<const BasicBlock *, 16> Visited;3669SmallVector<const BasicBlock *, 16> Worklist;3670Worklist.push_back(FromBB);36713672DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> LocalDeadEdges;3673while (!Worklist.empty()) {3674const BasicBlock *BB = Worklist.pop_back_val();3675if (!Visited.insert(BB).second)3676continue;3677for (const BasicBlock *SuccBB : successors(BB)) {3678if (LivenessAA && LivenessAA->isEdgeDead(BB, SuccBB)) {3679LocalDeadEdges.insert({BB, SuccBB});3680continue;3681}3682// We checked before if we just need to reach the ToBB block.3683if (SuccBB == ToBB)3684return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,3685IsTemporaryRQI);3686if (DT && ExclusionBlocks.empty() && DT->dominates(BB, ToBB))3687return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,3688IsTemporaryRQI);36893690if (ExclusionBlocks.count(SuccBB)) {3691UsedExclusionSet = true;3692continue;3693}3694Worklist.push_back(SuccBB);3695}3696}36973698DeadEdges.insert(LocalDeadEdges.begin(), LocalDeadEdges.end());3699return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,3700IsTemporaryRQI);3701}37023703/// See AbstractAttribute::trackStatistics()3704void trackStatistics() const override {}37053706private:3707// Set of assumed dead blocks we used in the last query. If any changes we3708// update the state.3709DenseSet<const BasicBlock *> DeadBlocks;37103711// Set of assumed dead edges we used in the last query. If any changes we3712// update the state.3713DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> DeadEdges;37143715/// The dominator tree of the function to short-circuit reasoning.3716const DominatorTree *DT = nullptr;3717};3718} // namespace37193720/// ------------------------ NoAlias Argument Attribute ------------------------37213722bool AANoAlias::isImpliedByIR(Attributor &A, const IRPosition &IRP,3723Attribute::AttrKind ImpliedAttributeKind,3724bool IgnoreSubsumingPositions) {3725assert(ImpliedAttributeKind == Attribute::NoAlias &&3726"Unexpected attribute kind");3727Value *Val = &IRP.getAssociatedValue();3728if (IRP.getPositionKind() != IRP_CALL_SITE_ARGUMENT) {3729if (isa<AllocaInst>(Val))3730return true;3731} else {3732IgnoreSubsumingPositions = true;3733}37343735if (isa<UndefValue>(Val))3736return true;37373738if (isa<ConstantPointerNull>(Val) &&3739!NullPointerIsDefined(IRP.getAnchorScope(),3740Val->getType()->getPointerAddressSpace()))3741return true;37423743if (A.hasAttr(IRP, {Attribute::ByVal, Attribute::NoAlias},3744IgnoreSubsumingPositions, Attribute::NoAlias))3745return true;37463747return false;3748}37493750namespace {3751struct AANoAliasImpl : AANoAlias {3752AANoAliasImpl(const IRPosition &IRP, Attributor &A) : AANoAlias(IRP, A) {3753assert(getAssociatedType()->isPointerTy() &&3754"Noalias is a pointer attribute");3755}37563757const std::string getAsStr(Attributor *A) const override {3758return getAssumed() ? "noalias" : "may-alias";3759}3760};37613762/// NoAlias attribute for a floating value.3763struct AANoAliasFloating final : AANoAliasImpl {3764AANoAliasFloating(const IRPosition &IRP, Attributor &A)3765: AANoAliasImpl(IRP, A) {}37663767/// See AbstractAttribute::updateImpl(...).3768ChangeStatus updateImpl(Attributor &A) override {3769// TODO: Implement this.3770return indicatePessimisticFixpoint();3771}37723773/// See AbstractAttribute::trackStatistics()3774void trackStatistics() const override {3775STATS_DECLTRACK_FLOATING_ATTR(noalias)3776}3777};37783779/// NoAlias attribute for an argument.3780struct AANoAliasArgument final3781: AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl> {3782using Base = AAArgumentFromCallSiteArguments<AANoAlias, AANoAliasImpl>;3783AANoAliasArgument(const IRPosition &IRP, Attributor &A) : Base(IRP, A) {}37843785/// See AbstractAttribute::update(...).3786ChangeStatus updateImpl(Attributor &A) override {3787// We have to make sure no-alias on the argument does not break3788// synchronization when this is a callback argument, see also [1] below.3789// If synchronization cannot be affected, we delegate to the base updateImpl3790// function, otherwise we give up for now.37913792// If the function is no-sync, no-alias cannot break synchronization.3793bool IsKnownNoSycn;3794if (AA::hasAssumedIRAttr<Attribute::NoSync>(3795A, this, IRPosition::function_scope(getIRPosition()),3796DepClassTy::OPTIONAL, IsKnownNoSycn))3797return Base::updateImpl(A);37983799// If the argument is read-only, no-alias cannot break synchronization.3800bool IsKnown;3801if (AA::isAssumedReadOnly(A, getIRPosition(), *this, IsKnown))3802return Base::updateImpl(A);38033804// If the argument is never passed through callbacks, no-alias cannot break3805// synchronization.3806bool UsedAssumedInformation = false;3807if (A.checkForAllCallSites(3808[](AbstractCallSite ACS) { return !ACS.isCallbackCall(); }, *this,3809true, UsedAssumedInformation))3810return Base::updateImpl(A);38113812// TODO: add no-alias but make sure it doesn't break synchronization by3813// introducing fake uses. See:3814// [1] Compiler Optimizations for OpenMP, J. Doerfert and H. Finkel,3815// International Workshop on OpenMP 2018,3816// http://compilers.cs.uni-saarland.de/people/doerfert/par_opt18.pdf38173818return indicatePessimisticFixpoint();3819}38203821/// See AbstractAttribute::trackStatistics()3822void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noalias) }3823};38243825struct AANoAliasCallSiteArgument final : AANoAliasImpl {3826AANoAliasCallSiteArgument(const IRPosition &IRP, Attributor &A)3827: AANoAliasImpl(IRP, A) {}38283829/// Determine if the underlying value may alias with the call site argument3830/// \p OtherArgNo of \p ICS (= the underlying call site).3831bool mayAliasWithArgument(Attributor &A, AAResults *&AAR,3832const AAMemoryBehavior &MemBehaviorAA,3833const CallBase &CB, unsigned OtherArgNo) {3834// We do not need to worry about aliasing with the underlying IRP.3835if (this->getCalleeArgNo() == (int)OtherArgNo)3836return false;38373838// If it is not a pointer or pointer vector we do not alias.3839const Value *ArgOp = CB.getArgOperand(OtherArgNo);3840if (!ArgOp->getType()->isPtrOrPtrVectorTy())3841return false;38423843auto *CBArgMemBehaviorAA = A.getAAFor<AAMemoryBehavior>(3844*this, IRPosition::callsite_argument(CB, OtherArgNo), DepClassTy::NONE);38453846// If the argument is readnone, there is no read-write aliasing.3847if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadNone()) {3848A.recordDependence(*CBArgMemBehaviorAA, *this, DepClassTy::OPTIONAL);3849return false;3850}38513852// If the argument is readonly and the underlying value is readonly, there3853// is no read-write aliasing.3854bool IsReadOnly = MemBehaviorAA.isAssumedReadOnly();3855if (CBArgMemBehaviorAA && CBArgMemBehaviorAA->isAssumedReadOnly() &&3856IsReadOnly) {3857A.recordDependence(MemBehaviorAA, *this, DepClassTy::OPTIONAL);3858A.recordDependence(*CBArgMemBehaviorAA, *this, DepClassTy::OPTIONAL);3859return false;3860}38613862// We have to utilize actual alias analysis queries so we need the object.3863if (!AAR)3864AAR = A.getInfoCache().getAnalysisResultForFunction<AAManager>(3865*getAnchorScope());38663867// Try to rule it out at the call site.3868bool IsAliasing = !AAR || !AAR->isNoAlias(&getAssociatedValue(), ArgOp);3869LLVM_DEBUG(dbgs() << "[NoAliasCSArg] Check alias between "3870"callsite arguments: "3871<< getAssociatedValue() << " " << *ArgOp << " => "3872<< (IsAliasing ? "" : "no-") << "alias \n");38733874return IsAliasing;3875}38763877bool isKnownNoAliasDueToNoAliasPreservation(3878Attributor &A, AAResults *&AAR, const AAMemoryBehavior &MemBehaviorAA) {3879// We can deduce "noalias" if the following conditions hold.3880// (i) Associated value is assumed to be noalias in the definition.3881// (ii) Associated value is assumed to be no-capture in all the uses3882// possibly executed before this callsite.3883// (iii) There is no other pointer argument which could alias with the3884// value.38853886auto IsDereferenceableOrNull = [&](Value *O, const DataLayout &DL) {3887const auto *DerefAA = A.getAAFor<AADereferenceable>(3888*this, IRPosition::value(*O), DepClassTy::OPTIONAL);3889return DerefAA ? DerefAA->getAssumedDereferenceableBytes() : 0;3890};38913892const IRPosition &VIRP = IRPosition::value(getAssociatedValue());3893const Function *ScopeFn = VIRP.getAnchorScope();3894// Check whether the value is captured in the scope using AANoCapture.3895// Look at CFG and check only uses possibly executed before this3896// callsite.3897auto UsePred = [&](const Use &U, bool &Follow) -> bool {3898Instruction *UserI = cast<Instruction>(U.getUser());38993900// If UserI is the curr instruction and there is a single potential use of3901// the value in UserI we allow the use.3902// TODO: We should inspect the operands and allow those that cannot alias3903// with the value.3904if (UserI == getCtxI() && UserI->getNumOperands() == 1)3905return true;39063907if (ScopeFn) {3908if (auto *CB = dyn_cast<CallBase>(UserI)) {3909if (CB->isArgOperand(&U)) {39103911unsigned ArgNo = CB->getArgOperandNo(&U);39123913bool IsKnownNoCapture;3914if (AA::hasAssumedIRAttr<Attribute::NoCapture>(3915A, this, IRPosition::callsite_argument(*CB, ArgNo),3916DepClassTy::OPTIONAL, IsKnownNoCapture))3917return true;3918}3919}39203921if (!AA::isPotentiallyReachable(3922A, *UserI, *getCtxI(), *this, /* ExclusionSet */ nullptr,3923[ScopeFn](const Function &Fn) { return &Fn != ScopeFn; }))3924return true;3925}39263927// TODO: We should track the capturing uses in AANoCapture but the problem3928// is CGSCC runs. For those we would need to "allow" AANoCapture for3929// a value in the module slice.3930switch (DetermineUseCaptureKind(U, IsDereferenceableOrNull)) {3931case UseCaptureKind::NO_CAPTURE:3932return true;3933case UseCaptureKind::MAY_CAPTURE:3934LLVM_DEBUG(dbgs() << "[AANoAliasCSArg] Unknown user: " << *UserI3935<< "\n");3936return false;3937case UseCaptureKind::PASSTHROUGH:3938Follow = true;3939return true;3940}3941llvm_unreachable("unknown UseCaptureKind");3942};39433944bool IsKnownNoCapture;3945const AANoCapture *NoCaptureAA = nullptr;3946bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(3947A, this, VIRP, DepClassTy::NONE, IsKnownNoCapture, false, &NoCaptureAA);3948if (!IsAssumedNoCapture &&3949(!NoCaptureAA || !NoCaptureAA->isAssumedNoCaptureMaybeReturned())) {3950if (!A.checkForAllUses(UsePred, *this, getAssociatedValue())) {3951LLVM_DEBUG(3952dbgs() << "[AANoAliasCSArg] " << getAssociatedValue()3953<< " cannot be noalias as it is potentially captured\n");3954return false;3955}3956}3957if (NoCaptureAA)3958A.recordDependence(*NoCaptureAA, *this, DepClassTy::OPTIONAL);39593960// Check there is no other pointer argument which could alias with the3961// value passed at this call site.3962// TODO: AbstractCallSite3963const auto &CB = cast<CallBase>(getAnchorValue());3964for (unsigned OtherArgNo = 0; OtherArgNo < CB.arg_size(); OtherArgNo++)3965if (mayAliasWithArgument(A, AAR, MemBehaviorAA, CB, OtherArgNo))3966return false;39673968return true;3969}39703971/// See AbstractAttribute::updateImpl(...).3972ChangeStatus updateImpl(Attributor &A) override {3973// If the argument is readnone we are done as there are no accesses via the3974// argument.3975auto *MemBehaviorAA =3976A.getAAFor<AAMemoryBehavior>(*this, getIRPosition(), DepClassTy::NONE);3977if (MemBehaviorAA && MemBehaviorAA->isAssumedReadNone()) {3978A.recordDependence(*MemBehaviorAA, *this, DepClassTy::OPTIONAL);3979return ChangeStatus::UNCHANGED;3980}39813982bool IsKnownNoAlias;3983const IRPosition &VIRP = IRPosition::value(getAssociatedValue());3984if (!AA::hasAssumedIRAttr<Attribute::NoAlias>(3985A, this, VIRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {3986LLVM_DEBUG(dbgs() << "[AANoAlias] " << getAssociatedValue()3987<< " is not no-alias at the definition\n");3988return indicatePessimisticFixpoint();3989}39903991AAResults *AAR = nullptr;3992if (MemBehaviorAA &&3993isKnownNoAliasDueToNoAliasPreservation(A, AAR, *MemBehaviorAA)) {3994LLVM_DEBUG(3995dbgs() << "[AANoAlias] No-Alias deduced via no-alias preservation\n");3996return ChangeStatus::UNCHANGED;3997}39983999return indicatePessimisticFixpoint();4000}40014002/// See AbstractAttribute::trackStatistics()4003void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noalias) }4004};40054006/// NoAlias attribute for function return value.4007struct AANoAliasReturned final : AANoAliasImpl {4008AANoAliasReturned(const IRPosition &IRP, Attributor &A)4009: AANoAliasImpl(IRP, A) {}40104011/// See AbstractAttribute::updateImpl(...).4012ChangeStatus updateImpl(Attributor &A) override {40134014auto CheckReturnValue = [&](Value &RV) -> bool {4015if (Constant *C = dyn_cast<Constant>(&RV))4016if (C->isNullValue() || isa<UndefValue>(C))4017return true;40184019/// For now, we can only deduce noalias if we have call sites.4020/// FIXME: add more support.4021if (!isa<CallBase>(&RV))4022return false;40234024const IRPosition &RVPos = IRPosition::value(RV);4025bool IsKnownNoAlias;4026if (!AA::hasAssumedIRAttr<Attribute::NoAlias>(4027A, this, RVPos, DepClassTy::REQUIRED, IsKnownNoAlias))4028return false;40294030bool IsKnownNoCapture;4031const AANoCapture *NoCaptureAA = nullptr;4032bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(4033A, this, RVPos, DepClassTy::REQUIRED, IsKnownNoCapture, false,4034&NoCaptureAA);4035return IsAssumedNoCapture ||4036(NoCaptureAA && NoCaptureAA->isAssumedNoCaptureMaybeReturned());4037};40384039if (!A.checkForAllReturnedValues(CheckReturnValue, *this))4040return indicatePessimisticFixpoint();40414042return ChangeStatus::UNCHANGED;4043}40444045/// See AbstractAttribute::trackStatistics()4046void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noalias) }4047};40484049/// NoAlias attribute deduction for a call site return value.4050struct AANoAliasCallSiteReturned final4051: AACalleeToCallSite<AANoAlias, AANoAliasImpl> {4052AANoAliasCallSiteReturned(const IRPosition &IRP, Attributor &A)4053: AACalleeToCallSite<AANoAlias, AANoAliasImpl>(IRP, A) {}40544055/// See AbstractAttribute::trackStatistics()4056void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noalias); }4057};4058} // namespace40594060/// -------------------AAIsDead Function Attribute-----------------------40614062namespace {4063struct AAIsDeadValueImpl : public AAIsDead {4064AAIsDeadValueImpl(const IRPosition &IRP, Attributor &A) : AAIsDead(IRP, A) {}40654066/// See AAIsDead::isAssumedDead().4067bool isAssumedDead() const override { return isAssumed(IS_DEAD); }40684069/// See AAIsDead::isKnownDead().4070bool isKnownDead() const override { return isKnown(IS_DEAD); }40714072/// See AAIsDead::isAssumedDead(BasicBlock *).4073bool isAssumedDead(const BasicBlock *BB) const override { return false; }40744075/// See AAIsDead::isKnownDead(BasicBlock *).4076bool isKnownDead(const BasicBlock *BB) const override { return false; }40774078/// See AAIsDead::isAssumedDead(Instruction *I).4079bool isAssumedDead(const Instruction *I) const override {4080return I == getCtxI() && isAssumedDead();4081}40824083/// See AAIsDead::isKnownDead(Instruction *I).4084bool isKnownDead(const Instruction *I) const override {4085return isAssumedDead(I) && isKnownDead();4086}40874088/// See AbstractAttribute::getAsStr().4089const std::string getAsStr(Attributor *A) const override {4090return isAssumedDead() ? "assumed-dead" : "assumed-live";4091}40924093/// Check if all uses are assumed dead.4094bool areAllUsesAssumedDead(Attributor &A, Value &V) {4095// Callers might not check the type, void has no uses.4096if (V.getType()->isVoidTy() || V.use_empty())4097return true;40984099// If we replace a value with a constant there are no uses left afterwards.4100if (!isa<Constant>(V)) {4101if (auto *I = dyn_cast<Instruction>(&V))4102if (!A.isRunOn(*I->getFunction()))4103return false;4104bool UsedAssumedInformation = false;4105std::optional<Constant *> C =4106A.getAssumedConstant(V, *this, UsedAssumedInformation);4107if (!C || *C)4108return true;4109}41104111auto UsePred = [&](const Use &U, bool &Follow) { return false; };4112// Explicitly set the dependence class to required because we want a long4113// chain of N dependent instructions to be considered live as soon as one is4114// without going through N update cycles. This is not required for4115// correctness.4116return A.checkForAllUses(UsePred, *this, V, /* CheckBBLivenessOnly */ false,4117DepClassTy::REQUIRED,4118/* IgnoreDroppableUses */ false);4119}41204121/// Determine if \p I is assumed to be side-effect free.4122bool isAssumedSideEffectFree(Attributor &A, Instruction *I) {4123if (!I || wouldInstructionBeTriviallyDead(I))4124return true;41254126auto *CB = dyn_cast<CallBase>(I);4127if (!CB || isa<IntrinsicInst>(CB))4128return false;41294130const IRPosition &CallIRP = IRPosition::callsite_function(*CB);41314132bool IsKnownNoUnwind;4133if (!AA::hasAssumedIRAttr<Attribute::NoUnwind>(4134A, this, CallIRP, DepClassTy::OPTIONAL, IsKnownNoUnwind))4135return false;41364137bool IsKnown;4138return AA::isAssumedReadOnly(A, CallIRP, *this, IsKnown);4139}4140};41414142struct AAIsDeadFloating : public AAIsDeadValueImpl {4143AAIsDeadFloating(const IRPosition &IRP, Attributor &A)4144: AAIsDeadValueImpl(IRP, A) {}41454146/// See AbstractAttribute::initialize(...).4147void initialize(Attributor &A) override {4148AAIsDeadValueImpl::initialize(A);41494150if (isa<UndefValue>(getAssociatedValue())) {4151indicatePessimisticFixpoint();4152return;4153}41544155Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());4156if (!isAssumedSideEffectFree(A, I)) {4157if (!isa_and_nonnull<StoreInst>(I) && !isa_and_nonnull<FenceInst>(I))4158indicatePessimisticFixpoint();4159else4160removeAssumedBits(HAS_NO_EFFECT);4161}4162}41634164bool isDeadFence(Attributor &A, FenceInst &FI) {4165const auto *ExecDomainAA = A.lookupAAFor<AAExecutionDomain>(4166IRPosition::function(*FI.getFunction()), *this, DepClassTy::NONE);4167if (!ExecDomainAA || !ExecDomainAA->isNoOpFence(FI))4168return false;4169A.recordDependence(*ExecDomainAA, *this, DepClassTy::OPTIONAL);4170return true;4171}41724173bool isDeadStore(Attributor &A, StoreInst &SI,4174SmallSetVector<Instruction *, 8> *AssumeOnlyInst = nullptr) {4175// Lang ref now states volatile store is not UB/dead, let's skip them.4176if (SI.isVolatile())4177return false;41784179// If we are collecting assumes to be deleted we are in the manifest stage.4180// It's problematic to collect the potential copies again now so we use the4181// cached ones.4182bool UsedAssumedInformation = false;4183if (!AssumeOnlyInst) {4184PotentialCopies.clear();4185if (!AA::getPotentialCopiesOfStoredValue(A, SI, PotentialCopies, *this,4186UsedAssumedInformation)) {4187LLVM_DEBUG(4188dbgs()4189<< "[AAIsDead] Could not determine potential copies of store!\n");4190return false;4191}4192}4193LLVM_DEBUG(dbgs() << "[AAIsDead] Store has " << PotentialCopies.size()4194<< " potential copies.\n");41954196InformationCache &InfoCache = A.getInfoCache();4197return llvm::all_of(PotentialCopies, [&](Value *V) {4198if (A.isAssumedDead(IRPosition::value(*V), this, nullptr,4199UsedAssumedInformation))4200return true;4201if (auto *LI = dyn_cast<LoadInst>(V)) {4202if (llvm::all_of(LI->uses(), [&](const Use &U) {4203auto &UserI = cast<Instruction>(*U.getUser());4204if (InfoCache.isOnlyUsedByAssume(UserI)) {4205if (AssumeOnlyInst)4206AssumeOnlyInst->insert(&UserI);4207return true;4208}4209return A.isAssumedDead(U, this, nullptr, UsedAssumedInformation);4210})) {4211return true;4212}4213}4214LLVM_DEBUG(dbgs() << "[AAIsDead] Potential copy " << *V4215<< " is assumed live!\n");4216return false;4217});4218}42194220/// See AbstractAttribute::getAsStr().4221const std::string getAsStr(Attributor *A) const override {4222Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());4223if (isa_and_nonnull<StoreInst>(I))4224if (isValidState())4225return "assumed-dead-store";4226if (isa_and_nonnull<FenceInst>(I))4227if (isValidState())4228return "assumed-dead-fence";4229return AAIsDeadValueImpl::getAsStr(A);4230}42314232/// See AbstractAttribute::updateImpl(...).4233ChangeStatus updateImpl(Attributor &A) override {4234Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());4235if (auto *SI = dyn_cast_or_null<StoreInst>(I)) {4236if (!isDeadStore(A, *SI))4237return indicatePessimisticFixpoint();4238} else if (auto *FI = dyn_cast_or_null<FenceInst>(I)) {4239if (!isDeadFence(A, *FI))4240return indicatePessimisticFixpoint();4241} else {4242if (!isAssumedSideEffectFree(A, I))4243return indicatePessimisticFixpoint();4244if (!areAllUsesAssumedDead(A, getAssociatedValue()))4245return indicatePessimisticFixpoint();4246}4247return ChangeStatus::UNCHANGED;4248}42494250bool isRemovableStore() const override {4251return isAssumed(IS_REMOVABLE) && isa<StoreInst>(&getAssociatedValue());4252}42534254/// See AbstractAttribute::manifest(...).4255ChangeStatus manifest(Attributor &A) override {4256Value &V = getAssociatedValue();4257if (auto *I = dyn_cast<Instruction>(&V)) {4258// If we get here we basically know the users are all dead. We check if4259// isAssumedSideEffectFree returns true here again because it might not be4260// the case and only the users are dead but the instruction (=call) is4261// still needed.4262if (auto *SI = dyn_cast<StoreInst>(I)) {4263SmallSetVector<Instruction *, 8> AssumeOnlyInst;4264bool IsDead = isDeadStore(A, *SI, &AssumeOnlyInst);4265(void)IsDead;4266assert(IsDead && "Store was assumed to be dead!");4267A.deleteAfterManifest(*I);4268for (size_t i = 0; i < AssumeOnlyInst.size(); ++i) {4269Instruction *AOI = AssumeOnlyInst[i];4270for (auto *Usr : AOI->users())4271AssumeOnlyInst.insert(cast<Instruction>(Usr));4272A.deleteAfterManifest(*AOI);4273}4274return ChangeStatus::CHANGED;4275}4276if (auto *FI = dyn_cast<FenceInst>(I)) {4277assert(isDeadFence(A, *FI));4278A.deleteAfterManifest(*FI);4279return ChangeStatus::CHANGED;4280}4281if (isAssumedSideEffectFree(A, I) && !isa<InvokeInst>(I)) {4282A.deleteAfterManifest(*I);4283return ChangeStatus::CHANGED;4284}4285}4286return ChangeStatus::UNCHANGED;4287}42884289/// See AbstractAttribute::trackStatistics()4290void trackStatistics() const override {4291STATS_DECLTRACK_FLOATING_ATTR(IsDead)4292}42934294private:4295// The potential copies of a dead store, used for deletion during manifest.4296SmallSetVector<Value *, 4> PotentialCopies;4297};42984299struct AAIsDeadArgument : public AAIsDeadFloating {4300AAIsDeadArgument(const IRPosition &IRP, Attributor &A)4301: AAIsDeadFloating(IRP, A) {}43024303/// See AbstractAttribute::manifest(...).4304ChangeStatus manifest(Attributor &A) override {4305Argument &Arg = *getAssociatedArgument();4306if (A.isValidFunctionSignatureRewrite(Arg, /* ReplacementTypes */ {}))4307if (A.registerFunctionSignatureRewrite(4308Arg, /* ReplacementTypes */ {},4309Attributor::ArgumentReplacementInfo::CalleeRepairCBTy{},4310Attributor::ArgumentReplacementInfo::ACSRepairCBTy{})) {4311return ChangeStatus::CHANGED;4312}4313return ChangeStatus::UNCHANGED;4314}43154316/// See AbstractAttribute::trackStatistics()4317void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(IsDead) }4318};43194320struct AAIsDeadCallSiteArgument : public AAIsDeadValueImpl {4321AAIsDeadCallSiteArgument(const IRPosition &IRP, Attributor &A)4322: AAIsDeadValueImpl(IRP, A) {}43234324/// See AbstractAttribute::initialize(...).4325void initialize(Attributor &A) override {4326AAIsDeadValueImpl::initialize(A);4327if (isa<UndefValue>(getAssociatedValue()))4328indicatePessimisticFixpoint();4329}43304331/// See AbstractAttribute::updateImpl(...).4332ChangeStatus updateImpl(Attributor &A) override {4333// TODO: Once we have call site specific value information we can provide4334// call site specific liveness information and then it makes4335// sense to specialize attributes for call sites arguments instead of4336// redirecting requests to the callee argument.4337Argument *Arg = getAssociatedArgument();4338if (!Arg)4339return indicatePessimisticFixpoint();4340const IRPosition &ArgPos = IRPosition::argument(*Arg);4341auto *ArgAA = A.getAAFor<AAIsDead>(*this, ArgPos, DepClassTy::REQUIRED);4342if (!ArgAA)4343return indicatePessimisticFixpoint();4344return clampStateAndIndicateChange(getState(), ArgAA->getState());4345}43464347/// See AbstractAttribute::manifest(...).4348ChangeStatus manifest(Attributor &A) override {4349CallBase &CB = cast<CallBase>(getAnchorValue());4350Use &U = CB.getArgOperandUse(getCallSiteArgNo());4351assert(!isa<UndefValue>(U.get()) &&4352"Expected undef values to be filtered out!");4353UndefValue &UV = *UndefValue::get(U->getType());4354if (A.changeUseAfterManifest(U, UV))4355return ChangeStatus::CHANGED;4356return ChangeStatus::UNCHANGED;4357}43584359/// See AbstractAttribute::trackStatistics()4360void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(IsDead) }4361};43624363struct AAIsDeadCallSiteReturned : public AAIsDeadFloating {4364AAIsDeadCallSiteReturned(const IRPosition &IRP, Attributor &A)4365: AAIsDeadFloating(IRP, A) {}43664367/// See AAIsDead::isAssumedDead().4368bool isAssumedDead() const override {4369return AAIsDeadFloating::isAssumedDead() && IsAssumedSideEffectFree;4370}43714372/// See AbstractAttribute::initialize(...).4373void initialize(Attributor &A) override {4374AAIsDeadFloating::initialize(A);4375if (isa<UndefValue>(getAssociatedValue())) {4376indicatePessimisticFixpoint();4377return;4378}43794380// We track this separately as a secondary state.4381IsAssumedSideEffectFree = isAssumedSideEffectFree(A, getCtxI());4382}43834384/// See AbstractAttribute::updateImpl(...).4385ChangeStatus updateImpl(Attributor &A) override {4386ChangeStatus Changed = ChangeStatus::UNCHANGED;4387if (IsAssumedSideEffectFree && !isAssumedSideEffectFree(A, getCtxI())) {4388IsAssumedSideEffectFree = false;4389Changed = ChangeStatus::CHANGED;4390}4391if (!areAllUsesAssumedDead(A, getAssociatedValue()))4392return indicatePessimisticFixpoint();4393return Changed;4394}43954396/// See AbstractAttribute::trackStatistics()4397void trackStatistics() const override {4398if (IsAssumedSideEffectFree)4399STATS_DECLTRACK_CSRET_ATTR(IsDead)4400else4401STATS_DECLTRACK_CSRET_ATTR(UnusedResult)4402}44034404/// See AbstractAttribute::getAsStr().4405const std::string getAsStr(Attributor *A) const override {4406return isAssumedDead()4407? "assumed-dead"4408: (getAssumed() ? "assumed-dead-users" : "assumed-live");4409}44104411private:4412bool IsAssumedSideEffectFree = true;4413};44144415struct AAIsDeadReturned : public AAIsDeadValueImpl {4416AAIsDeadReturned(const IRPosition &IRP, Attributor &A)4417: AAIsDeadValueImpl(IRP, A) {}44184419/// See AbstractAttribute::updateImpl(...).4420ChangeStatus updateImpl(Attributor &A) override {44214422bool UsedAssumedInformation = false;4423A.checkForAllInstructions([](Instruction &) { return true; }, *this,4424{Instruction::Ret}, UsedAssumedInformation);44254426auto PredForCallSite = [&](AbstractCallSite ACS) {4427if (ACS.isCallbackCall() || !ACS.getInstruction())4428return false;4429return areAllUsesAssumedDead(A, *ACS.getInstruction());4430};44314432if (!A.checkForAllCallSites(PredForCallSite, *this, true,4433UsedAssumedInformation))4434return indicatePessimisticFixpoint();44354436return ChangeStatus::UNCHANGED;4437}44384439/// See AbstractAttribute::manifest(...).4440ChangeStatus manifest(Attributor &A) override {4441// TODO: Rewrite the signature to return void?4442bool AnyChange = false;4443UndefValue &UV = *UndefValue::get(getAssociatedFunction()->getReturnType());4444auto RetInstPred = [&](Instruction &I) {4445ReturnInst &RI = cast<ReturnInst>(I);4446if (!isa<UndefValue>(RI.getReturnValue()))4447AnyChange |= A.changeUseAfterManifest(RI.getOperandUse(0), UV);4448return true;4449};4450bool UsedAssumedInformation = false;4451A.checkForAllInstructions(RetInstPred, *this, {Instruction::Ret},4452UsedAssumedInformation);4453return AnyChange ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;4454}44554456/// See AbstractAttribute::trackStatistics()4457void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(IsDead) }4458};44594460struct AAIsDeadFunction : public AAIsDead {4461AAIsDeadFunction(const IRPosition &IRP, Attributor &A) : AAIsDead(IRP, A) {}44624463/// See AbstractAttribute::initialize(...).4464void initialize(Attributor &A) override {4465Function *F = getAnchorScope();4466assert(F && "Did expect an anchor function");4467if (!isAssumedDeadInternalFunction(A)) {4468ToBeExploredFrom.insert(&F->getEntryBlock().front());4469assumeLive(A, F->getEntryBlock());4470}4471}44724473bool isAssumedDeadInternalFunction(Attributor &A) {4474if (!getAnchorScope()->hasLocalLinkage())4475return false;4476bool UsedAssumedInformation = false;4477return A.checkForAllCallSites([](AbstractCallSite) { return false; }, *this,4478true, UsedAssumedInformation);4479}44804481/// See AbstractAttribute::getAsStr().4482const std::string getAsStr(Attributor *A) const override {4483return "Live[#BB " + std::to_string(AssumedLiveBlocks.size()) + "/" +4484std::to_string(getAnchorScope()->size()) + "][#TBEP " +4485std::to_string(ToBeExploredFrom.size()) + "][#KDE " +4486std::to_string(KnownDeadEnds.size()) + "]";4487}44884489/// See AbstractAttribute::manifest(...).4490ChangeStatus manifest(Attributor &A) override {4491assert(getState().isValidState() &&4492"Attempted to manifest an invalid state!");44934494ChangeStatus HasChanged = ChangeStatus::UNCHANGED;4495Function &F = *getAnchorScope();44964497if (AssumedLiveBlocks.empty()) {4498A.deleteAfterManifest(F);4499return ChangeStatus::CHANGED;4500}45014502// Flag to determine if we can change an invoke to a call assuming the4503// callee is nounwind. This is not possible if the personality of the4504// function allows to catch asynchronous exceptions.4505bool Invoke2CallAllowed = !mayCatchAsynchronousExceptions(F);45064507KnownDeadEnds.set_union(ToBeExploredFrom);4508for (const Instruction *DeadEndI : KnownDeadEnds) {4509auto *CB = dyn_cast<CallBase>(DeadEndI);4510if (!CB)4511continue;4512bool IsKnownNoReturn;4513bool MayReturn = !AA::hasAssumedIRAttr<Attribute::NoReturn>(4514A, this, IRPosition::callsite_function(*CB), DepClassTy::OPTIONAL,4515IsKnownNoReturn);4516if (MayReturn && (!Invoke2CallAllowed || !isa<InvokeInst>(CB)))4517continue;45184519if (auto *II = dyn_cast<InvokeInst>(DeadEndI))4520A.registerInvokeWithDeadSuccessor(const_cast<InvokeInst &>(*II));4521else4522A.changeToUnreachableAfterManifest(4523const_cast<Instruction *>(DeadEndI->getNextNode()));4524HasChanged = ChangeStatus::CHANGED;4525}45264527STATS_DECL(AAIsDead, BasicBlock, "Number of dead basic blocks deleted.");4528for (BasicBlock &BB : F)4529if (!AssumedLiveBlocks.count(&BB)) {4530A.deleteAfterManifest(BB);4531++BUILD_STAT_NAME(AAIsDead, BasicBlock);4532HasChanged = ChangeStatus::CHANGED;4533}45344535return HasChanged;4536}45374538/// See AbstractAttribute::updateImpl(...).4539ChangeStatus updateImpl(Attributor &A) override;45404541bool isEdgeDead(const BasicBlock *From, const BasicBlock *To) const override {4542assert(From->getParent() == getAnchorScope() &&4543To->getParent() == getAnchorScope() &&4544"Used AAIsDead of the wrong function");4545return isValidState() && !AssumedLiveEdges.count(std::make_pair(From, To));4546}45474548/// See AbstractAttribute::trackStatistics()4549void trackStatistics() const override {}45504551/// Returns true if the function is assumed dead.4552bool isAssumedDead() const override { return false; }45534554/// See AAIsDead::isKnownDead().4555bool isKnownDead() const override { return false; }45564557/// See AAIsDead::isAssumedDead(BasicBlock *).4558bool isAssumedDead(const BasicBlock *BB) const override {4559assert(BB->getParent() == getAnchorScope() &&4560"BB must be in the same anchor scope function.");45614562if (!getAssumed())4563return false;4564return !AssumedLiveBlocks.count(BB);4565}45664567/// See AAIsDead::isKnownDead(BasicBlock *).4568bool isKnownDead(const BasicBlock *BB) const override {4569return getKnown() && isAssumedDead(BB);4570}45714572/// See AAIsDead::isAssumed(Instruction *I).4573bool isAssumedDead(const Instruction *I) const override {4574assert(I->getParent()->getParent() == getAnchorScope() &&4575"Instruction must be in the same anchor scope function.");45764577if (!getAssumed())4578return false;45794580// If it is not in AssumedLiveBlocks then it for sure dead.4581// Otherwise, it can still be after noreturn call in a live block.4582if (!AssumedLiveBlocks.count(I->getParent()))4583return true;45844585// If it is not after a liveness barrier it is live.4586const Instruction *PrevI = I->getPrevNode();4587while (PrevI) {4588if (KnownDeadEnds.count(PrevI) || ToBeExploredFrom.count(PrevI))4589return true;4590PrevI = PrevI->getPrevNode();4591}4592return false;4593}45944595/// See AAIsDead::isKnownDead(Instruction *I).4596bool isKnownDead(const Instruction *I) const override {4597return getKnown() && isAssumedDead(I);4598}45994600/// Assume \p BB is (partially) live now and indicate to the Attributor \p A4601/// that internal function called from \p BB should now be looked at.4602bool assumeLive(Attributor &A, const BasicBlock &BB) {4603if (!AssumedLiveBlocks.insert(&BB).second)4604return false;46054606// We assume that all of BB is (probably) live now and if there are calls to4607// internal functions we will assume that those are now live as well. This4608// is a performance optimization for blocks with calls to a lot of internal4609// functions. It can however cause dead functions to be treated as live.4610for (const Instruction &I : BB)4611if (const auto *CB = dyn_cast<CallBase>(&I))4612if (auto *F = dyn_cast_if_present<Function>(CB->getCalledOperand()))4613if (F->hasLocalLinkage())4614A.markLiveInternalFunction(*F);4615return true;4616}46174618/// Collection of instructions that need to be explored again, e.g., we4619/// did assume they do not transfer control to (one of their) successors.4620SmallSetVector<const Instruction *, 8> ToBeExploredFrom;46214622/// Collection of instructions that are known to not transfer control.4623SmallSetVector<const Instruction *, 8> KnownDeadEnds;46244625/// Collection of all assumed live edges4626DenseSet<std::pair<const BasicBlock *, const BasicBlock *>> AssumedLiveEdges;46274628/// Collection of all assumed live BasicBlocks.4629DenseSet<const BasicBlock *> AssumedLiveBlocks;4630};46314632static bool4633identifyAliveSuccessors(Attributor &A, const CallBase &CB,4634AbstractAttribute &AA,4635SmallVectorImpl<const Instruction *> &AliveSuccessors) {4636const IRPosition &IPos = IRPosition::callsite_function(CB);46374638bool IsKnownNoReturn;4639if (AA::hasAssumedIRAttr<Attribute::NoReturn>(4640A, &AA, IPos, DepClassTy::OPTIONAL, IsKnownNoReturn))4641return !IsKnownNoReturn;4642if (CB.isTerminator())4643AliveSuccessors.push_back(&CB.getSuccessor(0)->front());4644else4645AliveSuccessors.push_back(CB.getNextNode());4646return false;4647}46484649static bool4650identifyAliveSuccessors(Attributor &A, const InvokeInst &II,4651AbstractAttribute &AA,4652SmallVectorImpl<const Instruction *> &AliveSuccessors) {4653bool UsedAssumedInformation =4654identifyAliveSuccessors(A, cast<CallBase>(II), AA, AliveSuccessors);46554656// First, determine if we can change an invoke to a call assuming the4657// callee is nounwind. This is not possible if the personality of the4658// function allows to catch asynchronous exceptions.4659if (AAIsDeadFunction::mayCatchAsynchronousExceptions(*II.getFunction())) {4660AliveSuccessors.push_back(&II.getUnwindDest()->front());4661} else {4662const IRPosition &IPos = IRPosition::callsite_function(II);46634664bool IsKnownNoUnwind;4665if (AA::hasAssumedIRAttr<Attribute::NoUnwind>(4666A, &AA, IPos, DepClassTy::OPTIONAL, IsKnownNoUnwind)) {4667UsedAssumedInformation |= !IsKnownNoUnwind;4668} else {4669AliveSuccessors.push_back(&II.getUnwindDest()->front());4670}4671}4672return UsedAssumedInformation;4673}46744675static bool4676identifyAliveSuccessors(Attributor &A, const BranchInst &BI,4677AbstractAttribute &AA,4678SmallVectorImpl<const Instruction *> &AliveSuccessors) {4679bool UsedAssumedInformation = false;4680if (BI.getNumSuccessors() == 1) {4681AliveSuccessors.push_back(&BI.getSuccessor(0)->front());4682} else {4683std::optional<Constant *> C =4684A.getAssumedConstant(*BI.getCondition(), AA, UsedAssumedInformation);4685if (!C || isa_and_nonnull<UndefValue>(*C)) {4686// No value yet, assume both edges are dead.4687} else if (isa_and_nonnull<ConstantInt>(*C)) {4688const BasicBlock *SuccBB =4689BI.getSuccessor(1 - cast<ConstantInt>(*C)->getValue().getZExtValue());4690AliveSuccessors.push_back(&SuccBB->front());4691} else {4692AliveSuccessors.push_back(&BI.getSuccessor(0)->front());4693AliveSuccessors.push_back(&BI.getSuccessor(1)->front());4694UsedAssumedInformation = false;4695}4696}4697return UsedAssumedInformation;4698}46994700static bool4701identifyAliveSuccessors(Attributor &A, const SwitchInst &SI,4702AbstractAttribute &AA,4703SmallVectorImpl<const Instruction *> &AliveSuccessors) {4704bool UsedAssumedInformation = false;4705SmallVector<AA::ValueAndContext> Values;4706if (!A.getAssumedSimplifiedValues(IRPosition::value(*SI.getCondition()), &AA,4707Values, AA::AnyScope,4708UsedAssumedInformation)) {4709// Something went wrong, assume all successors are live.4710for (const BasicBlock *SuccBB : successors(SI.getParent()))4711AliveSuccessors.push_back(&SuccBB->front());4712return false;4713}47144715if (Values.empty() ||4716(Values.size() == 1 &&4717isa_and_nonnull<UndefValue>(Values.front().getValue()))) {4718// No valid value yet, assume all edges are dead.4719return UsedAssumedInformation;4720}47214722Type &Ty = *SI.getCondition()->getType();4723SmallPtrSet<ConstantInt *, 8> Constants;4724auto CheckForConstantInt = [&](Value *V) {4725if (auto *CI = dyn_cast_if_present<ConstantInt>(AA::getWithType(*V, Ty))) {4726Constants.insert(CI);4727return true;4728}4729return false;4730};47314732if (!all_of(Values, [&](AA::ValueAndContext &VAC) {4733return CheckForConstantInt(VAC.getValue());4734})) {4735for (const BasicBlock *SuccBB : successors(SI.getParent()))4736AliveSuccessors.push_back(&SuccBB->front());4737return UsedAssumedInformation;4738}47394740unsigned MatchedCases = 0;4741for (const auto &CaseIt : SI.cases()) {4742if (Constants.count(CaseIt.getCaseValue())) {4743++MatchedCases;4744AliveSuccessors.push_back(&CaseIt.getCaseSuccessor()->front());4745}4746}47474748// If all potential values have been matched, we will not visit the default4749// case.4750if (MatchedCases < Constants.size())4751AliveSuccessors.push_back(&SI.getDefaultDest()->front());4752return UsedAssumedInformation;4753}47544755ChangeStatus AAIsDeadFunction::updateImpl(Attributor &A) {4756ChangeStatus Change = ChangeStatus::UNCHANGED;47574758if (AssumedLiveBlocks.empty()) {4759if (isAssumedDeadInternalFunction(A))4760return ChangeStatus::UNCHANGED;47614762Function *F = getAnchorScope();4763ToBeExploredFrom.insert(&F->getEntryBlock().front());4764assumeLive(A, F->getEntryBlock());4765Change = ChangeStatus::CHANGED;4766}47674768LLVM_DEBUG(dbgs() << "[AAIsDead] Live [" << AssumedLiveBlocks.size() << "/"4769<< getAnchorScope()->size() << "] BBs and "4770<< ToBeExploredFrom.size() << " exploration points and "4771<< KnownDeadEnds.size() << " known dead ends\n");47724773// Copy and clear the list of instructions we need to explore from. It is4774// refilled with instructions the next update has to look at.4775SmallVector<const Instruction *, 8> Worklist(ToBeExploredFrom.begin(),4776ToBeExploredFrom.end());4777decltype(ToBeExploredFrom) NewToBeExploredFrom;47784779SmallVector<const Instruction *, 8> AliveSuccessors;4780while (!Worklist.empty()) {4781const Instruction *I = Worklist.pop_back_val();4782LLVM_DEBUG(dbgs() << "[AAIsDead] Exploration inst: " << *I << "\n");47834784// Fast forward for uninteresting instructions. We could look for UB here4785// though.4786while (!I->isTerminator() && !isa<CallBase>(I))4787I = I->getNextNode();47884789AliveSuccessors.clear();47904791bool UsedAssumedInformation = false;4792switch (I->getOpcode()) {4793// TODO: look for (assumed) UB to backwards propagate "deadness".4794default:4795assert(I->isTerminator() &&4796"Expected non-terminators to be handled already!");4797for (const BasicBlock *SuccBB : successors(I->getParent()))4798AliveSuccessors.push_back(&SuccBB->front());4799break;4800case Instruction::Call:4801UsedAssumedInformation = identifyAliveSuccessors(A, cast<CallInst>(*I),4802*this, AliveSuccessors);4803break;4804case Instruction::Invoke:4805UsedAssumedInformation = identifyAliveSuccessors(A, cast<InvokeInst>(*I),4806*this, AliveSuccessors);4807break;4808case Instruction::Br:4809UsedAssumedInformation = identifyAliveSuccessors(A, cast<BranchInst>(*I),4810*this, AliveSuccessors);4811break;4812case Instruction::Switch:4813UsedAssumedInformation = identifyAliveSuccessors(A, cast<SwitchInst>(*I),4814*this, AliveSuccessors);4815break;4816}48174818if (UsedAssumedInformation) {4819NewToBeExploredFrom.insert(I);4820} else if (AliveSuccessors.empty() ||4821(I->isTerminator() &&4822AliveSuccessors.size() < I->getNumSuccessors())) {4823if (KnownDeadEnds.insert(I))4824Change = ChangeStatus::CHANGED;4825}48264827LLVM_DEBUG(dbgs() << "[AAIsDead] #AliveSuccessors: "4828<< AliveSuccessors.size() << " UsedAssumedInformation: "4829<< UsedAssumedInformation << "\n");48304831for (const Instruction *AliveSuccessor : AliveSuccessors) {4832if (!I->isTerminator()) {4833assert(AliveSuccessors.size() == 1 &&4834"Non-terminator expected to have a single successor!");4835Worklist.push_back(AliveSuccessor);4836} else {4837// record the assumed live edge4838auto Edge = std::make_pair(I->getParent(), AliveSuccessor->getParent());4839if (AssumedLiveEdges.insert(Edge).second)4840Change = ChangeStatus::CHANGED;4841if (assumeLive(A, *AliveSuccessor->getParent()))4842Worklist.push_back(AliveSuccessor);4843}4844}4845}48464847// Check if the content of ToBeExploredFrom changed, ignore the order.4848if (NewToBeExploredFrom.size() != ToBeExploredFrom.size() ||4849llvm::any_of(NewToBeExploredFrom, [&](const Instruction *I) {4850return !ToBeExploredFrom.count(I);4851})) {4852Change = ChangeStatus::CHANGED;4853ToBeExploredFrom = std::move(NewToBeExploredFrom);4854}48554856// If we know everything is live there is no need to query for liveness.4857// Instead, indicating a pessimistic fixpoint will cause the state to be4858// "invalid" and all queries to be answered conservatively without lookups.4859// To be in this state we have to (1) finished the exploration and (3) not4860// discovered any non-trivial dead end and (2) not ruled unreachable code4861// dead.4862if (ToBeExploredFrom.empty() &&4863getAnchorScope()->size() == AssumedLiveBlocks.size() &&4864llvm::all_of(KnownDeadEnds, [](const Instruction *DeadEndI) {4865return DeadEndI->isTerminator() && DeadEndI->getNumSuccessors() == 0;4866}))4867return indicatePessimisticFixpoint();4868return Change;4869}48704871/// Liveness information for a call sites.4872struct AAIsDeadCallSite final : AAIsDeadFunction {4873AAIsDeadCallSite(const IRPosition &IRP, Attributor &A)4874: AAIsDeadFunction(IRP, A) {}48754876/// See AbstractAttribute::initialize(...).4877void initialize(Attributor &A) override {4878// TODO: Once we have call site specific value information we can provide4879// call site specific liveness information and then it makes4880// sense to specialize attributes for call sites instead of4881// redirecting requests to the callee.4882llvm_unreachable("Abstract attributes for liveness are not "4883"supported for call sites yet!");4884}48854886/// See AbstractAttribute::updateImpl(...).4887ChangeStatus updateImpl(Attributor &A) override {4888return indicatePessimisticFixpoint();4889}48904891/// See AbstractAttribute::trackStatistics()4892void trackStatistics() const override {}4893};4894} // namespace48954896/// -------------------- Dereferenceable Argument Attribute --------------------48974898namespace {4899struct AADereferenceableImpl : AADereferenceable {4900AADereferenceableImpl(const IRPosition &IRP, Attributor &A)4901: AADereferenceable(IRP, A) {}4902using StateType = DerefState;49034904/// See AbstractAttribute::initialize(...).4905void initialize(Attributor &A) override {4906Value &V = *getAssociatedValue().stripPointerCasts();4907SmallVector<Attribute, 4> Attrs;4908A.getAttrs(getIRPosition(),4909{Attribute::Dereferenceable, Attribute::DereferenceableOrNull},4910Attrs, /* IgnoreSubsumingPositions */ false);4911for (const Attribute &Attr : Attrs)4912takeKnownDerefBytesMaximum(Attr.getValueAsInt());49134914// Ensure we initialize the non-null AA (if necessary).4915bool IsKnownNonNull;4916AA::hasAssumedIRAttr<Attribute::NonNull>(4917A, this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNonNull);49184919bool CanBeNull, CanBeFreed;4920takeKnownDerefBytesMaximum(V.getPointerDereferenceableBytes(4921A.getDataLayout(), CanBeNull, CanBeFreed));49224923if (Instruction *CtxI = getCtxI())4924followUsesInMBEC(*this, A, getState(), *CtxI);4925}49264927/// See AbstractAttribute::getState()4928/// {4929StateType &getState() override { return *this; }4930const StateType &getState() const override { return *this; }4931/// }49324933/// Helper function for collecting accessed bytes in must-be-executed-context4934void addAccessedBytesForUse(Attributor &A, const Use *U, const Instruction *I,4935DerefState &State) {4936const Value *UseV = U->get();4937if (!UseV->getType()->isPointerTy())4938return;49394940std::optional<MemoryLocation> Loc = MemoryLocation::getOrNone(I);4941if (!Loc || Loc->Ptr != UseV || !Loc->Size.isPrecise() || I->isVolatile())4942return;49434944int64_t Offset;4945const Value *Base = GetPointerBaseWithConstantOffset(4946Loc->Ptr, Offset, A.getDataLayout(), /*AllowNonInbounds*/ true);4947if (Base && Base == &getAssociatedValue())4948State.addAccessedBytes(Offset, Loc->Size.getValue());4949}49504951/// See followUsesInMBEC4952bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I,4953AADereferenceable::StateType &State) {4954bool IsNonNull = false;4955bool TrackUse = false;4956int64_t DerefBytes = getKnownNonNullAndDerefBytesForUse(4957A, *this, getAssociatedValue(), U, I, IsNonNull, TrackUse);4958LLVM_DEBUG(dbgs() << "[AADereferenceable] Deref bytes: " << DerefBytes4959<< " for instruction " << *I << "\n");49604961addAccessedBytesForUse(A, U, I, State);4962State.takeKnownDerefBytesMaximum(DerefBytes);4963return TrackUse;4964}49654966/// See AbstractAttribute::manifest(...).4967ChangeStatus manifest(Attributor &A) override {4968ChangeStatus Change = AADereferenceable::manifest(A);4969bool IsKnownNonNull;4970bool IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(4971A, this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);4972if (IsAssumedNonNull &&4973A.hasAttr(getIRPosition(), Attribute::DereferenceableOrNull)) {4974A.removeAttrs(getIRPosition(), {Attribute::DereferenceableOrNull});4975return ChangeStatus::CHANGED;4976}4977return Change;4978}49794980void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,4981SmallVectorImpl<Attribute> &Attrs) const override {4982// TODO: Add *_globally support4983bool IsKnownNonNull;4984bool IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(4985A, this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);4986if (IsAssumedNonNull)4987Attrs.emplace_back(Attribute::getWithDereferenceableBytes(4988Ctx, getAssumedDereferenceableBytes()));4989else4990Attrs.emplace_back(Attribute::getWithDereferenceableOrNullBytes(4991Ctx, getAssumedDereferenceableBytes()));4992}49934994/// See AbstractAttribute::getAsStr().4995const std::string getAsStr(Attributor *A) const override {4996if (!getAssumedDereferenceableBytes())4997return "unknown-dereferenceable";4998bool IsKnownNonNull;4999bool IsAssumedNonNull = false;5000if (A)5001IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(5002*A, this, getIRPosition(), DepClassTy::NONE, IsKnownNonNull);5003return std::string("dereferenceable") +5004(IsAssumedNonNull ? "" : "_or_null") +5005(isAssumedGlobal() ? "_globally" : "") + "<" +5006std::to_string(getKnownDereferenceableBytes()) + "-" +5007std::to_string(getAssumedDereferenceableBytes()) + ">" +5008(!A ? " [non-null is unknown]" : "");5009}5010};50115012/// Dereferenceable attribute for a floating value.5013struct AADereferenceableFloating : AADereferenceableImpl {5014AADereferenceableFloating(const IRPosition &IRP, Attributor &A)5015: AADereferenceableImpl(IRP, A) {}50165017/// See AbstractAttribute::updateImpl(...).5018ChangeStatus updateImpl(Attributor &A) override {5019bool Stripped;5020bool UsedAssumedInformation = false;5021SmallVector<AA::ValueAndContext> Values;5022if (!A.getAssumedSimplifiedValues(getIRPosition(), *this, Values,5023AA::AnyScope, UsedAssumedInformation)) {5024Values.push_back({getAssociatedValue(), getCtxI()});5025Stripped = false;5026} else {5027Stripped = Values.size() != 1 ||5028Values.front().getValue() != &getAssociatedValue();5029}50305031const DataLayout &DL = A.getDataLayout();5032DerefState T;50335034auto VisitValueCB = [&](const Value &V) -> bool {5035unsigned IdxWidth =5036DL.getIndexSizeInBits(V.getType()->getPointerAddressSpace());5037APInt Offset(IdxWidth, 0);5038const Value *Base = stripAndAccumulateOffsets(5039A, *this, &V, DL, Offset, /* GetMinOffset */ false,5040/* AllowNonInbounds */ true);50415042const auto *AA = A.getAAFor<AADereferenceable>(5043*this, IRPosition::value(*Base), DepClassTy::REQUIRED);5044int64_t DerefBytes = 0;5045if (!AA || (!Stripped && this == AA)) {5046// Use IR information if we did not strip anything.5047// TODO: track globally.5048bool CanBeNull, CanBeFreed;5049DerefBytes =5050Base->getPointerDereferenceableBytes(DL, CanBeNull, CanBeFreed);5051T.GlobalState.indicatePessimisticFixpoint();5052} else {5053const DerefState &DS = AA->getState();5054DerefBytes = DS.DerefBytesState.getAssumed();5055T.GlobalState &= DS.GlobalState;5056}50575058// For now we do not try to "increase" dereferenceability due to negative5059// indices as we first have to come up with code to deal with loops and5060// for overflows of the dereferenceable bytes.5061int64_t OffsetSExt = Offset.getSExtValue();5062if (OffsetSExt < 0)5063OffsetSExt = 0;50645065T.takeAssumedDerefBytesMinimum(5066std::max(int64_t(0), DerefBytes - OffsetSExt));50675068if (this == AA) {5069if (!Stripped) {5070// If nothing was stripped IR information is all we got.5071T.takeKnownDerefBytesMaximum(5072std::max(int64_t(0), DerefBytes - OffsetSExt));5073T.indicatePessimisticFixpoint();5074} else if (OffsetSExt > 0) {5075// If something was stripped but there is circular reasoning we look5076// for the offset. If it is positive we basically decrease the5077// dereferenceable bytes in a circular loop now, which will simply5078// drive them down to the known value in a very slow way which we5079// can accelerate.5080T.indicatePessimisticFixpoint();5081}5082}50835084return T.isValidState();5085};50865087for (const auto &VAC : Values)5088if (!VisitValueCB(*VAC.getValue()))5089return indicatePessimisticFixpoint();50905091return clampStateAndIndicateChange(getState(), T);5092}50935094/// See AbstractAttribute::trackStatistics()5095void trackStatistics() const override {5096STATS_DECLTRACK_FLOATING_ATTR(dereferenceable)5097}5098};50995100/// Dereferenceable attribute for a return value.5101struct AADereferenceableReturned final5102: AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl> {5103using Base =5104AAReturnedFromReturnedValues<AADereferenceable, AADereferenceableImpl>;5105AADereferenceableReturned(const IRPosition &IRP, Attributor &A)5106: Base(IRP, A) {}51075108/// See AbstractAttribute::trackStatistics()5109void trackStatistics() const override {5110STATS_DECLTRACK_FNRET_ATTR(dereferenceable)5111}5112};51135114/// Dereferenceable attribute for an argument5115struct AADereferenceableArgument final5116: AAArgumentFromCallSiteArguments<AADereferenceable,5117AADereferenceableImpl> {5118using Base =5119AAArgumentFromCallSiteArguments<AADereferenceable, AADereferenceableImpl>;5120AADereferenceableArgument(const IRPosition &IRP, Attributor &A)5121: Base(IRP, A) {}51225123/// See AbstractAttribute::trackStatistics()5124void trackStatistics() const override {5125STATS_DECLTRACK_ARG_ATTR(dereferenceable)5126}5127};51285129/// Dereferenceable attribute for a call site argument.5130struct AADereferenceableCallSiteArgument final : AADereferenceableFloating {5131AADereferenceableCallSiteArgument(const IRPosition &IRP, Attributor &A)5132: AADereferenceableFloating(IRP, A) {}51335134/// See AbstractAttribute::trackStatistics()5135void trackStatistics() const override {5136STATS_DECLTRACK_CSARG_ATTR(dereferenceable)5137}5138};51395140/// Dereferenceable attribute deduction for a call site return value.5141struct AADereferenceableCallSiteReturned final5142: AACalleeToCallSite<AADereferenceable, AADereferenceableImpl> {5143using Base = AACalleeToCallSite<AADereferenceable, AADereferenceableImpl>;5144AADereferenceableCallSiteReturned(const IRPosition &IRP, Attributor &A)5145: Base(IRP, A) {}51465147/// See AbstractAttribute::trackStatistics()5148void trackStatistics() const override {5149STATS_DECLTRACK_CS_ATTR(dereferenceable);5150}5151};5152} // namespace51535154// ------------------------ Align Argument Attribute ------------------------51555156namespace {5157static unsigned getKnownAlignForUse(Attributor &A, AAAlign &QueryingAA,5158Value &AssociatedValue, const Use *U,5159const Instruction *I, bool &TrackUse) {5160// We need to follow common pointer manipulation uses to the accesses they5161// feed into.5162if (isa<CastInst>(I)) {5163// Follow all but ptr2int casts.5164TrackUse = !isa<PtrToIntInst>(I);5165return 0;5166}5167if (auto *GEP = dyn_cast<GetElementPtrInst>(I)) {5168if (GEP->hasAllConstantIndices())5169TrackUse = true;5170return 0;5171}51725173MaybeAlign MA;5174if (const auto *CB = dyn_cast<CallBase>(I)) {5175if (CB->isBundleOperand(U) || CB->isCallee(U))5176return 0;51775178unsigned ArgNo = CB->getArgOperandNo(U);5179IRPosition IRP = IRPosition::callsite_argument(*CB, ArgNo);5180// As long as we only use known information there is no need to track5181// dependences here.5182auto *AlignAA = A.getAAFor<AAAlign>(QueryingAA, IRP, DepClassTy::NONE);5183if (AlignAA)5184MA = MaybeAlign(AlignAA->getKnownAlign());5185}51865187const DataLayout &DL = A.getDataLayout();5188const Value *UseV = U->get();5189if (auto *SI = dyn_cast<StoreInst>(I)) {5190if (SI->getPointerOperand() == UseV)5191MA = SI->getAlign();5192} else if (auto *LI = dyn_cast<LoadInst>(I)) {5193if (LI->getPointerOperand() == UseV)5194MA = LI->getAlign();5195} else if (auto *AI = dyn_cast<AtomicRMWInst>(I)) {5196if (AI->getPointerOperand() == UseV)5197MA = AI->getAlign();5198} else if (auto *AI = dyn_cast<AtomicCmpXchgInst>(I)) {5199if (AI->getPointerOperand() == UseV)5200MA = AI->getAlign();5201}52025203if (!MA || *MA <= QueryingAA.getKnownAlign())5204return 0;52055206unsigned Alignment = MA->value();5207int64_t Offset;52085209if (const Value *Base = GetPointerBaseWithConstantOffset(UseV, Offset, DL)) {5210if (Base == &AssociatedValue) {5211// BasePointerAddr + Offset = Alignment * Q for some integer Q.5212// So we can say that the maximum power of two which is a divisor of5213// gcd(Offset, Alignment) is an alignment.52145215uint32_t gcd = std::gcd(uint32_t(abs((int32_t)Offset)), Alignment);5216Alignment = llvm::bit_floor(gcd);5217}5218}52195220return Alignment;5221}52225223struct AAAlignImpl : AAAlign {5224AAAlignImpl(const IRPosition &IRP, Attributor &A) : AAAlign(IRP, A) {}52255226/// See AbstractAttribute::initialize(...).5227void initialize(Attributor &A) override {5228SmallVector<Attribute, 4> Attrs;5229A.getAttrs(getIRPosition(), {Attribute::Alignment}, Attrs);5230for (const Attribute &Attr : Attrs)5231takeKnownMaximum(Attr.getValueAsInt());52325233Value &V = *getAssociatedValue().stripPointerCasts();5234takeKnownMaximum(V.getPointerAlignment(A.getDataLayout()).value());52355236if (Instruction *CtxI = getCtxI())5237followUsesInMBEC(*this, A, getState(), *CtxI);5238}52395240/// See AbstractAttribute::manifest(...).5241ChangeStatus manifest(Attributor &A) override {5242ChangeStatus LoadStoreChanged = ChangeStatus::UNCHANGED;52435244// Check for users that allow alignment annotations.5245Value &AssociatedValue = getAssociatedValue();5246for (const Use &U : AssociatedValue.uses()) {5247if (auto *SI = dyn_cast<StoreInst>(U.getUser())) {5248if (SI->getPointerOperand() == &AssociatedValue)5249if (SI->getAlign() < getAssumedAlign()) {5250STATS_DECLTRACK(AAAlign, Store,5251"Number of times alignment added to a store");5252SI->setAlignment(getAssumedAlign());5253LoadStoreChanged = ChangeStatus::CHANGED;5254}5255} else if (auto *LI = dyn_cast<LoadInst>(U.getUser())) {5256if (LI->getPointerOperand() == &AssociatedValue)5257if (LI->getAlign() < getAssumedAlign()) {5258LI->setAlignment(getAssumedAlign());5259STATS_DECLTRACK(AAAlign, Load,5260"Number of times alignment added to a load");5261LoadStoreChanged = ChangeStatus::CHANGED;5262}5263}5264}52655266ChangeStatus Changed = AAAlign::manifest(A);52675268Align InheritAlign =5269getAssociatedValue().getPointerAlignment(A.getDataLayout());5270if (InheritAlign >= getAssumedAlign())5271return LoadStoreChanged;5272return Changed | LoadStoreChanged;5273}52745275// TODO: Provide a helper to determine the implied ABI alignment and check in5276// the existing manifest method and a new one for AAAlignImpl that value5277// to avoid making the alignment explicit if it did not improve.52785279/// See AbstractAttribute::getDeducedAttributes5280void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,5281SmallVectorImpl<Attribute> &Attrs) const override {5282if (getAssumedAlign() > 1)5283Attrs.emplace_back(5284Attribute::getWithAlignment(Ctx, Align(getAssumedAlign())));5285}52865287/// See followUsesInMBEC5288bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I,5289AAAlign::StateType &State) {5290bool TrackUse = false;52915292unsigned int KnownAlign =5293getKnownAlignForUse(A, *this, getAssociatedValue(), U, I, TrackUse);5294State.takeKnownMaximum(KnownAlign);52955296return TrackUse;5297}52985299/// See AbstractAttribute::getAsStr().5300const std::string getAsStr(Attributor *A) const override {5301return "align<" + std::to_string(getKnownAlign().value()) + "-" +5302std::to_string(getAssumedAlign().value()) + ">";5303}5304};53055306/// Align attribute for a floating value.5307struct AAAlignFloating : AAAlignImpl {5308AAAlignFloating(const IRPosition &IRP, Attributor &A) : AAAlignImpl(IRP, A) {}53095310/// See AbstractAttribute::updateImpl(...).5311ChangeStatus updateImpl(Attributor &A) override {5312const DataLayout &DL = A.getDataLayout();53135314bool Stripped;5315bool UsedAssumedInformation = false;5316SmallVector<AA::ValueAndContext> Values;5317if (!A.getAssumedSimplifiedValues(getIRPosition(), *this, Values,5318AA::AnyScope, UsedAssumedInformation)) {5319Values.push_back({getAssociatedValue(), getCtxI()});5320Stripped = false;5321} else {5322Stripped = Values.size() != 1 ||5323Values.front().getValue() != &getAssociatedValue();5324}53255326StateType T;5327auto VisitValueCB = [&](Value &V) -> bool {5328if (isa<UndefValue>(V) || isa<ConstantPointerNull>(V))5329return true;5330const auto *AA = A.getAAFor<AAAlign>(*this, IRPosition::value(V),5331DepClassTy::REQUIRED);5332if (!AA || (!Stripped && this == AA)) {5333int64_t Offset;5334unsigned Alignment = 1;5335if (const Value *Base =5336GetPointerBaseWithConstantOffset(&V, Offset, DL)) {5337// TODO: Use AAAlign for the base too.5338Align PA = Base->getPointerAlignment(DL);5339// BasePointerAddr + Offset = Alignment * Q for some integer Q.5340// So we can say that the maximum power of two which is a divisor of5341// gcd(Offset, Alignment) is an alignment.53425343uint32_t gcd =5344std::gcd(uint32_t(abs((int32_t)Offset)), uint32_t(PA.value()));5345Alignment = llvm::bit_floor(gcd);5346} else {5347Alignment = V.getPointerAlignment(DL).value();5348}5349// Use only IR information if we did not strip anything.5350T.takeKnownMaximum(Alignment);5351T.indicatePessimisticFixpoint();5352} else {5353// Use abstract attribute information.5354const AAAlign::StateType &DS = AA->getState();5355T ^= DS;5356}5357return T.isValidState();5358};53595360for (const auto &VAC : Values) {5361if (!VisitValueCB(*VAC.getValue()))5362return indicatePessimisticFixpoint();5363}53645365// TODO: If we know we visited all incoming values, thus no are assumed5366// dead, we can take the known information from the state T.5367return clampStateAndIndicateChange(getState(), T);5368}53695370/// See AbstractAttribute::trackStatistics()5371void trackStatistics() const override { STATS_DECLTRACK_FLOATING_ATTR(align) }5372};53735374/// Align attribute for function return value.5375struct AAAlignReturned final5376: AAReturnedFromReturnedValues<AAAlign, AAAlignImpl> {5377using Base = AAReturnedFromReturnedValues<AAAlign, AAAlignImpl>;5378AAAlignReturned(const IRPosition &IRP, Attributor &A) : Base(IRP, A) {}53795380/// See AbstractAttribute::trackStatistics()5381void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(aligned) }5382};53835384/// Align attribute for function argument.5385struct AAAlignArgument final5386: AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl> {5387using Base = AAArgumentFromCallSiteArguments<AAAlign, AAAlignImpl>;5388AAAlignArgument(const IRPosition &IRP, Attributor &A) : Base(IRP, A) {}53895390/// See AbstractAttribute::manifest(...).5391ChangeStatus manifest(Attributor &A) override {5392// If the associated argument is involved in a must-tail call we give up5393// because we would need to keep the argument alignments of caller and5394// callee in-sync. Just does not seem worth the trouble right now.5395if (A.getInfoCache().isInvolvedInMustTailCall(*getAssociatedArgument()))5396return ChangeStatus::UNCHANGED;5397return Base::manifest(A);5398}53995400/// See AbstractAttribute::trackStatistics()5401void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(aligned) }5402};54035404struct AAAlignCallSiteArgument final : AAAlignFloating {5405AAAlignCallSiteArgument(const IRPosition &IRP, Attributor &A)5406: AAAlignFloating(IRP, A) {}54075408/// See AbstractAttribute::manifest(...).5409ChangeStatus manifest(Attributor &A) override {5410// If the associated argument is involved in a must-tail call we give up5411// because we would need to keep the argument alignments of caller and5412// callee in-sync. Just does not seem worth the trouble right now.5413if (Argument *Arg = getAssociatedArgument())5414if (A.getInfoCache().isInvolvedInMustTailCall(*Arg))5415return ChangeStatus::UNCHANGED;5416ChangeStatus Changed = AAAlignImpl::manifest(A);5417Align InheritAlign =5418getAssociatedValue().getPointerAlignment(A.getDataLayout());5419if (InheritAlign >= getAssumedAlign())5420Changed = ChangeStatus::UNCHANGED;5421return Changed;5422}54235424/// See AbstractAttribute::updateImpl(Attributor &A).5425ChangeStatus updateImpl(Attributor &A) override {5426ChangeStatus Changed = AAAlignFloating::updateImpl(A);5427if (Argument *Arg = getAssociatedArgument()) {5428// We only take known information from the argument5429// so we do not need to track a dependence.5430const auto *ArgAlignAA = A.getAAFor<AAAlign>(5431*this, IRPosition::argument(*Arg), DepClassTy::NONE);5432if (ArgAlignAA)5433takeKnownMaximum(ArgAlignAA->getKnownAlign().value());5434}5435return Changed;5436}54375438/// See AbstractAttribute::trackStatistics()5439void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(aligned) }5440};54415442/// Align attribute deduction for a call site return value.5443struct AAAlignCallSiteReturned final5444: AACalleeToCallSite<AAAlign, AAAlignImpl> {5445using Base = AACalleeToCallSite<AAAlign, AAAlignImpl>;5446AAAlignCallSiteReturned(const IRPosition &IRP, Attributor &A)5447: Base(IRP, A) {}54485449/// See AbstractAttribute::trackStatistics()5450void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(align); }5451};5452} // namespace54535454/// ------------------ Function No-Return Attribute ----------------------------5455namespace {5456struct AANoReturnImpl : public AANoReturn {5457AANoReturnImpl(const IRPosition &IRP, Attributor &A) : AANoReturn(IRP, A) {}54585459/// See AbstractAttribute::initialize(...).5460void initialize(Attributor &A) override {5461bool IsKnown;5462assert(!AA::hasAssumedIRAttr<Attribute::NoReturn>(5463A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));5464(void)IsKnown;5465}54665467/// See AbstractAttribute::getAsStr().5468const std::string getAsStr(Attributor *A) const override {5469return getAssumed() ? "noreturn" : "may-return";5470}54715472/// See AbstractAttribute::updateImpl(Attributor &A).5473ChangeStatus updateImpl(Attributor &A) override {5474auto CheckForNoReturn = [](Instruction &) { return false; };5475bool UsedAssumedInformation = false;5476if (!A.checkForAllInstructions(CheckForNoReturn, *this,5477{(unsigned)Instruction::Ret},5478UsedAssumedInformation))5479return indicatePessimisticFixpoint();5480return ChangeStatus::UNCHANGED;5481}5482};54835484struct AANoReturnFunction final : AANoReturnImpl {5485AANoReturnFunction(const IRPosition &IRP, Attributor &A)5486: AANoReturnImpl(IRP, A) {}54875488/// See AbstractAttribute::trackStatistics()5489void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(noreturn) }5490};54915492/// NoReturn attribute deduction for a call sites.5493struct AANoReturnCallSite final5494: AACalleeToCallSite<AANoReturn, AANoReturnImpl> {5495AANoReturnCallSite(const IRPosition &IRP, Attributor &A)5496: AACalleeToCallSite<AANoReturn, AANoReturnImpl>(IRP, A) {}54975498/// See AbstractAttribute::trackStatistics()5499void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(noreturn); }5500};5501} // namespace55025503/// ----------------------- Instance Info ---------------------------------55045505namespace {5506/// A class to hold the state of for no-capture attributes.5507struct AAInstanceInfoImpl : public AAInstanceInfo {5508AAInstanceInfoImpl(const IRPosition &IRP, Attributor &A)5509: AAInstanceInfo(IRP, A) {}55105511/// See AbstractAttribute::initialize(...).5512void initialize(Attributor &A) override {5513Value &V = getAssociatedValue();5514if (auto *C = dyn_cast<Constant>(&V)) {5515if (C->isThreadDependent())5516indicatePessimisticFixpoint();5517else5518indicateOptimisticFixpoint();5519return;5520}5521if (auto *CB = dyn_cast<CallBase>(&V))5522if (CB->arg_size() == 0 && !CB->mayHaveSideEffects() &&5523!CB->mayReadFromMemory()) {5524indicateOptimisticFixpoint();5525return;5526}5527if (auto *I = dyn_cast<Instruction>(&V)) {5528const auto *CI =5529A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(5530*I->getFunction());5531if (mayBeInCycle(CI, I, /* HeaderOnly */ false)) {5532indicatePessimisticFixpoint();5533return;5534}5535}5536}55375538/// See AbstractAttribute::updateImpl(...).5539ChangeStatus updateImpl(Attributor &A) override {5540ChangeStatus Changed = ChangeStatus::UNCHANGED;55415542Value &V = getAssociatedValue();5543const Function *Scope = nullptr;5544if (auto *I = dyn_cast<Instruction>(&V))5545Scope = I->getFunction();5546if (auto *A = dyn_cast<Argument>(&V)) {5547Scope = A->getParent();5548if (!Scope->hasLocalLinkage())5549return Changed;5550}5551if (!Scope)5552return indicateOptimisticFixpoint();55535554bool IsKnownNoRecurse;5555if (AA::hasAssumedIRAttr<Attribute::NoRecurse>(5556A, this, IRPosition::function(*Scope), DepClassTy::OPTIONAL,5557IsKnownNoRecurse))5558return Changed;55595560auto UsePred = [&](const Use &U, bool &Follow) {5561const Instruction *UserI = dyn_cast<Instruction>(U.getUser());5562if (!UserI || isa<GetElementPtrInst>(UserI) || isa<CastInst>(UserI) ||5563isa<PHINode>(UserI) || isa<SelectInst>(UserI)) {5564Follow = true;5565return true;5566}5567if (isa<LoadInst>(UserI) || isa<CmpInst>(UserI) ||5568(isa<StoreInst>(UserI) &&5569cast<StoreInst>(UserI)->getValueOperand() != U.get()))5570return true;5571if (auto *CB = dyn_cast<CallBase>(UserI)) {5572// This check is not guaranteeing uniqueness but for now that we cannot5573// end up with two versions of \p U thinking it was one.5574auto *Callee = dyn_cast_if_present<Function>(CB->getCalledOperand());5575if (!Callee || !Callee->hasLocalLinkage())5576return true;5577if (!CB->isArgOperand(&U))5578return false;5579const auto *ArgInstanceInfoAA = A.getAAFor<AAInstanceInfo>(5580*this, IRPosition::callsite_argument(*CB, CB->getArgOperandNo(&U)),5581DepClassTy::OPTIONAL);5582if (!ArgInstanceInfoAA ||5583!ArgInstanceInfoAA->isAssumedUniqueForAnalysis())5584return false;5585// If this call base might reach the scope again we might forward the5586// argument back here. This is very conservative.5587if (AA::isPotentiallyReachable(5588A, *CB, *Scope, *this, /* ExclusionSet */ nullptr,5589[Scope](const Function &Fn) { return &Fn != Scope; }))5590return false;5591return true;5592}5593return false;5594};55955596auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) {5597if (auto *SI = dyn_cast<StoreInst>(OldU.getUser())) {5598auto *Ptr = SI->getPointerOperand()->stripPointerCasts();5599if ((isa<AllocaInst>(Ptr) || isNoAliasCall(Ptr)) &&5600AA::isDynamicallyUnique(A, *this, *Ptr))5601return true;5602}5603return false;5604};56055606if (!A.checkForAllUses(UsePred, *this, V, /* CheckBBLivenessOnly */ true,5607DepClassTy::OPTIONAL,5608/* IgnoreDroppableUses */ true, EquivalentUseCB))5609return indicatePessimisticFixpoint();56105611return Changed;5612}56135614/// See AbstractState::getAsStr().5615const std::string getAsStr(Attributor *A) const override {5616return isAssumedUniqueForAnalysis() ? "<unique [fAa]>" : "<unknown>";5617}56185619/// See AbstractAttribute::trackStatistics()5620void trackStatistics() const override {}5621};56225623/// InstanceInfo attribute for floating values.5624struct AAInstanceInfoFloating : AAInstanceInfoImpl {5625AAInstanceInfoFloating(const IRPosition &IRP, Attributor &A)5626: AAInstanceInfoImpl(IRP, A) {}5627};56285629/// NoCapture attribute for function arguments.5630struct AAInstanceInfoArgument final : AAInstanceInfoFloating {5631AAInstanceInfoArgument(const IRPosition &IRP, Attributor &A)5632: AAInstanceInfoFloating(IRP, A) {}5633};56345635/// InstanceInfo attribute for call site arguments.5636struct AAInstanceInfoCallSiteArgument final : AAInstanceInfoImpl {5637AAInstanceInfoCallSiteArgument(const IRPosition &IRP, Attributor &A)5638: AAInstanceInfoImpl(IRP, A) {}56395640/// See AbstractAttribute::updateImpl(...).5641ChangeStatus updateImpl(Attributor &A) override {5642// TODO: Once we have call site specific value information we can provide5643// call site specific liveness information and then it makes5644// sense to specialize attributes for call sites arguments instead of5645// redirecting requests to the callee argument.5646Argument *Arg = getAssociatedArgument();5647if (!Arg)5648return indicatePessimisticFixpoint();5649const IRPosition &ArgPos = IRPosition::argument(*Arg);5650auto *ArgAA =5651A.getAAFor<AAInstanceInfo>(*this, ArgPos, DepClassTy::REQUIRED);5652if (!ArgAA)5653return indicatePessimisticFixpoint();5654return clampStateAndIndicateChange(getState(), ArgAA->getState());5655}5656};56575658/// InstanceInfo attribute for function return value.5659struct AAInstanceInfoReturned final : AAInstanceInfoImpl {5660AAInstanceInfoReturned(const IRPosition &IRP, Attributor &A)5661: AAInstanceInfoImpl(IRP, A) {5662llvm_unreachable("InstanceInfo is not applicable to function returns!");5663}56645665/// See AbstractAttribute::initialize(...).5666void initialize(Attributor &A) override {5667llvm_unreachable("InstanceInfo is not applicable to function returns!");5668}56695670/// See AbstractAttribute::updateImpl(...).5671ChangeStatus updateImpl(Attributor &A) override {5672llvm_unreachable("InstanceInfo is not applicable to function returns!");5673}5674};56755676/// InstanceInfo attribute deduction for a call site return value.5677struct AAInstanceInfoCallSiteReturned final : AAInstanceInfoFloating {5678AAInstanceInfoCallSiteReturned(const IRPosition &IRP, Attributor &A)5679: AAInstanceInfoFloating(IRP, A) {}5680};5681} // namespace56825683/// ----------------------- Variable Capturing ---------------------------------5684bool AANoCapture::isImpliedByIR(Attributor &A, const IRPosition &IRP,5685Attribute::AttrKind ImpliedAttributeKind,5686bool IgnoreSubsumingPositions) {5687assert(ImpliedAttributeKind == Attribute::NoCapture &&5688"Unexpected attribute kind");5689Value &V = IRP.getAssociatedValue();5690if (!IRP.isArgumentPosition())5691return V.use_empty();56925693// You cannot "capture" null in the default address space.5694//5695// FIXME: This should use NullPointerIsDefined to account for the function5696// attribute.5697if (isa<UndefValue>(V) || (isa<ConstantPointerNull>(V) &&5698V.getType()->getPointerAddressSpace() == 0)) {5699return true;5700}57015702if (A.hasAttr(IRP, {Attribute::NoCapture},5703/* IgnoreSubsumingPositions */ true, Attribute::NoCapture))5704return true;57055706if (IRP.getPositionKind() == IRP_CALL_SITE_ARGUMENT)5707if (Argument *Arg = IRP.getAssociatedArgument())5708if (A.hasAttr(IRPosition::argument(*Arg),5709{Attribute::NoCapture, Attribute::ByVal},5710/* IgnoreSubsumingPositions */ true)) {5711A.manifestAttrs(IRP,5712Attribute::get(V.getContext(), Attribute::NoCapture));5713return true;5714}57155716if (const Function *F = IRP.getAssociatedFunction()) {5717// Check what state the associated function can actually capture.5718AANoCapture::StateType State;5719determineFunctionCaptureCapabilities(IRP, *F, State);5720if (State.isKnown(NO_CAPTURE)) {5721A.manifestAttrs(IRP,5722Attribute::get(V.getContext(), Attribute::NoCapture));5723return true;5724}5725}57265727return false;5728}57295730/// Set the NOT_CAPTURED_IN_MEM and NOT_CAPTURED_IN_RET bits in \p Known5731/// depending on the ability of the function associated with \p IRP to capture5732/// state in memory and through "returning/throwing", respectively.5733void AANoCapture::determineFunctionCaptureCapabilities(const IRPosition &IRP,5734const Function &F,5735BitIntegerState &State) {5736// TODO: Once we have memory behavior attributes we should use them here.57375738// If we know we cannot communicate or write to memory, we do not care about5739// ptr2int anymore.5740bool ReadOnly = F.onlyReadsMemory();5741bool NoThrow = F.doesNotThrow();5742bool IsVoidReturn = F.getReturnType()->isVoidTy();5743if (ReadOnly && NoThrow && IsVoidReturn) {5744State.addKnownBits(NO_CAPTURE);5745return;5746}57475748// A function cannot capture state in memory if it only reads memory, it can5749// however return/throw state and the state might be influenced by the5750// pointer value, e.g., loading from a returned pointer might reveal a bit.5751if (ReadOnly)5752State.addKnownBits(NOT_CAPTURED_IN_MEM);57535754// A function cannot communicate state back if it does not through5755// exceptions and doesn not return values.5756if (NoThrow && IsVoidReturn)5757State.addKnownBits(NOT_CAPTURED_IN_RET);57585759// Check existing "returned" attributes.5760int ArgNo = IRP.getCalleeArgNo();5761if (!NoThrow || ArgNo < 0 ||5762!F.getAttributes().hasAttrSomewhere(Attribute::Returned))5763return;57645765for (unsigned U = 0, E = F.arg_size(); U < E; ++U)5766if (F.hasParamAttribute(U, Attribute::Returned)) {5767if (U == unsigned(ArgNo))5768State.removeAssumedBits(NOT_CAPTURED_IN_RET);5769else if (ReadOnly)5770State.addKnownBits(NO_CAPTURE);5771else5772State.addKnownBits(NOT_CAPTURED_IN_RET);5773break;5774}5775}57765777namespace {5778/// A class to hold the state of for no-capture attributes.5779struct AANoCaptureImpl : public AANoCapture {5780AANoCaptureImpl(const IRPosition &IRP, Attributor &A) : AANoCapture(IRP, A) {}57815782/// See AbstractAttribute::initialize(...).5783void initialize(Attributor &A) override {5784bool IsKnown;5785assert(!AA::hasAssumedIRAttr<Attribute::NoCapture>(5786A, nullptr, getIRPosition(), DepClassTy::NONE, IsKnown));5787(void)IsKnown;5788}57895790/// See AbstractAttribute::updateImpl(...).5791ChangeStatus updateImpl(Attributor &A) override;57925793/// see AbstractAttribute::isAssumedNoCaptureMaybeReturned(...).5794void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,5795SmallVectorImpl<Attribute> &Attrs) const override {5796if (!isAssumedNoCaptureMaybeReturned())5797return;57985799if (isArgumentPosition()) {5800if (isAssumedNoCapture())5801Attrs.emplace_back(Attribute::get(Ctx, Attribute::NoCapture));5802else if (ManifestInternal)5803Attrs.emplace_back(Attribute::get(Ctx, "no-capture-maybe-returned"));5804}5805}58065807/// See AbstractState::getAsStr().5808const std::string getAsStr(Attributor *A) const override {5809if (isKnownNoCapture())5810return "known not-captured";5811if (isAssumedNoCapture())5812return "assumed not-captured";5813if (isKnownNoCaptureMaybeReturned())5814return "known not-captured-maybe-returned";5815if (isAssumedNoCaptureMaybeReturned())5816return "assumed not-captured-maybe-returned";5817return "assumed-captured";5818}58195820/// Check the use \p U and update \p State accordingly. Return true if we5821/// should continue to update the state.5822bool checkUse(Attributor &A, AANoCapture::StateType &State, const Use &U,5823bool &Follow) {5824Instruction *UInst = cast<Instruction>(U.getUser());5825LLVM_DEBUG(dbgs() << "[AANoCapture] Check use: " << *U.get() << " in "5826<< *UInst << "\n");58275828// Deal with ptr2int by following uses.5829if (isa<PtrToIntInst>(UInst)) {5830LLVM_DEBUG(dbgs() << " - ptr2int assume the worst!\n");5831return isCapturedIn(State, /* Memory */ true, /* Integer */ true,5832/* Return */ true);5833}58345835// For stores we already checked if we can follow them, if they make it5836// here we give up.5837if (isa<StoreInst>(UInst))5838return isCapturedIn(State, /* Memory */ true, /* Integer */ true,5839/* Return */ true);58405841// Explicitly catch return instructions.5842if (isa<ReturnInst>(UInst)) {5843if (UInst->getFunction() == getAnchorScope())5844return isCapturedIn(State, /* Memory */ false, /* Integer */ false,5845/* Return */ true);5846return isCapturedIn(State, /* Memory */ true, /* Integer */ true,5847/* Return */ true);5848}58495850// For now we only use special logic for call sites. However, the tracker5851// itself knows about a lot of other non-capturing cases already.5852auto *CB = dyn_cast<CallBase>(UInst);5853if (!CB || !CB->isArgOperand(&U))5854return isCapturedIn(State, /* Memory */ true, /* Integer */ true,5855/* Return */ true);58565857unsigned ArgNo = CB->getArgOperandNo(&U);5858const IRPosition &CSArgPos = IRPosition::callsite_argument(*CB, ArgNo);5859// If we have a abstract no-capture attribute for the argument we can use5860// it to justify a non-capture attribute here. This allows recursion!5861bool IsKnownNoCapture;5862const AANoCapture *ArgNoCaptureAA = nullptr;5863bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(5864A, this, CSArgPos, DepClassTy::REQUIRED, IsKnownNoCapture, false,5865&ArgNoCaptureAA);5866if (IsAssumedNoCapture)5867return isCapturedIn(State, /* Memory */ false, /* Integer */ false,5868/* Return */ false);5869if (ArgNoCaptureAA && ArgNoCaptureAA->isAssumedNoCaptureMaybeReturned()) {5870Follow = true;5871return isCapturedIn(State, /* Memory */ false, /* Integer */ false,5872/* Return */ false);5873}58745875// Lastly, we could not find a reason no-capture can be assumed so we don't.5876return isCapturedIn(State, /* Memory */ true, /* Integer */ true,5877/* Return */ true);5878}58795880/// Update \p State according to \p CapturedInMem, \p CapturedInInt, and5881/// \p CapturedInRet, then return true if we should continue updating the5882/// state.5883static bool isCapturedIn(AANoCapture::StateType &State, bool CapturedInMem,5884bool CapturedInInt, bool CapturedInRet) {5885LLVM_DEBUG(dbgs() << " - captures [Mem " << CapturedInMem << "|Int "5886<< CapturedInInt << "|Ret " << CapturedInRet << "]\n");5887if (CapturedInMem)5888State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_MEM);5889if (CapturedInInt)5890State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_INT);5891if (CapturedInRet)5892State.removeAssumedBits(AANoCapture::NOT_CAPTURED_IN_RET);5893return State.isAssumed(AANoCapture::NO_CAPTURE_MAYBE_RETURNED);5894}5895};58965897ChangeStatus AANoCaptureImpl::updateImpl(Attributor &A) {5898const IRPosition &IRP = getIRPosition();5899Value *V = isArgumentPosition() ? IRP.getAssociatedArgument()5900: &IRP.getAssociatedValue();5901if (!V)5902return indicatePessimisticFixpoint();59035904const Function *F =5905isArgumentPosition() ? IRP.getAssociatedFunction() : IRP.getAnchorScope();59065907// TODO: Is the checkForAllUses below useful for constants?5908if (!F)5909return indicatePessimisticFixpoint();59105911AANoCapture::StateType T;5912const IRPosition &FnPos = IRPosition::function(*F);59135914// Readonly means we cannot capture through memory.5915bool IsKnown;5916if (AA::isAssumedReadOnly(A, FnPos, *this, IsKnown)) {5917T.addKnownBits(NOT_CAPTURED_IN_MEM);5918if (IsKnown)5919addKnownBits(NOT_CAPTURED_IN_MEM);5920}59215922// Make sure all returned values are different than the underlying value.5923// TODO: we could do this in a more sophisticated way inside5924// AAReturnedValues, e.g., track all values that escape through returns5925// directly somehow.5926auto CheckReturnedArgs = [&](bool &UsedAssumedInformation) {5927SmallVector<AA::ValueAndContext> Values;5928if (!A.getAssumedSimplifiedValues(IRPosition::returned(*F), this, Values,5929AA::ValueScope::Intraprocedural,5930UsedAssumedInformation))5931return false;5932bool SeenConstant = false;5933for (const AA::ValueAndContext &VAC : Values) {5934if (isa<Constant>(VAC.getValue())) {5935if (SeenConstant)5936return false;5937SeenConstant = true;5938} else if (!isa<Argument>(VAC.getValue()) ||5939VAC.getValue() == getAssociatedArgument())5940return false;5941}5942return true;5943};59445945bool IsKnownNoUnwind;5946if (AA::hasAssumedIRAttr<Attribute::NoUnwind>(5947A, this, FnPos, DepClassTy::OPTIONAL, IsKnownNoUnwind)) {5948bool IsVoidTy = F->getReturnType()->isVoidTy();5949bool UsedAssumedInformation = false;5950if (IsVoidTy || CheckReturnedArgs(UsedAssumedInformation)) {5951T.addKnownBits(NOT_CAPTURED_IN_RET);5952if (T.isKnown(NOT_CAPTURED_IN_MEM))5953return ChangeStatus::UNCHANGED;5954if (IsKnownNoUnwind && (IsVoidTy || !UsedAssumedInformation)) {5955addKnownBits(NOT_CAPTURED_IN_RET);5956if (isKnown(NOT_CAPTURED_IN_MEM))5957return indicateOptimisticFixpoint();5958}5959}5960}59615962auto IsDereferenceableOrNull = [&](Value *O, const DataLayout &DL) {5963const auto *DerefAA = A.getAAFor<AADereferenceable>(5964*this, IRPosition::value(*O), DepClassTy::OPTIONAL);5965return DerefAA && DerefAA->getAssumedDereferenceableBytes();5966};59675968auto UseCheck = [&](const Use &U, bool &Follow) -> bool {5969switch (DetermineUseCaptureKind(U, IsDereferenceableOrNull)) {5970case UseCaptureKind::NO_CAPTURE:5971return true;5972case UseCaptureKind::MAY_CAPTURE:5973return checkUse(A, T, U, Follow);5974case UseCaptureKind::PASSTHROUGH:5975Follow = true;5976return true;5977}5978llvm_unreachable("Unexpected use capture kind!");5979};59805981if (!A.checkForAllUses(UseCheck, *this, *V))5982return indicatePessimisticFixpoint();59835984AANoCapture::StateType &S = getState();5985auto Assumed = S.getAssumed();5986S.intersectAssumedBits(T.getAssumed());5987if (!isAssumedNoCaptureMaybeReturned())5988return indicatePessimisticFixpoint();5989return Assumed == S.getAssumed() ? ChangeStatus::UNCHANGED5990: ChangeStatus::CHANGED;5991}59925993/// NoCapture attribute for function arguments.5994struct AANoCaptureArgument final : AANoCaptureImpl {5995AANoCaptureArgument(const IRPosition &IRP, Attributor &A)5996: AANoCaptureImpl(IRP, A) {}59975998/// See AbstractAttribute::trackStatistics()5999void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nocapture) }6000};60016002/// NoCapture attribute for call site arguments.6003struct AANoCaptureCallSiteArgument final : AANoCaptureImpl {6004AANoCaptureCallSiteArgument(const IRPosition &IRP, Attributor &A)6005: AANoCaptureImpl(IRP, A) {}60066007/// See AbstractAttribute::updateImpl(...).6008ChangeStatus updateImpl(Attributor &A) override {6009// TODO: Once we have call site specific value information we can provide6010// call site specific liveness information and then it makes6011// sense to specialize attributes for call sites arguments instead of6012// redirecting requests to the callee argument.6013Argument *Arg = getAssociatedArgument();6014if (!Arg)6015return indicatePessimisticFixpoint();6016const IRPosition &ArgPos = IRPosition::argument(*Arg);6017bool IsKnownNoCapture;6018const AANoCapture *ArgAA = nullptr;6019if (AA::hasAssumedIRAttr<Attribute::NoCapture>(6020A, this, ArgPos, DepClassTy::REQUIRED, IsKnownNoCapture, false,6021&ArgAA))6022return ChangeStatus::UNCHANGED;6023if (!ArgAA || !ArgAA->isAssumedNoCaptureMaybeReturned())6024return indicatePessimisticFixpoint();6025return clampStateAndIndicateChange(getState(), ArgAA->getState());6026}60276028/// See AbstractAttribute::trackStatistics()6029void trackStatistics() const override{STATS_DECLTRACK_CSARG_ATTR(nocapture)};6030};60316032/// NoCapture attribute for floating values.6033struct AANoCaptureFloating final : AANoCaptureImpl {6034AANoCaptureFloating(const IRPosition &IRP, Attributor &A)6035: AANoCaptureImpl(IRP, A) {}60366037/// See AbstractAttribute::trackStatistics()6038void trackStatistics() const override {6039STATS_DECLTRACK_FLOATING_ATTR(nocapture)6040}6041};60426043/// NoCapture attribute for function return value.6044struct AANoCaptureReturned final : AANoCaptureImpl {6045AANoCaptureReturned(const IRPosition &IRP, Attributor &A)6046: AANoCaptureImpl(IRP, A) {6047llvm_unreachable("NoCapture is not applicable to function returns!");6048}60496050/// See AbstractAttribute::initialize(...).6051void initialize(Attributor &A) override {6052llvm_unreachable("NoCapture is not applicable to function returns!");6053}60546055/// See AbstractAttribute::updateImpl(...).6056ChangeStatus updateImpl(Attributor &A) override {6057llvm_unreachable("NoCapture is not applicable to function returns!");6058}60596060/// See AbstractAttribute::trackStatistics()6061void trackStatistics() const override {}6062};60636064/// NoCapture attribute deduction for a call site return value.6065struct AANoCaptureCallSiteReturned final : AANoCaptureImpl {6066AANoCaptureCallSiteReturned(const IRPosition &IRP, Attributor &A)6067: AANoCaptureImpl(IRP, A) {}60686069/// See AbstractAttribute::initialize(...).6070void initialize(Attributor &A) override {6071const Function *F = getAnchorScope();6072// Check what state the associated function can actually capture.6073determineFunctionCaptureCapabilities(getIRPosition(), *F, *this);6074}60756076/// See AbstractAttribute::trackStatistics()6077void trackStatistics() const override {6078STATS_DECLTRACK_CSRET_ATTR(nocapture)6079}6080};6081} // namespace60826083/// ------------------ Value Simplify Attribute ----------------------------60846085bool ValueSimplifyStateType::unionAssumed(std::optional<Value *> Other) {6086// FIXME: Add a typecast support.6087SimplifiedAssociatedValue = AA::combineOptionalValuesInAAValueLatice(6088SimplifiedAssociatedValue, Other, Ty);6089if (SimplifiedAssociatedValue == std::optional<Value *>(nullptr))6090return false;60916092LLVM_DEBUG({6093if (SimplifiedAssociatedValue)6094dbgs() << "[ValueSimplify] is assumed to be "6095<< **SimplifiedAssociatedValue << "\n";6096else6097dbgs() << "[ValueSimplify] is assumed to be <none>\n";6098});6099return true;6100}61016102namespace {6103struct AAValueSimplifyImpl : AAValueSimplify {6104AAValueSimplifyImpl(const IRPosition &IRP, Attributor &A)6105: AAValueSimplify(IRP, A) {}61066107/// See AbstractAttribute::initialize(...).6108void initialize(Attributor &A) override {6109if (getAssociatedValue().getType()->isVoidTy())6110indicatePessimisticFixpoint();6111if (A.hasSimplificationCallback(getIRPosition()))6112indicatePessimisticFixpoint();6113}61146115/// See AbstractAttribute::getAsStr().6116const std::string getAsStr(Attributor *A) const override {6117LLVM_DEBUG({6118dbgs() << "SAV: " << (bool)SimplifiedAssociatedValue << " ";6119if (SimplifiedAssociatedValue && *SimplifiedAssociatedValue)6120dbgs() << "SAV: " << **SimplifiedAssociatedValue << " ";6121});6122return isValidState() ? (isAtFixpoint() ? "simplified" : "maybe-simple")6123: "not-simple";6124}61256126/// See AbstractAttribute::trackStatistics()6127void trackStatistics() const override {}61286129/// See AAValueSimplify::getAssumedSimplifiedValue()6130std::optional<Value *>6131getAssumedSimplifiedValue(Attributor &A) const override {6132return SimplifiedAssociatedValue;6133}61346135/// Ensure the return value is \p V with type \p Ty, if not possible return6136/// nullptr. If \p Check is true we will only verify such an operation would6137/// suceed and return a non-nullptr value if that is the case. No IR is6138/// generated or modified.6139static Value *ensureType(Attributor &A, Value &V, Type &Ty, Instruction *CtxI,6140bool Check) {6141if (auto *TypedV = AA::getWithType(V, Ty))6142return TypedV;6143if (CtxI && V.getType()->canLosslesslyBitCastTo(&Ty))6144return Check ? &V6145: BitCastInst::CreatePointerBitCastOrAddrSpaceCast(6146&V, &Ty, "", CtxI->getIterator());6147return nullptr;6148}61496150/// Reproduce \p I with type \p Ty or return nullptr if that is not posisble.6151/// If \p Check is true we will only verify such an operation would suceed and6152/// return a non-nullptr value if that is the case. No IR is generated or6153/// modified.6154static Value *reproduceInst(Attributor &A,6155const AbstractAttribute &QueryingAA,6156Instruction &I, Type &Ty, Instruction *CtxI,6157bool Check, ValueToValueMapTy &VMap) {6158assert(CtxI && "Cannot reproduce an instruction without context!");6159if (Check && (I.mayReadFromMemory() ||6160!isSafeToSpeculativelyExecute(&I, CtxI, /* DT */ nullptr,6161/* TLI */ nullptr)))6162return nullptr;6163for (Value *Op : I.operands()) {6164Value *NewOp = reproduceValue(A, QueryingAA, *Op, Ty, CtxI, Check, VMap);6165if (!NewOp) {6166assert(Check && "Manifest of new value unexpectedly failed!");6167return nullptr;6168}6169if (!Check)6170VMap[Op] = NewOp;6171}6172if (Check)6173return &I;61746175Instruction *CloneI = I.clone();6176// TODO: Try to salvage debug information here.6177CloneI->setDebugLoc(DebugLoc());6178VMap[&I] = CloneI;6179CloneI->insertBefore(CtxI);6180RemapInstruction(CloneI, VMap);6181return CloneI;6182}61836184/// Reproduce \p V with type \p Ty or return nullptr if that is not posisble.6185/// If \p Check is true we will only verify such an operation would suceed and6186/// return a non-nullptr value if that is the case. No IR is generated or6187/// modified.6188static Value *reproduceValue(Attributor &A,6189const AbstractAttribute &QueryingAA, Value &V,6190Type &Ty, Instruction *CtxI, bool Check,6191ValueToValueMapTy &VMap) {6192if (const auto &NewV = VMap.lookup(&V))6193return NewV;6194bool UsedAssumedInformation = false;6195std::optional<Value *> SimpleV = A.getAssumedSimplified(6196V, QueryingAA, UsedAssumedInformation, AA::Interprocedural);6197if (!SimpleV.has_value())6198return PoisonValue::get(&Ty);6199Value *EffectiveV = &V;6200if (*SimpleV)6201EffectiveV = *SimpleV;6202if (auto *C = dyn_cast<Constant>(EffectiveV))6203return C;6204if (CtxI && AA::isValidAtPosition(AA::ValueAndContext(*EffectiveV, *CtxI),6205A.getInfoCache()))6206return ensureType(A, *EffectiveV, Ty, CtxI, Check);6207if (auto *I = dyn_cast<Instruction>(EffectiveV))6208if (Value *NewV = reproduceInst(A, QueryingAA, *I, Ty, CtxI, Check, VMap))6209return ensureType(A, *NewV, Ty, CtxI, Check);6210return nullptr;6211}62126213/// Return a value we can use as replacement for the associated one, or6214/// nullptr if we don't have one that makes sense.6215Value *manifestReplacementValue(Attributor &A, Instruction *CtxI) const {6216Value *NewV = SimplifiedAssociatedValue6217? *SimplifiedAssociatedValue6218: UndefValue::get(getAssociatedType());6219if (NewV && NewV != &getAssociatedValue()) {6220ValueToValueMapTy VMap;6221// First verify we can reprduce the value with the required type at the6222// context location before we actually start modifying the IR.6223if (reproduceValue(A, *this, *NewV, *getAssociatedType(), CtxI,6224/* CheckOnly */ true, VMap))6225return reproduceValue(A, *this, *NewV, *getAssociatedType(), CtxI,6226/* CheckOnly */ false, VMap);6227}6228return nullptr;6229}62306231/// Helper function for querying AAValueSimplify and updating candidate.6232/// \param IRP The value position we are trying to unify with SimplifiedValue6233bool checkAndUpdate(Attributor &A, const AbstractAttribute &QueryingAA,6234const IRPosition &IRP, bool Simplify = true) {6235bool UsedAssumedInformation = false;6236std::optional<Value *> QueryingValueSimplified = &IRP.getAssociatedValue();6237if (Simplify)6238QueryingValueSimplified = A.getAssumedSimplified(6239IRP, QueryingAA, UsedAssumedInformation, AA::Interprocedural);6240return unionAssumed(QueryingValueSimplified);6241}62426243/// Returns a candidate is found or not6244template <typename AAType> bool askSimplifiedValueFor(Attributor &A) {6245if (!getAssociatedValue().getType()->isIntegerTy())6246return false;62476248// This will also pass the call base context.6249const auto *AA =6250A.getAAFor<AAType>(*this, getIRPosition(), DepClassTy::NONE);6251if (!AA)6252return false;62536254std::optional<Constant *> COpt = AA->getAssumedConstant(A);62556256if (!COpt) {6257SimplifiedAssociatedValue = std::nullopt;6258A.recordDependence(*AA, *this, DepClassTy::OPTIONAL);6259return true;6260}6261if (auto *C = *COpt) {6262SimplifiedAssociatedValue = C;6263A.recordDependence(*AA, *this, DepClassTy::OPTIONAL);6264return true;6265}6266return false;6267}62686269bool askSimplifiedValueForOtherAAs(Attributor &A) {6270if (askSimplifiedValueFor<AAValueConstantRange>(A))6271return true;6272if (askSimplifiedValueFor<AAPotentialConstantValues>(A))6273return true;6274return false;6275}62766277/// See AbstractAttribute::manifest(...).6278ChangeStatus manifest(Attributor &A) override {6279ChangeStatus Changed = ChangeStatus::UNCHANGED;6280for (auto &U : getAssociatedValue().uses()) {6281// Check if we need to adjust the insertion point to make sure the IR is6282// valid.6283Instruction *IP = dyn_cast<Instruction>(U.getUser());6284if (auto *PHI = dyn_cast_or_null<PHINode>(IP))6285IP = PHI->getIncomingBlock(U)->getTerminator();6286if (auto *NewV = manifestReplacementValue(A, IP)) {6287LLVM_DEBUG(dbgs() << "[ValueSimplify] " << getAssociatedValue()6288<< " -> " << *NewV << " :: " << *this << "\n");6289if (A.changeUseAfterManifest(U, *NewV))6290Changed = ChangeStatus::CHANGED;6291}6292}62936294return Changed | AAValueSimplify::manifest(A);6295}62966297/// See AbstractState::indicatePessimisticFixpoint(...).6298ChangeStatus indicatePessimisticFixpoint() override {6299SimplifiedAssociatedValue = &getAssociatedValue();6300return AAValueSimplify::indicatePessimisticFixpoint();6301}6302};63036304struct AAValueSimplifyArgument final : AAValueSimplifyImpl {6305AAValueSimplifyArgument(const IRPosition &IRP, Attributor &A)6306: AAValueSimplifyImpl(IRP, A) {}63076308void initialize(Attributor &A) override {6309AAValueSimplifyImpl::initialize(A);6310if (A.hasAttr(getIRPosition(),6311{Attribute::InAlloca, Attribute::Preallocated,6312Attribute::StructRet, Attribute::Nest, Attribute::ByVal},6313/* IgnoreSubsumingPositions */ true))6314indicatePessimisticFixpoint();6315}63166317/// See AbstractAttribute::updateImpl(...).6318ChangeStatus updateImpl(Attributor &A) override {6319// Byval is only replacable if it is readonly otherwise we would write into6320// the replaced value and not the copy that byval creates implicitly.6321Argument *Arg = getAssociatedArgument();6322if (Arg->hasByValAttr()) {6323// TODO: We probably need to verify synchronization is not an issue, e.g.,6324// there is no race by not copying a constant byval.6325bool IsKnown;6326if (!AA::isAssumedReadOnly(A, getIRPosition(), *this, IsKnown))6327return indicatePessimisticFixpoint();6328}63296330auto Before = SimplifiedAssociatedValue;63316332auto PredForCallSite = [&](AbstractCallSite ACS) {6333const IRPosition &ACSArgPos =6334IRPosition::callsite_argument(ACS, getCallSiteArgNo());6335// Check if a coresponding argument was found or if it is on not6336// associated (which can happen for callback calls).6337if (ACSArgPos.getPositionKind() == IRPosition::IRP_INVALID)6338return false;63396340// Simplify the argument operand explicitly and check if the result is6341// valid in the current scope. This avoids refering to simplified values6342// in other functions, e.g., we don't want to say a an argument in a6343// static function is actually an argument in a different function.6344bool UsedAssumedInformation = false;6345std::optional<Constant *> SimpleArgOp =6346A.getAssumedConstant(ACSArgPos, *this, UsedAssumedInformation);6347if (!SimpleArgOp)6348return true;6349if (!*SimpleArgOp)6350return false;6351if (!AA::isDynamicallyUnique(A, *this, **SimpleArgOp))6352return false;6353return unionAssumed(*SimpleArgOp);6354};63556356// Generate a answer specific to a call site context.6357bool Success;6358bool UsedAssumedInformation = false;6359if (hasCallBaseContext() &&6360getCallBaseContext()->getCalledOperand() == Arg->getParent())6361Success = PredForCallSite(6362AbstractCallSite(&getCallBaseContext()->getCalledOperandUse()));6363else6364Success = A.checkForAllCallSites(PredForCallSite, *this, true,6365UsedAssumedInformation);63666367if (!Success)6368if (!askSimplifiedValueForOtherAAs(A))6369return indicatePessimisticFixpoint();63706371// If a candidate was found in this update, return CHANGED.6372return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED6373: ChangeStatus ::CHANGED;6374}63756376/// See AbstractAttribute::trackStatistics()6377void trackStatistics() const override {6378STATS_DECLTRACK_ARG_ATTR(value_simplify)6379}6380};63816382struct AAValueSimplifyReturned : AAValueSimplifyImpl {6383AAValueSimplifyReturned(const IRPosition &IRP, Attributor &A)6384: AAValueSimplifyImpl(IRP, A) {}63856386/// See AAValueSimplify::getAssumedSimplifiedValue()6387std::optional<Value *>6388getAssumedSimplifiedValue(Attributor &A) const override {6389if (!isValidState())6390return nullptr;6391return SimplifiedAssociatedValue;6392}63936394/// See AbstractAttribute::updateImpl(...).6395ChangeStatus updateImpl(Attributor &A) override {6396auto Before = SimplifiedAssociatedValue;63976398auto ReturnInstCB = [&](Instruction &I) {6399auto &RI = cast<ReturnInst>(I);6400return checkAndUpdate(6401A, *this,6402IRPosition::value(*RI.getReturnValue(), getCallBaseContext()));6403};64046405bool UsedAssumedInformation = false;6406if (!A.checkForAllInstructions(ReturnInstCB, *this, {Instruction::Ret},6407UsedAssumedInformation))6408if (!askSimplifiedValueForOtherAAs(A))6409return indicatePessimisticFixpoint();64106411// If a candidate was found in this update, return CHANGED.6412return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED6413: ChangeStatus ::CHANGED;6414}64156416ChangeStatus manifest(Attributor &A) override {6417// We queried AAValueSimplify for the returned values so they will be6418// replaced if a simplified form was found. Nothing to do here.6419return ChangeStatus::UNCHANGED;6420}64216422/// See AbstractAttribute::trackStatistics()6423void trackStatistics() const override {6424STATS_DECLTRACK_FNRET_ATTR(value_simplify)6425}6426};64276428struct AAValueSimplifyFloating : AAValueSimplifyImpl {6429AAValueSimplifyFloating(const IRPosition &IRP, Attributor &A)6430: AAValueSimplifyImpl(IRP, A) {}64316432/// See AbstractAttribute::initialize(...).6433void initialize(Attributor &A) override {6434AAValueSimplifyImpl::initialize(A);6435Value &V = getAnchorValue();64366437// TODO: add other stuffs6438if (isa<Constant>(V))6439indicatePessimisticFixpoint();6440}64416442/// See AbstractAttribute::updateImpl(...).6443ChangeStatus updateImpl(Attributor &A) override {6444auto Before = SimplifiedAssociatedValue;6445if (!askSimplifiedValueForOtherAAs(A))6446return indicatePessimisticFixpoint();64476448// If a candidate was found in this update, return CHANGED.6449return Before == SimplifiedAssociatedValue ? ChangeStatus::UNCHANGED6450: ChangeStatus ::CHANGED;6451}64526453/// See AbstractAttribute::trackStatistics()6454void trackStatistics() const override {6455STATS_DECLTRACK_FLOATING_ATTR(value_simplify)6456}6457};64586459struct AAValueSimplifyFunction : AAValueSimplifyImpl {6460AAValueSimplifyFunction(const IRPosition &IRP, Attributor &A)6461: AAValueSimplifyImpl(IRP, A) {}64626463/// See AbstractAttribute::initialize(...).6464void initialize(Attributor &A) override {6465SimplifiedAssociatedValue = nullptr;6466indicateOptimisticFixpoint();6467}6468/// See AbstractAttribute::initialize(...).6469ChangeStatus updateImpl(Attributor &A) override {6470llvm_unreachable(6471"AAValueSimplify(Function|CallSite)::updateImpl will not be called");6472}6473/// See AbstractAttribute::trackStatistics()6474void trackStatistics() const override {6475STATS_DECLTRACK_FN_ATTR(value_simplify)6476}6477};64786479struct AAValueSimplifyCallSite : AAValueSimplifyFunction {6480AAValueSimplifyCallSite(const IRPosition &IRP, Attributor &A)6481: AAValueSimplifyFunction(IRP, A) {}6482/// See AbstractAttribute::trackStatistics()6483void trackStatistics() const override {6484STATS_DECLTRACK_CS_ATTR(value_simplify)6485}6486};64876488struct AAValueSimplifyCallSiteReturned : AAValueSimplifyImpl {6489AAValueSimplifyCallSiteReturned(const IRPosition &IRP, Attributor &A)6490: AAValueSimplifyImpl(IRP, A) {}64916492void initialize(Attributor &A) override {6493AAValueSimplifyImpl::initialize(A);6494Function *Fn = getAssociatedFunction();6495assert(Fn && "Did expect an associted function");6496for (Argument &Arg : Fn->args()) {6497if (Arg.hasReturnedAttr()) {6498auto IRP = IRPosition::callsite_argument(*cast<CallBase>(getCtxI()),6499Arg.getArgNo());6500if (IRP.getPositionKind() == IRPosition::IRP_CALL_SITE_ARGUMENT &&6501checkAndUpdate(A, *this, IRP))6502indicateOptimisticFixpoint();6503else6504indicatePessimisticFixpoint();6505return;6506}6507}6508}65096510/// See AbstractAttribute::updateImpl(...).6511ChangeStatus updateImpl(Attributor &A) override {6512return indicatePessimisticFixpoint();6513}65146515void trackStatistics() const override {6516STATS_DECLTRACK_CSRET_ATTR(value_simplify)6517}6518};65196520struct AAValueSimplifyCallSiteArgument : AAValueSimplifyFloating {6521AAValueSimplifyCallSiteArgument(const IRPosition &IRP, Attributor &A)6522: AAValueSimplifyFloating(IRP, A) {}65236524/// See AbstractAttribute::manifest(...).6525ChangeStatus manifest(Attributor &A) override {6526ChangeStatus Changed = ChangeStatus::UNCHANGED;6527// TODO: We should avoid simplification duplication to begin with.6528auto *FloatAA = A.lookupAAFor<AAValueSimplify>(6529IRPosition::value(getAssociatedValue()), this, DepClassTy::NONE);6530if (FloatAA && FloatAA->getState().isValidState())6531return Changed;65326533if (auto *NewV = manifestReplacementValue(A, getCtxI())) {6534Use &U = cast<CallBase>(&getAnchorValue())6535->getArgOperandUse(getCallSiteArgNo());6536if (A.changeUseAfterManifest(U, *NewV))6537Changed = ChangeStatus::CHANGED;6538}65396540return Changed | AAValueSimplify::manifest(A);6541}65426543void trackStatistics() const override {6544STATS_DECLTRACK_CSARG_ATTR(value_simplify)6545}6546};6547} // namespace65486549/// ----------------------- Heap-To-Stack Conversion ---------------------------6550namespace {6551struct AAHeapToStackFunction final : public AAHeapToStack {65526553struct AllocationInfo {6554/// The call that allocates the memory.6555CallBase *const CB;65566557/// The library function id for the allocation.6558LibFunc LibraryFunctionId = NotLibFunc;65596560/// The status wrt. a rewrite.6561enum {6562STACK_DUE_TO_USE,6563STACK_DUE_TO_FREE,6564INVALID,6565} Status = STACK_DUE_TO_USE;65666567/// Flag to indicate if we encountered a use that might free this allocation6568/// but which is not in the deallocation infos.6569bool HasPotentiallyFreeingUnknownUses = false;65706571/// Flag to indicate that we should place the new alloca in the function6572/// entry block rather than where the call site (CB) is.6573bool MoveAllocaIntoEntry = true;65746575/// The set of free calls that use this allocation.6576SmallSetVector<CallBase *, 1> PotentialFreeCalls{};6577};65786579struct DeallocationInfo {6580/// The call that deallocates the memory.6581CallBase *const CB;6582/// The value freed by the call.6583Value *FreedOp;65846585/// Flag to indicate if we don't know all objects this deallocation might6586/// free.6587bool MightFreeUnknownObjects = false;65886589/// The set of allocation calls that are potentially freed.6590SmallSetVector<CallBase *, 1> PotentialAllocationCalls{};6591};65926593AAHeapToStackFunction(const IRPosition &IRP, Attributor &A)6594: AAHeapToStack(IRP, A) {}65956596~AAHeapToStackFunction() {6597// Ensure we call the destructor so we release any memory allocated in the6598// sets.6599for (auto &It : AllocationInfos)6600It.second->~AllocationInfo();6601for (auto &It : DeallocationInfos)6602It.second->~DeallocationInfo();6603}66046605void initialize(Attributor &A) override {6606AAHeapToStack::initialize(A);66076608const Function *F = getAnchorScope();6609const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F);66106611auto AllocationIdentifierCB = [&](Instruction &I) {6612CallBase *CB = dyn_cast<CallBase>(&I);6613if (!CB)6614return true;6615if (Value *FreedOp = getFreedOperand(CB, TLI)) {6616DeallocationInfos[CB] = new (A.Allocator) DeallocationInfo{CB, FreedOp};6617return true;6618}6619// To do heap to stack, we need to know that the allocation itself is6620// removable once uses are rewritten, and that we can initialize the6621// alloca to the same pattern as the original allocation result.6622if (isRemovableAlloc(CB, TLI)) {6623auto *I8Ty = Type::getInt8Ty(CB->getParent()->getContext());6624if (nullptr != getInitialValueOfAllocation(CB, TLI, I8Ty)) {6625AllocationInfo *AI = new (A.Allocator) AllocationInfo{CB};6626AllocationInfos[CB] = AI;6627if (TLI)6628TLI->getLibFunc(*CB, AI->LibraryFunctionId);6629}6630}6631return true;6632};66336634bool UsedAssumedInformation = false;6635bool Success = A.checkForAllCallLikeInstructions(6636AllocationIdentifierCB, *this, UsedAssumedInformation,6637/* CheckBBLivenessOnly */ false,6638/* CheckPotentiallyDead */ true);6639(void)Success;6640assert(Success && "Did not expect the call base visit callback to fail!");66416642Attributor::SimplifictionCallbackTy SCB =6643[](const IRPosition &, const AbstractAttribute *,6644bool &) -> std::optional<Value *> { return nullptr; };6645for (const auto &It : AllocationInfos)6646A.registerSimplificationCallback(IRPosition::callsite_returned(*It.first),6647SCB);6648for (const auto &It : DeallocationInfos)6649A.registerSimplificationCallback(IRPosition::callsite_returned(*It.first),6650SCB);6651}66526653const std::string getAsStr(Attributor *A) const override {6654unsigned NumH2SMallocs = 0, NumInvalidMallocs = 0;6655for (const auto &It : AllocationInfos) {6656if (It.second->Status == AllocationInfo::INVALID)6657++NumInvalidMallocs;6658else6659++NumH2SMallocs;6660}6661return "[H2S] Mallocs Good/Bad: " + std::to_string(NumH2SMallocs) + "/" +6662std::to_string(NumInvalidMallocs);6663}66646665/// See AbstractAttribute::trackStatistics().6666void trackStatistics() const override {6667STATS_DECL(6668MallocCalls, Function,6669"Number of malloc/calloc/aligned_alloc calls converted to allocas");6670for (const auto &It : AllocationInfos)6671if (It.second->Status != AllocationInfo::INVALID)6672++BUILD_STAT_NAME(MallocCalls, Function);6673}66746675bool isAssumedHeapToStack(const CallBase &CB) const override {6676if (isValidState())6677if (AllocationInfo *AI =6678AllocationInfos.lookup(const_cast<CallBase *>(&CB)))6679return AI->Status != AllocationInfo::INVALID;6680return false;6681}66826683bool isAssumedHeapToStackRemovedFree(CallBase &CB) const override {6684if (!isValidState())6685return false;66866687for (const auto &It : AllocationInfos) {6688AllocationInfo &AI = *It.second;6689if (AI.Status == AllocationInfo::INVALID)6690continue;66916692if (AI.PotentialFreeCalls.count(&CB))6693return true;6694}66956696return false;6697}66986699ChangeStatus manifest(Attributor &A) override {6700assert(getState().isValidState() &&6701"Attempted to manifest an invalid state!");67026703ChangeStatus HasChanged = ChangeStatus::UNCHANGED;6704Function *F = getAnchorScope();6705const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F);67066707for (auto &It : AllocationInfos) {6708AllocationInfo &AI = *It.second;6709if (AI.Status == AllocationInfo::INVALID)6710continue;67116712for (CallBase *FreeCall : AI.PotentialFreeCalls) {6713LLVM_DEBUG(dbgs() << "H2S: Removing free call: " << *FreeCall << "\n");6714A.deleteAfterManifest(*FreeCall);6715HasChanged = ChangeStatus::CHANGED;6716}67176718LLVM_DEBUG(dbgs() << "H2S: Removing malloc-like call: " << *AI.CB6719<< "\n");67206721auto Remark = [&](OptimizationRemark OR) {6722LibFunc IsAllocShared;6723if (TLI->getLibFunc(*AI.CB, IsAllocShared))6724if (IsAllocShared == LibFunc___kmpc_alloc_shared)6725return OR << "Moving globalized variable to the stack.";6726return OR << "Moving memory allocation from the heap to the stack.";6727};6728if (AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)6729A.emitRemark<OptimizationRemark>(AI.CB, "OMP110", Remark);6730else6731A.emitRemark<OptimizationRemark>(AI.CB, "HeapToStack", Remark);67326733const DataLayout &DL = A.getInfoCache().getDL();6734Value *Size;6735std::optional<APInt> SizeAPI = getSize(A, *this, AI);6736if (SizeAPI) {6737Size = ConstantInt::get(AI.CB->getContext(), *SizeAPI);6738} else {6739LLVMContext &Ctx = AI.CB->getContext();6740ObjectSizeOpts Opts;6741ObjectSizeOffsetEvaluator Eval(DL, TLI, Ctx, Opts);6742SizeOffsetValue SizeOffsetPair = Eval.compute(AI.CB);6743assert(SizeOffsetPair != ObjectSizeOffsetEvaluator::unknown() &&6744cast<ConstantInt>(SizeOffsetPair.Offset)->isZero());6745Size = SizeOffsetPair.Size;6746}67476748BasicBlock::iterator IP = AI.MoveAllocaIntoEntry6749? F->getEntryBlock().begin()6750: AI.CB->getIterator();67516752Align Alignment(1);6753if (MaybeAlign RetAlign = AI.CB->getRetAlign())6754Alignment = std::max(Alignment, *RetAlign);6755if (Value *Align = getAllocAlignment(AI.CB, TLI)) {6756std::optional<APInt> AlignmentAPI = getAPInt(A, *this, *Align);6757assert(AlignmentAPI && AlignmentAPI->getZExtValue() > 0 &&6758"Expected an alignment during manifest!");6759Alignment =6760std::max(Alignment, assumeAligned(AlignmentAPI->getZExtValue()));6761}67626763// TODO: Hoist the alloca towards the function entry.6764unsigned AS = DL.getAllocaAddrSpace();6765Instruction *Alloca =6766new AllocaInst(Type::getInt8Ty(F->getContext()), AS, Size, Alignment,6767AI.CB->getName() + ".h2s", IP);67686769if (Alloca->getType() != AI.CB->getType())6770Alloca = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(6771Alloca, AI.CB->getType(), "malloc_cast", AI.CB->getIterator());67726773auto *I8Ty = Type::getInt8Ty(F->getContext());6774auto *InitVal = getInitialValueOfAllocation(AI.CB, TLI, I8Ty);6775assert(InitVal &&6776"Must be able to materialize initial memory state of allocation");67776778A.changeAfterManifest(IRPosition::inst(*AI.CB), *Alloca);67796780if (auto *II = dyn_cast<InvokeInst>(AI.CB)) {6781auto *NBB = II->getNormalDest();6782BranchInst::Create(NBB, AI.CB->getParent());6783A.deleteAfterManifest(*AI.CB);6784} else {6785A.deleteAfterManifest(*AI.CB);6786}67876788// Initialize the alloca with the same value as used by the allocation6789// function. We can skip undef as the initial value of an alloc is6790// undef, and the memset would simply end up being DSEd.6791if (!isa<UndefValue>(InitVal)) {6792IRBuilder<> Builder(Alloca->getNextNode());6793// TODO: Use alignment above if align!=16794Builder.CreateMemSet(Alloca, InitVal, Size, std::nullopt);6795}6796HasChanged = ChangeStatus::CHANGED;6797}67986799return HasChanged;6800}68016802std::optional<APInt> getAPInt(Attributor &A, const AbstractAttribute &AA,6803Value &V) {6804bool UsedAssumedInformation = false;6805std::optional<Constant *> SimpleV =6806A.getAssumedConstant(V, AA, UsedAssumedInformation);6807if (!SimpleV)6808return APInt(64, 0);6809if (auto *CI = dyn_cast_or_null<ConstantInt>(*SimpleV))6810return CI->getValue();6811return std::nullopt;6812}68136814std::optional<APInt> getSize(Attributor &A, const AbstractAttribute &AA,6815AllocationInfo &AI) {6816auto Mapper = [&](const Value *V) -> const Value * {6817bool UsedAssumedInformation = false;6818if (std::optional<Constant *> SimpleV =6819A.getAssumedConstant(*V, AA, UsedAssumedInformation))6820if (*SimpleV)6821return *SimpleV;6822return V;6823};68246825const Function *F = getAnchorScope();6826const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F);6827return getAllocSize(AI.CB, TLI, Mapper);6828}68296830/// Collection of all malloc-like calls in a function with associated6831/// information.6832MapVector<CallBase *, AllocationInfo *> AllocationInfos;68336834/// Collection of all free-like calls in a function with associated6835/// information.6836MapVector<CallBase *, DeallocationInfo *> DeallocationInfos;68376838ChangeStatus updateImpl(Attributor &A) override;6839};68406841ChangeStatus AAHeapToStackFunction::updateImpl(Attributor &A) {6842ChangeStatus Changed = ChangeStatus::UNCHANGED;6843const Function *F = getAnchorScope();6844const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F);68456846const auto *LivenessAA =6847A.getAAFor<AAIsDead>(*this, IRPosition::function(*F), DepClassTy::NONE);68486849MustBeExecutedContextExplorer *Explorer =6850A.getInfoCache().getMustBeExecutedContextExplorer();68516852bool StackIsAccessibleByOtherThreads =6853A.getInfoCache().stackIsAccessibleByOtherThreads();68546855LoopInfo *LI =6856A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(*F);6857std::optional<bool> MayContainIrreducibleControl;6858auto IsInLoop = [&](BasicBlock &BB) {6859if (&F->getEntryBlock() == &BB)6860return false;6861if (!MayContainIrreducibleControl.has_value())6862MayContainIrreducibleControl = mayContainIrreducibleControl(*F, LI);6863if (*MayContainIrreducibleControl)6864return true;6865if (!LI)6866return true;6867return LI->getLoopFor(&BB) != nullptr;6868};68696870// Flag to ensure we update our deallocation information at most once per6871// updateImpl call and only if we use the free check reasoning.6872bool HasUpdatedFrees = false;68736874auto UpdateFrees = [&]() {6875HasUpdatedFrees = true;68766877for (auto &It : DeallocationInfos) {6878DeallocationInfo &DI = *It.second;6879// For now we cannot use deallocations that have unknown inputs, skip6880// them.6881if (DI.MightFreeUnknownObjects)6882continue;68836884// No need to analyze dead calls, ignore them instead.6885bool UsedAssumedInformation = false;6886if (A.isAssumedDead(*DI.CB, this, LivenessAA, UsedAssumedInformation,6887/* CheckBBLivenessOnly */ true))6888continue;68896890// Use the non-optimistic version to get the freed object.6891Value *Obj = getUnderlyingObject(DI.FreedOp);6892if (!Obj) {6893LLVM_DEBUG(dbgs() << "[H2S] Unknown underlying object for free!\n");6894DI.MightFreeUnknownObjects = true;6895continue;6896}68976898// Free of null and undef can be ignored as no-ops (or UB in the latter6899// case).6900if (isa<ConstantPointerNull>(Obj) || isa<UndefValue>(Obj))6901continue;69026903CallBase *ObjCB = dyn_cast<CallBase>(Obj);6904if (!ObjCB) {6905LLVM_DEBUG(dbgs() << "[H2S] Free of a non-call object: " << *Obj6906<< "\n");6907DI.MightFreeUnknownObjects = true;6908continue;6909}69106911AllocationInfo *AI = AllocationInfos.lookup(ObjCB);6912if (!AI) {6913LLVM_DEBUG(dbgs() << "[H2S] Free of a non-allocation object: " << *Obj6914<< "\n");6915DI.MightFreeUnknownObjects = true;6916continue;6917}69186919DI.PotentialAllocationCalls.insert(ObjCB);6920}6921};69226923auto FreeCheck = [&](AllocationInfo &AI) {6924// If the stack is not accessible by other threads, the "must-free" logic6925// doesn't apply as the pointer could be shared and needs to be places in6926// "shareable" memory.6927if (!StackIsAccessibleByOtherThreads) {6928bool IsKnownNoSycn;6929if (!AA::hasAssumedIRAttr<Attribute::NoSync>(6930A, this, getIRPosition(), DepClassTy::OPTIONAL, IsKnownNoSycn)) {6931LLVM_DEBUG(6932dbgs() << "[H2S] found an escaping use, stack is not accessible by "6933"other threads and function is not nosync:\n");6934return false;6935}6936}6937if (!HasUpdatedFrees)6938UpdateFrees();69396940// TODO: Allow multi exit functions that have different free calls.6941if (AI.PotentialFreeCalls.size() != 1) {6942LLVM_DEBUG(dbgs() << "[H2S] did not find one free call but "6943<< AI.PotentialFreeCalls.size() << "\n");6944return false;6945}6946CallBase *UniqueFree = *AI.PotentialFreeCalls.begin();6947DeallocationInfo *DI = DeallocationInfos.lookup(UniqueFree);6948if (!DI) {6949LLVM_DEBUG(6950dbgs() << "[H2S] unique free call was not known as deallocation call "6951<< *UniqueFree << "\n");6952return false;6953}6954if (DI->MightFreeUnknownObjects) {6955LLVM_DEBUG(6956dbgs() << "[H2S] unique free call might free unknown allocations\n");6957return false;6958}6959if (DI->PotentialAllocationCalls.empty())6960return true;6961if (DI->PotentialAllocationCalls.size() > 1) {6962LLVM_DEBUG(dbgs() << "[H2S] unique free call might free "6963<< DI->PotentialAllocationCalls.size()6964<< " different allocations\n");6965return false;6966}6967if (*DI->PotentialAllocationCalls.begin() != AI.CB) {6968LLVM_DEBUG(6969dbgs()6970<< "[H2S] unique free call not known to free this allocation but "6971<< **DI->PotentialAllocationCalls.begin() << "\n");6972return false;6973}69746975// __kmpc_alloc_shared and __kmpc_alloc_free are by construction matched.6976if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared) {6977Instruction *CtxI = isa<InvokeInst>(AI.CB) ? AI.CB : AI.CB->getNextNode();6978if (!Explorer || !Explorer->findInContextOf(UniqueFree, CtxI)) {6979LLVM_DEBUG(dbgs() << "[H2S] unique free call might not be executed "6980"with the allocation "6981<< *UniqueFree << "\n");6982return false;6983}6984}6985return true;6986};69876988auto UsesCheck = [&](AllocationInfo &AI) {6989bool ValidUsesOnly = true;69906991auto Pred = [&](const Use &U, bool &Follow) -> bool {6992Instruction *UserI = cast<Instruction>(U.getUser());6993if (isa<LoadInst>(UserI))6994return true;6995if (auto *SI = dyn_cast<StoreInst>(UserI)) {6996if (SI->getValueOperand() == U.get()) {6997LLVM_DEBUG(dbgs()6998<< "[H2S] escaping store to memory: " << *UserI << "\n");6999ValidUsesOnly = false;7000} else {7001// A store into the malloc'ed memory is fine.7002}7003return true;7004}7005if (auto *CB = dyn_cast<CallBase>(UserI)) {7006if (!CB->isArgOperand(&U) || CB->isLifetimeStartOrEnd())7007return true;7008if (DeallocationInfos.count(CB)) {7009AI.PotentialFreeCalls.insert(CB);7010return true;7011}70127013unsigned ArgNo = CB->getArgOperandNo(&U);7014auto CBIRP = IRPosition::callsite_argument(*CB, ArgNo);70157016bool IsKnownNoCapture;7017bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(7018A, this, CBIRP, DepClassTy::OPTIONAL, IsKnownNoCapture);70197020// If a call site argument use is nofree, we are fine.7021bool IsKnownNoFree;7022bool IsAssumedNoFree = AA::hasAssumedIRAttr<Attribute::NoFree>(7023A, this, CBIRP, DepClassTy::OPTIONAL, IsKnownNoFree);70247025if (!IsAssumedNoCapture ||7026(AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&7027!IsAssumedNoFree)) {7028AI.HasPotentiallyFreeingUnknownUses |= !IsAssumedNoFree;70297030// Emit a missed remark if this is missed OpenMP globalization.7031auto Remark = [&](OptimizationRemarkMissed ORM) {7032return ORM7033<< "Could not move globalized variable to the stack. "7034"Variable is potentially captured in call. Mark "7035"parameter as `__attribute__((noescape))` to override.";7036};70377038if (ValidUsesOnly &&7039AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared)7040A.emitRemark<OptimizationRemarkMissed>(CB, "OMP113", Remark);70417042LLVM_DEBUG(dbgs() << "[H2S] Bad user: " << *UserI << "\n");7043ValidUsesOnly = false;7044}7045return true;7046}70477048if (isa<GetElementPtrInst>(UserI) || isa<BitCastInst>(UserI) ||7049isa<PHINode>(UserI) || isa<SelectInst>(UserI)) {7050Follow = true;7051return true;7052}7053// Unknown user for which we can not track uses further (in a way that7054// makes sense).7055LLVM_DEBUG(dbgs() << "[H2S] Unknown user: " << *UserI << "\n");7056ValidUsesOnly = false;7057return true;7058};7059if (!A.checkForAllUses(Pred, *this, *AI.CB, /* CheckBBLivenessOnly */ false,7060DepClassTy::OPTIONAL, /* IgnoreDroppableUses */ true,7061[&](const Use &OldU, const Use &NewU) {7062auto *SI = dyn_cast<StoreInst>(OldU.getUser());7063return !SI || StackIsAccessibleByOtherThreads ||7064AA::isAssumedThreadLocalObject(7065A, *SI->getPointerOperand(), *this);7066}))7067return false;7068return ValidUsesOnly;7069};70707071// The actual update starts here. We look at all allocations and depending on7072// their status perform the appropriate check(s).7073for (auto &It : AllocationInfos) {7074AllocationInfo &AI = *It.second;7075if (AI.Status == AllocationInfo::INVALID)7076continue;70777078if (Value *Align = getAllocAlignment(AI.CB, TLI)) {7079std::optional<APInt> APAlign = getAPInt(A, *this, *Align);7080if (!APAlign) {7081// Can't generate an alloca which respects the required alignment7082// on the allocation.7083LLVM_DEBUG(dbgs() << "[H2S] Unknown allocation alignment: " << *AI.CB7084<< "\n");7085AI.Status = AllocationInfo::INVALID;7086Changed = ChangeStatus::CHANGED;7087continue;7088}7089if (APAlign->ugt(llvm::Value::MaximumAlignment) ||7090!APAlign->isPowerOf2()) {7091LLVM_DEBUG(dbgs() << "[H2S] Invalid allocation alignment: " << APAlign7092<< "\n");7093AI.Status = AllocationInfo::INVALID;7094Changed = ChangeStatus::CHANGED;7095continue;7096}7097}70987099std::optional<APInt> Size = getSize(A, *this, AI);7100if (AI.LibraryFunctionId != LibFunc___kmpc_alloc_shared &&7101MaxHeapToStackSize != -1) {7102if (!Size || Size->ugt(MaxHeapToStackSize)) {7103LLVM_DEBUG({7104if (!Size)7105dbgs() << "[H2S] Unknown allocation size: " << *AI.CB << "\n";7106else7107dbgs() << "[H2S] Allocation size too large: " << *AI.CB << " vs. "7108<< MaxHeapToStackSize << "\n";7109});71107111AI.Status = AllocationInfo::INVALID;7112Changed = ChangeStatus::CHANGED;7113continue;7114}7115}71167117switch (AI.Status) {7118case AllocationInfo::STACK_DUE_TO_USE:7119if (UsesCheck(AI))7120break;7121AI.Status = AllocationInfo::STACK_DUE_TO_FREE;7122[[fallthrough]];7123case AllocationInfo::STACK_DUE_TO_FREE:7124if (FreeCheck(AI))7125break;7126AI.Status = AllocationInfo::INVALID;7127Changed = ChangeStatus::CHANGED;7128break;7129case AllocationInfo::INVALID:7130llvm_unreachable("Invalid allocations should never reach this point!");7131};71327133// Check if we still think we can move it into the entry block. If the7134// alloca comes from a converted __kmpc_alloc_shared then we can usually7135// ignore the potential compilations associated with loops.7136bool IsGlobalizedLocal =7137AI.LibraryFunctionId == LibFunc___kmpc_alloc_shared;7138if (AI.MoveAllocaIntoEntry &&7139(!Size.has_value() ||7140(!IsGlobalizedLocal && IsInLoop(*AI.CB->getParent()))))7141AI.MoveAllocaIntoEntry = false;7142}71437144return Changed;7145}7146} // namespace71477148/// ----------------------- Privatizable Pointers ------------------------------7149namespace {7150struct AAPrivatizablePtrImpl : public AAPrivatizablePtr {7151AAPrivatizablePtrImpl(const IRPosition &IRP, Attributor &A)7152: AAPrivatizablePtr(IRP, A), PrivatizableType(std::nullopt) {}71537154ChangeStatus indicatePessimisticFixpoint() override {7155AAPrivatizablePtr::indicatePessimisticFixpoint();7156PrivatizableType = nullptr;7157return ChangeStatus::CHANGED;7158}71597160/// Identify the type we can chose for a private copy of the underlying7161/// argument. std::nullopt means it is not clear yet, nullptr means there is7162/// none.7163virtual std::optional<Type *> identifyPrivatizableType(Attributor &A) = 0;71647165/// Return a privatizable type that encloses both T0 and T1.7166/// TODO: This is merely a stub for now as we should manage a mapping as well.7167std::optional<Type *> combineTypes(std::optional<Type *> T0,7168std::optional<Type *> T1) {7169if (!T0)7170return T1;7171if (!T1)7172return T0;7173if (T0 == T1)7174return T0;7175return nullptr;7176}71777178std::optional<Type *> getPrivatizableType() const override {7179return PrivatizableType;7180}71817182const std::string getAsStr(Attributor *A) const override {7183return isAssumedPrivatizablePtr() ? "[priv]" : "[no-priv]";7184}71857186protected:7187std::optional<Type *> PrivatizableType;7188};71897190// TODO: Do this for call site arguments (probably also other values) as well.71917192struct AAPrivatizablePtrArgument final : public AAPrivatizablePtrImpl {7193AAPrivatizablePtrArgument(const IRPosition &IRP, Attributor &A)7194: AAPrivatizablePtrImpl(IRP, A) {}71957196/// See AAPrivatizablePtrImpl::identifyPrivatizableType(...)7197std::optional<Type *> identifyPrivatizableType(Attributor &A) override {7198// If this is a byval argument and we know all the call sites (so we can7199// rewrite them), there is no need to check them explicitly.7200bool UsedAssumedInformation = false;7201SmallVector<Attribute, 1> Attrs;7202A.getAttrs(getIRPosition(), {Attribute::ByVal}, Attrs,7203/* IgnoreSubsumingPositions */ true);7204if (!Attrs.empty() &&7205A.checkForAllCallSites([](AbstractCallSite ACS) { return true; }, *this,7206true, UsedAssumedInformation))7207return Attrs[0].getValueAsType();72087209std::optional<Type *> Ty;7210unsigned ArgNo = getIRPosition().getCallSiteArgNo();72117212// Make sure the associated call site argument has the same type at all call7213// sites and it is an allocation we know is safe to privatize, for now that7214// means we only allow alloca instructions.7215// TODO: We can additionally analyze the accesses in the callee to create7216// the type from that information instead. That is a little more7217// involved and will be done in a follow up patch.7218auto CallSiteCheck = [&](AbstractCallSite ACS) {7219IRPosition ACSArgPos = IRPosition::callsite_argument(ACS, ArgNo);7220// Check if a coresponding argument was found or if it is one not7221// associated (which can happen for callback calls).7222if (ACSArgPos.getPositionKind() == IRPosition::IRP_INVALID)7223return false;72247225// Check that all call sites agree on a type.7226auto *PrivCSArgAA =7227A.getAAFor<AAPrivatizablePtr>(*this, ACSArgPos, DepClassTy::REQUIRED);7228if (!PrivCSArgAA)7229return false;7230std::optional<Type *> CSTy = PrivCSArgAA->getPrivatizableType();72317232LLVM_DEBUG({7233dbgs() << "[AAPrivatizablePtr] ACSPos: " << ACSArgPos << ", CSTy: ";7234if (CSTy && *CSTy)7235(*CSTy)->print(dbgs());7236else if (CSTy)7237dbgs() << "<nullptr>";7238else7239dbgs() << "<none>";7240});72417242Ty = combineTypes(Ty, CSTy);72437244LLVM_DEBUG({7245dbgs() << " : New Type: ";7246if (Ty && *Ty)7247(*Ty)->print(dbgs());7248else if (Ty)7249dbgs() << "<nullptr>";7250else7251dbgs() << "<none>";7252dbgs() << "\n";7253});72547255return !Ty || *Ty;7256};72577258if (!A.checkForAllCallSites(CallSiteCheck, *this, true,7259UsedAssumedInformation))7260return nullptr;7261return Ty;7262}72637264/// See AbstractAttribute::updateImpl(...).7265ChangeStatus updateImpl(Attributor &A) override {7266PrivatizableType = identifyPrivatizableType(A);7267if (!PrivatizableType)7268return ChangeStatus::UNCHANGED;7269if (!*PrivatizableType)7270return indicatePessimisticFixpoint();72717272// The dependence is optional so we don't give up once we give up on the7273// alignment.7274A.getAAFor<AAAlign>(*this, IRPosition::value(getAssociatedValue()),7275DepClassTy::OPTIONAL);72767277// Avoid arguments with padding for now.7278if (!A.hasAttr(getIRPosition(), Attribute::ByVal) &&7279!isDenselyPacked(*PrivatizableType, A.getInfoCache().getDL())) {7280LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] Padding detected\n");7281return indicatePessimisticFixpoint();7282}72837284// Collect the types that will replace the privatizable type in the function7285// signature.7286SmallVector<Type *, 16> ReplacementTypes;7287identifyReplacementTypes(*PrivatizableType, ReplacementTypes);72887289// Verify callee and caller agree on how the promoted argument would be7290// passed.7291Function &Fn = *getIRPosition().getAnchorScope();7292const auto *TTI =7293A.getInfoCache().getAnalysisResultForFunction<TargetIRAnalysis>(Fn);7294if (!TTI) {7295LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] Missing TTI for function "7296<< Fn.getName() << "\n");7297return indicatePessimisticFixpoint();7298}72997300auto CallSiteCheck = [&](AbstractCallSite ACS) {7301CallBase *CB = ACS.getInstruction();7302return TTI->areTypesABICompatible(7303CB->getCaller(),7304dyn_cast_if_present<Function>(CB->getCalledOperand()),7305ReplacementTypes);7306};7307bool UsedAssumedInformation = false;7308if (!A.checkForAllCallSites(CallSiteCheck, *this, true,7309UsedAssumedInformation)) {7310LLVM_DEBUG(7311dbgs() << "[AAPrivatizablePtr] ABI incompatibility detected for "7312<< Fn.getName() << "\n");7313return indicatePessimisticFixpoint();7314}73157316// Register a rewrite of the argument.7317Argument *Arg = getAssociatedArgument();7318if (!A.isValidFunctionSignatureRewrite(*Arg, ReplacementTypes)) {7319LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] Rewrite not valid\n");7320return indicatePessimisticFixpoint();7321}73227323unsigned ArgNo = Arg->getArgNo();73247325// Helper to check if for the given call site the associated argument is7326// passed to a callback where the privatization would be different.7327auto IsCompatiblePrivArgOfCallback = [&](CallBase &CB) {7328SmallVector<const Use *, 4> CallbackUses;7329AbstractCallSite::getCallbackUses(CB, CallbackUses);7330for (const Use *U : CallbackUses) {7331AbstractCallSite CBACS(U);7332assert(CBACS && CBACS.isCallbackCall());7333for (Argument &CBArg : CBACS.getCalledFunction()->args()) {7334int CBArgNo = CBACS.getCallArgOperandNo(CBArg);73357336LLVM_DEBUG({7337dbgs()7338<< "[AAPrivatizablePtr] Argument " << *Arg7339<< "check if can be privatized in the context of its parent ("7340<< Arg->getParent()->getName()7341<< ")\n[AAPrivatizablePtr] because it is an argument in a "7342"callback ("7343<< CBArgNo << "@" << CBACS.getCalledFunction()->getName()7344<< ")\n[AAPrivatizablePtr] " << CBArg << " : "7345<< CBACS.getCallArgOperand(CBArg) << " vs "7346<< CB.getArgOperand(ArgNo) << "\n"7347<< "[AAPrivatizablePtr] " << CBArg << " : "7348<< CBACS.getCallArgOperandNo(CBArg) << " vs " << ArgNo << "\n";7349});73507351if (CBArgNo != int(ArgNo))7352continue;7353const auto *CBArgPrivAA = A.getAAFor<AAPrivatizablePtr>(7354*this, IRPosition::argument(CBArg), DepClassTy::REQUIRED);7355if (CBArgPrivAA && CBArgPrivAA->isValidState()) {7356auto CBArgPrivTy = CBArgPrivAA->getPrivatizableType();7357if (!CBArgPrivTy)7358continue;7359if (*CBArgPrivTy == PrivatizableType)7360continue;7361}73627363LLVM_DEBUG({7364dbgs() << "[AAPrivatizablePtr] Argument " << *Arg7365<< " cannot be privatized in the context of its parent ("7366<< Arg->getParent()->getName()7367<< ")\n[AAPrivatizablePtr] because it is an argument in a "7368"callback ("7369<< CBArgNo << "@" << CBACS.getCalledFunction()->getName()7370<< ").\n[AAPrivatizablePtr] for which the argument "7371"privatization is not compatible.\n";7372});7373return false;7374}7375}7376return true;7377};73787379// Helper to check if for the given call site the associated argument is7380// passed to a direct call where the privatization would be different.7381auto IsCompatiblePrivArgOfDirectCS = [&](AbstractCallSite ACS) {7382CallBase *DC = cast<CallBase>(ACS.getInstruction());7383int DCArgNo = ACS.getCallArgOperandNo(ArgNo);7384assert(DCArgNo >= 0 && unsigned(DCArgNo) < DC->arg_size() &&7385"Expected a direct call operand for callback call operand");73867387Function *DCCallee =7388dyn_cast_if_present<Function>(DC->getCalledOperand());7389LLVM_DEBUG({7390dbgs() << "[AAPrivatizablePtr] Argument " << *Arg7391<< " check if be privatized in the context of its parent ("7392<< Arg->getParent()->getName()7393<< ")\n[AAPrivatizablePtr] because it is an argument in a "7394"direct call of ("7395<< DCArgNo << "@" << DCCallee->getName() << ").\n";7396});73977398if (unsigned(DCArgNo) < DCCallee->arg_size()) {7399const auto *DCArgPrivAA = A.getAAFor<AAPrivatizablePtr>(7400*this, IRPosition::argument(*DCCallee->getArg(DCArgNo)),7401DepClassTy::REQUIRED);7402if (DCArgPrivAA && DCArgPrivAA->isValidState()) {7403auto DCArgPrivTy = DCArgPrivAA->getPrivatizableType();7404if (!DCArgPrivTy)7405return true;7406if (*DCArgPrivTy == PrivatizableType)7407return true;7408}7409}74107411LLVM_DEBUG({7412dbgs() << "[AAPrivatizablePtr] Argument " << *Arg7413<< " cannot be privatized in the context of its parent ("7414<< Arg->getParent()->getName()7415<< ")\n[AAPrivatizablePtr] because it is an argument in a "7416"direct call of ("7417<< ACS.getInstruction()->getCalledOperand()->getName()7418<< ").\n[AAPrivatizablePtr] for which the argument "7419"privatization is not compatible.\n";7420});7421return false;7422};74237424// Helper to check if the associated argument is used at the given abstract7425// call site in a way that is incompatible with the privatization assumed7426// here.7427auto IsCompatiblePrivArgOfOtherCallSite = [&](AbstractCallSite ACS) {7428if (ACS.isDirectCall())7429return IsCompatiblePrivArgOfCallback(*ACS.getInstruction());7430if (ACS.isCallbackCall())7431return IsCompatiblePrivArgOfDirectCS(ACS);7432return false;7433};74347435if (!A.checkForAllCallSites(IsCompatiblePrivArgOfOtherCallSite, *this, true,7436UsedAssumedInformation))7437return indicatePessimisticFixpoint();74387439return ChangeStatus::UNCHANGED;7440}74417442/// Given a type to private \p PrivType, collect the constituates (which are7443/// used) in \p ReplacementTypes.7444static void7445identifyReplacementTypes(Type *PrivType,7446SmallVectorImpl<Type *> &ReplacementTypes) {7447// TODO: For now we expand the privatization type to the fullest which can7448// lead to dead arguments that need to be removed later.7449assert(PrivType && "Expected privatizable type!");74507451// Traverse the type, extract constituate types on the outermost level.7452if (auto *PrivStructType = dyn_cast<StructType>(PrivType)) {7453for (unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++)7454ReplacementTypes.push_back(PrivStructType->getElementType(u));7455} else if (auto *PrivArrayType = dyn_cast<ArrayType>(PrivType)) {7456ReplacementTypes.append(PrivArrayType->getNumElements(),7457PrivArrayType->getElementType());7458} else {7459ReplacementTypes.push_back(PrivType);7460}7461}74627463/// Initialize \p Base according to the type \p PrivType at position \p IP.7464/// The values needed are taken from the arguments of \p F starting at7465/// position \p ArgNo.7466static void createInitialization(Type *PrivType, Value &Base, Function &F,7467unsigned ArgNo, BasicBlock::iterator IP) {7468assert(PrivType && "Expected privatizable type!");74697470IRBuilder<NoFolder> IRB(IP->getParent(), IP);7471const DataLayout &DL = F.getDataLayout();74727473// Traverse the type, build GEPs and stores.7474if (auto *PrivStructType = dyn_cast<StructType>(PrivType)) {7475const StructLayout *PrivStructLayout = DL.getStructLayout(PrivStructType);7476for (unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {7477Value *Ptr =7478constructPointer(&Base, PrivStructLayout->getElementOffset(u), IRB);7479new StoreInst(F.getArg(ArgNo + u), Ptr, IP);7480}7481} else if (auto *PrivArrayType = dyn_cast<ArrayType>(PrivType)) {7482Type *PointeeTy = PrivArrayType->getElementType();7483uint64_t PointeeTySize = DL.getTypeStoreSize(PointeeTy);7484for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {7485Value *Ptr = constructPointer(&Base, u * PointeeTySize, IRB);7486new StoreInst(F.getArg(ArgNo + u), Ptr, IP);7487}7488} else {7489new StoreInst(F.getArg(ArgNo), &Base, IP);7490}7491}74927493/// Extract values from \p Base according to the type \p PrivType at the7494/// call position \p ACS. The values are appended to \p ReplacementValues.7495void createReplacementValues(Align Alignment, Type *PrivType,7496AbstractCallSite ACS, Value *Base,7497SmallVectorImpl<Value *> &ReplacementValues) {7498assert(Base && "Expected base value!");7499assert(PrivType && "Expected privatizable type!");7500Instruction *IP = ACS.getInstruction();75017502IRBuilder<NoFolder> IRB(IP);7503const DataLayout &DL = IP->getDataLayout();75047505// Traverse the type, build GEPs and loads.7506if (auto *PrivStructType = dyn_cast<StructType>(PrivType)) {7507const StructLayout *PrivStructLayout = DL.getStructLayout(PrivStructType);7508for (unsigned u = 0, e = PrivStructType->getNumElements(); u < e; u++) {7509Type *PointeeTy = PrivStructType->getElementType(u);7510Value *Ptr =7511constructPointer(Base, PrivStructLayout->getElementOffset(u), IRB);7512LoadInst *L = new LoadInst(PointeeTy, Ptr, "", IP->getIterator());7513L->setAlignment(Alignment);7514ReplacementValues.push_back(L);7515}7516} else if (auto *PrivArrayType = dyn_cast<ArrayType>(PrivType)) {7517Type *PointeeTy = PrivArrayType->getElementType();7518uint64_t PointeeTySize = DL.getTypeStoreSize(PointeeTy);7519for (unsigned u = 0, e = PrivArrayType->getNumElements(); u < e; u++) {7520Value *Ptr = constructPointer(Base, u * PointeeTySize, IRB);7521LoadInst *L = new LoadInst(PointeeTy, Ptr, "", IP->getIterator());7522L->setAlignment(Alignment);7523ReplacementValues.push_back(L);7524}7525} else {7526LoadInst *L = new LoadInst(PrivType, Base, "", IP->getIterator());7527L->setAlignment(Alignment);7528ReplacementValues.push_back(L);7529}7530}75317532/// See AbstractAttribute::manifest(...)7533ChangeStatus manifest(Attributor &A) override {7534if (!PrivatizableType)7535return ChangeStatus::UNCHANGED;7536assert(*PrivatizableType && "Expected privatizable type!");75377538// Collect all tail calls in the function as we cannot allow new allocas to7539// escape into tail recursion.7540// TODO: Be smarter about new allocas escaping into tail calls.7541SmallVector<CallInst *, 16> TailCalls;7542bool UsedAssumedInformation = false;7543if (!A.checkForAllInstructions(7544[&](Instruction &I) {7545CallInst &CI = cast<CallInst>(I);7546if (CI.isTailCall())7547TailCalls.push_back(&CI);7548return true;7549},7550*this, {Instruction::Call}, UsedAssumedInformation))7551return ChangeStatus::UNCHANGED;75527553Argument *Arg = getAssociatedArgument();7554// Query AAAlign attribute for alignment of associated argument to7555// determine the best alignment of loads.7556const auto *AlignAA =7557A.getAAFor<AAAlign>(*this, IRPosition::value(*Arg), DepClassTy::NONE);75587559// Callback to repair the associated function. A new alloca is placed at the7560// beginning and initialized with the values passed through arguments. The7561// new alloca replaces the use of the old pointer argument.7562Attributor::ArgumentReplacementInfo::CalleeRepairCBTy FnRepairCB =7563[=](const Attributor::ArgumentReplacementInfo &ARI,7564Function &ReplacementFn, Function::arg_iterator ArgIt) {7565BasicBlock &EntryBB = ReplacementFn.getEntryBlock();7566BasicBlock::iterator IP = EntryBB.getFirstInsertionPt();7567const DataLayout &DL = IP->getDataLayout();7568unsigned AS = DL.getAllocaAddrSpace();7569Instruction *AI = new AllocaInst(*PrivatizableType, AS,7570Arg->getName() + ".priv", IP);7571createInitialization(*PrivatizableType, *AI, ReplacementFn,7572ArgIt->getArgNo(), IP);75737574if (AI->getType() != Arg->getType())7575AI = BitCastInst::CreatePointerBitCastOrAddrSpaceCast(7576AI, Arg->getType(), "", IP);7577Arg->replaceAllUsesWith(AI);75787579for (CallInst *CI : TailCalls)7580CI->setTailCall(false);7581};75827583// Callback to repair a call site of the associated function. The elements7584// of the privatizable type are loaded prior to the call and passed to the7585// new function version.7586Attributor::ArgumentReplacementInfo::ACSRepairCBTy ACSRepairCB =7587[=](const Attributor::ArgumentReplacementInfo &ARI,7588AbstractCallSite ACS, SmallVectorImpl<Value *> &NewArgOperands) {7589// When no alignment is specified for the load instruction,7590// natural alignment is assumed.7591createReplacementValues(7592AlignAA ? AlignAA->getAssumedAlign() : Align(0),7593*PrivatizableType, ACS,7594ACS.getCallArgOperand(ARI.getReplacedArg().getArgNo()),7595NewArgOperands);7596};75977598// Collect the types that will replace the privatizable type in the function7599// signature.7600SmallVector<Type *, 16> ReplacementTypes;7601identifyReplacementTypes(*PrivatizableType, ReplacementTypes);76027603// Register a rewrite of the argument.7604if (A.registerFunctionSignatureRewrite(*Arg, ReplacementTypes,7605std::move(FnRepairCB),7606std::move(ACSRepairCB)))7607return ChangeStatus::CHANGED;7608return ChangeStatus::UNCHANGED;7609}76107611/// See AbstractAttribute::trackStatistics()7612void trackStatistics() const override {7613STATS_DECLTRACK_ARG_ATTR(privatizable_ptr);7614}7615};76167617struct AAPrivatizablePtrFloating : public AAPrivatizablePtrImpl {7618AAPrivatizablePtrFloating(const IRPosition &IRP, Attributor &A)7619: AAPrivatizablePtrImpl(IRP, A) {}76207621/// See AbstractAttribute::initialize(...).7622void initialize(Attributor &A) override {7623// TODO: We can privatize more than arguments.7624indicatePessimisticFixpoint();7625}76267627ChangeStatus updateImpl(Attributor &A) override {7628llvm_unreachable("AAPrivatizablePtr(Floating|Returned|CallSiteReturned)::"7629"updateImpl will not be called");7630}76317632/// See AAPrivatizablePtrImpl::identifyPrivatizableType(...)7633std::optional<Type *> identifyPrivatizableType(Attributor &A) override {7634Value *Obj = getUnderlyingObject(&getAssociatedValue());7635if (!Obj) {7636LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] No underlying object found!\n");7637return nullptr;7638}76397640if (auto *AI = dyn_cast<AllocaInst>(Obj))7641if (auto *CI = dyn_cast<ConstantInt>(AI->getArraySize()))7642if (CI->isOne())7643return AI->getAllocatedType();7644if (auto *Arg = dyn_cast<Argument>(Obj)) {7645auto *PrivArgAA = A.getAAFor<AAPrivatizablePtr>(7646*this, IRPosition::argument(*Arg), DepClassTy::REQUIRED);7647if (PrivArgAA && PrivArgAA->isAssumedPrivatizablePtr())7648return PrivArgAA->getPrivatizableType();7649}76507651LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] Underlying object neither valid "7652"alloca nor privatizable argument: "7653<< *Obj << "!\n");7654return nullptr;7655}76567657/// See AbstractAttribute::trackStatistics()7658void trackStatistics() const override {7659STATS_DECLTRACK_FLOATING_ATTR(privatizable_ptr);7660}7661};76627663struct AAPrivatizablePtrCallSiteArgument final7664: public AAPrivatizablePtrFloating {7665AAPrivatizablePtrCallSiteArgument(const IRPosition &IRP, Attributor &A)7666: AAPrivatizablePtrFloating(IRP, A) {}76677668/// See AbstractAttribute::initialize(...).7669void initialize(Attributor &A) override {7670if (A.hasAttr(getIRPosition(), Attribute::ByVal))7671indicateOptimisticFixpoint();7672}76737674/// See AbstractAttribute::updateImpl(...).7675ChangeStatus updateImpl(Attributor &A) override {7676PrivatizableType = identifyPrivatizableType(A);7677if (!PrivatizableType)7678return ChangeStatus::UNCHANGED;7679if (!*PrivatizableType)7680return indicatePessimisticFixpoint();76817682const IRPosition &IRP = getIRPosition();7683bool IsKnownNoCapture;7684bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(7685A, this, IRP, DepClassTy::REQUIRED, IsKnownNoCapture);7686if (!IsAssumedNoCapture) {7687LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] pointer might be captured!\n");7688return indicatePessimisticFixpoint();7689}76907691bool IsKnownNoAlias;7692if (!AA::hasAssumedIRAttr<Attribute::NoAlias>(7693A, this, IRP, DepClassTy::REQUIRED, IsKnownNoAlias)) {7694LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] pointer might alias!\n");7695return indicatePessimisticFixpoint();7696}76977698bool IsKnown;7699if (!AA::isAssumedReadOnly(A, IRP, *this, IsKnown)) {7700LLVM_DEBUG(dbgs() << "[AAPrivatizablePtr] pointer is written!\n");7701return indicatePessimisticFixpoint();7702}77037704return ChangeStatus::UNCHANGED;7705}77067707/// See AbstractAttribute::trackStatistics()7708void trackStatistics() const override {7709STATS_DECLTRACK_CSARG_ATTR(privatizable_ptr);7710}7711};77127713struct AAPrivatizablePtrCallSiteReturned final7714: public AAPrivatizablePtrFloating {7715AAPrivatizablePtrCallSiteReturned(const IRPosition &IRP, Attributor &A)7716: AAPrivatizablePtrFloating(IRP, A) {}77177718/// See AbstractAttribute::initialize(...).7719void initialize(Attributor &A) override {7720// TODO: We can privatize more than arguments.7721indicatePessimisticFixpoint();7722}77237724/// See AbstractAttribute::trackStatistics()7725void trackStatistics() const override {7726STATS_DECLTRACK_CSRET_ATTR(privatizable_ptr);7727}7728};77297730struct AAPrivatizablePtrReturned final : public AAPrivatizablePtrFloating {7731AAPrivatizablePtrReturned(const IRPosition &IRP, Attributor &A)7732: AAPrivatizablePtrFloating(IRP, A) {}77337734/// See AbstractAttribute::initialize(...).7735void initialize(Attributor &A) override {7736// TODO: We can privatize more than arguments.7737indicatePessimisticFixpoint();7738}77397740/// See AbstractAttribute::trackStatistics()7741void trackStatistics() const override {7742STATS_DECLTRACK_FNRET_ATTR(privatizable_ptr);7743}7744};7745} // namespace77467747/// -------------------- Memory Behavior Attributes ----------------------------7748/// Includes read-none, read-only, and write-only.7749/// ----------------------------------------------------------------------------7750namespace {7751struct AAMemoryBehaviorImpl : public AAMemoryBehavior {7752AAMemoryBehaviorImpl(const IRPosition &IRP, Attributor &A)7753: AAMemoryBehavior(IRP, A) {}77547755/// See AbstractAttribute::initialize(...).7756void initialize(Attributor &A) override {7757intersectAssumedBits(BEST_STATE);7758getKnownStateFromValue(A, getIRPosition(), getState());7759AAMemoryBehavior::initialize(A);7760}77617762/// Return the memory behavior information encoded in the IR for \p IRP.7763static void getKnownStateFromValue(Attributor &A, const IRPosition &IRP,7764BitIntegerState &State,7765bool IgnoreSubsumingPositions = false) {7766SmallVector<Attribute, 2> Attrs;7767A.getAttrs(IRP, AttrKinds, Attrs, IgnoreSubsumingPositions);7768for (const Attribute &Attr : Attrs) {7769switch (Attr.getKindAsEnum()) {7770case Attribute::ReadNone:7771State.addKnownBits(NO_ACCESSES);7772break;7773case Attribute::ReadOnly:7774State.addKnownBits(NO_WRITES);7775break;7776case Attribute::WriteOnly:7777State.addKnownBits(NO_READS);7778break;7779default:7780llvm_unreachable("Unexpected attribute!");7781}7782}77837784if (auto *I = dyn_cast<Instruction>(&IRP.getAnchorValue())) {7785if (!I->mayReadFromMemory())7786State.addKnownBits(NO_READS);7787if (!I->mayWriteToMemory())7788State.addKnownBits(NO_WRITES);7789}7790}77917792/// See AbstractAttribute::getDeducedAttributes(...).7793void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,7794SmallVectorImpl<Attribute> &Attrs) const override {7795assert(Attrs.size() == 0);7796if (isAssumedReadNone())7797Attrs.push_back(Attribute::get(Ctx, Attribute::ReadNone));7798else if (isAssumedReadOnly())7799Attrs.push_back(Attribute::get(Ctx, Attribute::ReadOnly));7800else if (isAssumedWriteOnly())7801Attrs.push_back(Attribute::get(Ctx, Attribute::WriteOnly));7802assert(Attrs.size() <= 1);7803}78047805/// See AbstractAttribute::manifest(...).7806ChangeStatus manifest(Attributor &A) override {7807const IRPosition &IRP = getIRPosition();78087809if (A.hasAttr(IRP, Attribute::ReadNone,7810/* IgnoreSubsumingPositions */ true))7811return ChangeStatus::UNCHANGED;78127813// Check if we would improve the existing attributes first.7814SmallVector<Attribute, 4> DeducedAttrs;7815getDeducedAttributes(A, IRP.getAnchorValue().getContext(), DeducedAttrs);7816if (llvm::all_of(DeducedAttrs, [&](const Attribute &Attr) {7817return A.hasAttr(IRP, Attr.getKindAsEnum(),7818/* IgnoreSubsumingPositions */ true);7819}))7820return ChangeStatus::UNCHANGED;78217822// Clear existing attributes.7823A.removeAttrs(IRP, AttrKinds);7824// Clear conflicting writable attribute.7825if (isAssumedReadOnly())7826A.removeAttrs(IRP, Attribute::Writable);78277828// Use the generic manifest method.7829return IRAttribute::manifest(A);7830}78317832/// See AbstractState::getAsStr().7833const std::string getAsStr(Attributor *A) const override {7834if (isAssumedReadNone())7835return "readnone";7836if (isAssumedReadOnly())7837return "readonly";7838if (isAssumedWriteOnly())7839return "writeonly";7840return "may-read/write";7841}78427843/// The set of IR attributes AAMemoryBehavior deals with.7844static const Attribute::AttrKind AttrKinds[3];7845};78467847const Attribute::AttrKind AAMemoryBehaviorImpl::AttrKinds[] = {7848Attribute::ReadNone, Attribute::ReadOnly, Attribute::WriteOnly};78497850/// Memory behavior attribute for a floating value.7851struct AAMemoryBehaviorFloating : AAMemoryBehaviorImpl {7852AAMemoryBehaviorFloating(const IRPosition &IRP, Attributor &A)7853: AAMemoryBehaviorImpl(IRP, A) {}78547855/// See AbstractAttribute::updateImpl(...).7856ChangeStatus updateImpl(Attributor &A) override;78577858/// See AbstractAttribute::trackStatistics()7859void trackStatistics() const override {7860if (isAssumedReadNone())7861STATS_DECLTRACK_FLOATING_ATTR(readnone)7862else if (isAssumedReadOnly())7863STATS_DECLTRACK_FLOATING_ATTR(readonly)7864else if (isAssumedWriteOnly())7865STATS_DECLTRACK_FLOATING_ATTR(writeonly)7866}78677868private:7869/// Return true if users of \p UserI might access the underlying7870/// variable/location described by \p U and should therefore be analyzed.7871bool followUsersOfUseIn(Attributor &A, const Use &U,7872const Instruction *UserI);78737874/// Update the state according to the effect of use \p U in \p UserI.7875void analyzeUseIn(Attributor &A, const Use &U, const Instruction *UserI);7876};78777878/// Memory behavior attribute for function argument.7879struct AAMemoryBehaviorArgument : AAMemoryBehaviorFloating {7880AAMemoryBehaviorArgument(const IRPosition &IRP, Attributor &A)7881: AAMemoryBehaviorFloating(IRP, A) {}78827883/// See AbstractAttribute::initialize(...).7884void initialize(Attributor &A) override {7885intersectAssumedBits(BEST_STATE);7886const IRPosition &IRP = getIRPosition();7887// TODO: Make IgnoreSubsumingPositions a property of an IRAttribute so we7888// can query it when we use has/getAttr. That would allow us to reuse the7889// initialize of the base class here.7890bool HasByVal = A.hasAttr(IRP, {Attribute::ByVal},7891/* IgnoreSubsumingPositions */ true);7892getKnownStateFromValue(A, IRP, getState(),7893/* IgnoreSubsumingPositions */ HasByVal);7894}78957896ChangeStatus manifest(Attributor &A) override {7897// TODO: Pointer arguments are not supported on vectors of pointers yet.7898if (!getAssociatedValue().getType()->isPointerTy())7899return ChangeStatus::UNCHANGED;79007901// TODO: From readattrs.ll: "inalloca parameters are always7902// considered written"7903if (A.hasAttr(getIRPosition(),7904{Attribute::InAlloca, Attribute::Preallocated})) {7905removeKnownBits(NO_WRITES);7906removeAssumedBits(NO_WRITES);7907}7908A.removeAttrs(getIRPosition(), AttrKinds);7909return AAMemoryBehaviorFloating::manifest(A);7910}79117912/// See AbstractAttribute::trackStatistics()7913void trackStatistics() const override {7914if (isAssumedReadNone())7915STATS_DECLTRACK_ARG_ATTR(readnone)7916else if (isAssumedReadOnly())7917STATS_DECLTRACK_ARG_ATTR(readonly)7918else if (isAssumedWriteOnly())7919STATS_DECLTRACK_ARG_ATTR(writeonly)7920}7921};79227923struct AAMemoryBehaviorCallSiteArgument final : AAMemoryBehaviorArgument {7924AAMemoryBehaviorCallSiteArgument(const IRPosition &IRP, Attributor &A)7925: AAMemoryBehaviorArgument(IRP, A) {}79267927/// See AbstractAttribute::initialize(...).7928void initialize(Attributor &A) override {7929// If we don't have an associated attribute this is either a variadic call7930// or an indirect call, either way, nothing to do here.7931Argument *Arg = getAssociatedArgument();7932if (!Arg) {7933indicatePessimisticFixpoint();7934return;7935}7936if (Arg->hasByValAttr()) {7937addKnownBits(NO_WRITES);7938removeKnownBits(NO_READS);7939removeAssumedBits(NO_READS);7940}7941AAMemoryBehaviorArgument::initialize(A);7942if (getAssociatedFunction()->isDeclaration())7943indicatePessimisticFixpoint();7944}79457946/// See AbstractAttribute::updateImpl(...).7947ChangeStatus updateImpl(Attributor &A) override {7948// TODO: Once we have call site specific value information we can provide7949// call site specific liveness liveness information and then it makes7950// sense to specialize attributes for call sites arguments instead of7951// redirecting requests to the callee argument.7952Argument *Arg = getAssociatedArgument();7953const IRPosition &ArgPos = IRPosition::argument(*Arg);7954auto *ArgAA =7955A.getAAFor<AAMemoryBehavior>(*this, ArgPos, DepClassTy::REQUIRED);7956if (!ArgAA)7957return indicatePessimisticFixpoint();7958return clampStateAndIndicateChange(getState(), ArgAA->getState());7959}79607961/// See AbstractAttribute::trackStatistics()7962void trackStatistics() const override {7963if (isAssumedReadNone())7964STATS_DECLTRACK_CSARG_ATTR(readnone)7965else if (isAssumedReadOnly())7966STATS_DECLTRACK_CSARG_ATTR(readonly)7967else if (isAssumedWriteOnly())7968STATS_DECLTRACK_CSARG_ATTR(writeonly)7969}7970};79717972/// Memory behavior attribute for a call site return position.7973struct AAMemoryBehaviorCallSiteReturned final : AAMemoryBehaviorFloating {7974AAMemoryBehaviorCallSiteReturned(const IRPosition &IRP, Attributor &A)7975: AAMemoryBehaviorFloating(IRP, A) {}79767977/// See AbstractAttribute::initialize(...).7978void initialize(Attributor &A) override {7979AAMemoryBehaviorImpl::initialize(A);7980}7981/// See AbstractAttribute::manifest(...).7982ChangeStatus manifest(Attributor &A) override {7983// We do not annotate returned values.7984return ChangeStatus::UNCHANGED;7985}79867987/// See AbstractAttribute::trackStatistics()7988void trackStatistics() const override {}7989};79907991/// An AA to represent the memory behavior function attributes.7992struct AAMemoryBehaviorFunction final : public AAMemoryBehaviorImpl {7993AAMemoryBehaviorFunction(const IRPosition &IRP, Attributor &A)7994: AAMemoryBehaviorImpl(IRP, A) {}79957996/// See AbstractAttribute::updateImpl(Attributor &A).7997ChangeStatus updateImpl(Attributor &A) override;79987999/// See AbstractAttribute::manifest(...).8000ChangeStatus manifest(Attributor &A) override {8001// TODO: It would be better to merge this with AAMemoryLocation, so that8002// we could determine read/write per location. This would also have the8003// benefit of only one place trying to manifest the memory attribute.8004Function &F = cast<Function>(getAnchorValue());8005MemoryEffects ME = MemoryEffects::unknown();8006if (isAssumedReadNone())8007ME = MemoryEffects::none();8008else if (isAssumedReadOnly())8009ME = MemoryEffects::readOnly();8010else if (isAssumedWriteOnly())8011ME = MemoryEffects::writeOnly();80128013A.removeAttrs(getIRPosition(), AttrKinds);8014// Clear conflicting writable attribute.8015if (ME.onlyReadsMemory())8016for (Argument &Arg : F.args())8017A.removeAttrs(IRPosition::argument(Arg), Attribute::Writable);8018return A.manifestAttrs(getIRPosition(),8019Attribute::getWithMemoryEffects(F.getContext(), ME));8020}80218022/// See AbstractAttribute::trackStatistics()8023void trackStatistics() const override {8024if (isAssumedReadNone())8025STATS_DECLTRACK_FN_ATTR(readnone)8026else if (isAssumedReadOnly())8027STATS_DECLTRACK_FN_ATTR(readonly)8028else if (isAssumedWriteOnly())8029STATS_DECLTRACK_FN_ATTR(writeonly)8030}8031};80328033/// AAMemoryBehavior attribute for call sites.8034struct AAMemoryBehaviorCallSite final8035: AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl> {8036AAMemoryBehaviorCallSite(const IRPosition &IRP, Attributor &A)8037: AACalleeToCallSite<AAMemoryBehavior, AAMemoryBehaviorImpl>(IRP, A) {}80388039/// See AbstractAttribute::manifest(...).8040ChangeStatus manifest(Attributor &A) override {8041// TODO: Deduplicate this with AAMemoryBehaviorFunction.8042CallBase &CB = cast<CallBase>(getAnchorValue());8043MemoryEffects ME = MemoryEffects::unknown();8044if (isAssumedReadNone())8045ME = MemoryEffects::none();8046else if (isAssumedReadOnly())8047ME = MemoryEffects::readOnly();8048else if (isAssumedWriteOnly())8049ME = MemoryEffects::writeOnly();80508051A.removeAttrs(getIRPosition(), AttrKinds);8052// Clear conflicting writable attribute.8053if (ME.onlyReadsMemory())8054for (Use &U : CB.args())8055A.removeAttrs(IRPosition::callsite_argument(CB, U.getOperandNo()),8056Attribute::Writable);8057return A.manifestAttrs(8058getIRPosition(), Attribute::getWithMemoryEffects(CB.getContext(), ME));8059}80608061/// See AbstractAttribute::trackStatistics()8062void trackStatistics() const override {8063if (isAssumedReadNone())8064STATS_DECLTRACK_CS_ATTR(readnone)8065else if (isAssumedReadOnly())8066STATS_DECLTRACK_CS_ATTR(readonly)8067else if (isAssumedWriteOnly())8068STATS_DECLTRACK_CS_ATTR(writeonly)8069}8070};80718072ChangeStatus AAMemoryBehaviorFunction::updateImpl(Attributor &A) {80738074// The current assumed state used to determine a change.8075auto AssumedState = getAssumed();80768077auto CheckRWInst = [&](Instruction &I) {8078// If the instruction has an own memory behavior state, use it to restrict8079// the local state. No further analysis is required as the other memory8080// state is as optimistic as it gets.8081if (const auto *CB = dyn_cast<CallBase>(&I)) {8082const auto *MemBehaviorAA = A.getAAFor<AAMemoryBehavior>(8083*this, IRPosition::callsite_function(*CB), DepClassTy::REQUIRED);8084if (MemBehaviorAA) {8085intersectAssumedBits(MemBehaviorAA->getAssumed());8086return !isAtFixpoint();8087}8088}80898090// Remove access kind modifiers if necessary.8091if (I.mayReadFromMemory())8092removeAssumedBits(NO_READS);8093if (I.mayWriteToMemory())8094removeAssumedBits(NO_WRITES);8095return !isAtFixpoint();8096};80978098bool UsedAssumedInformation = false;8099if (!A.checkForAllReadWriteInstructions(CheckRWInst, *this,8100UsedAssumedInformation))8101return indicatePessimisticFixpoint();81028103return (AssumedState != getAssumed()) ? ChangeStatus::CHANGED8104: ChangeStatus::UNCHANGED;8105}81068107ChangeStatus AAMemoryBehaviorFloating::updateImpl(Attributor &A) {81088109const IRPosition &IRP = getIRPosition();8110const IRPosition &FnPos = IRPosition::function_scope(IRP);8111AAMemoryBehavior::StateType &S = getState();81128113// First, check the function scope. We take the known information and we avoid8114// work if the assumed information implies the current assumed information for8115// this attribute. This is a valid for all but byval arguments.8116Argument *Arg = IRP.getAssociatedArgument();8117AAMemoryBehavior::base_t FnMemAssumedState =8118AAMemoryBehavior::StateType::getWorstState();8119if (!Arg || !Arg->hasByValAttr()) {8120const auto *FnMemAA =8121A.getAAFor<AAMemoryBehavior>(*this, FnPos, DepClassTy::OPTIONAL);8122if (FnMemAA) {8123FnMemAssumedState = FnMemAA->getAssumed();8124S.addKnownBits(FnMemAA->getKnown());8125if ((S.getAssumed() & FnMemAA->getAssumed()) == S.getAssumed())8126return ChangeStatus::UNCHANGED;8127}8128}81298130// The current assumed state used to determine a change.8131auto AssumedState = S.getAssumed();81328133// Make sure the value is not captured (except through "return"), if8134// it is, any information derived would be irrelevant anyway as we cannot8135// check the potential aliases introduced by the capture. However, no need8136// to fall back to anythign less optimistic than the function state.8137bool IsKnownNoCapture;8138const AANoCapture *ArgNoCaptureAA = nullptr;8139bool IsAssumedNoCapture = AA::hasAssumedIRAttr<Attribute::NoCapture>(8140A, this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture, false,8141&ArgNoCaptureAA);81428143if (!IsAssumedNoCapture &&8144(!ArgNoCaptureAA || !ArgNoCaptureAA->isAssumedNoCaptureMaybeReturned())) {8145S.intersectAssumedBits(FnMemAssumedState);8146return (AssumedState != getAssumed()) ? ChangeStatus::CHANGED8147: ChangeStatus::UNCHANGED;8148}81498150// Visit and expand uses until all are analyzed or a fixpoint is reached.8151auto UsePred = [&](const Use &U, bool &Follow) -> bool {8152Instruction *UserI = cast<Instruction>(U.getUser());8153LLVM_DEBUG(dbgs() << "[AAMemoryBehavior] Use: " << *U << " in " << *UserI8154<< " \n");81558156// Droppable users, e.g., llvm::assume does not actually perform any action.8157if (UserI->isDroppable())8158return true;81598160// Check if the users of UserI should also be visited.8161Follow = followUsersOfUseIn(A, U, UserI);81628163// If UserI might touch memory we analyze the use in detail.8164if (UserI->mayReadOrWriteMemory())8165analyzeUseIn(A, U, UserI);81668167return !isAtFixpoint();8168};81698170if (!A.checkForAllUses(UsePred, *this, getAssociatedValue()))8171return indicatePessimisticFixpoint();81728173return (AssumedState != getAssumed()) ? ChangeStatus::CHANGED8174: ChangeStatus::UNCHANGED;8175}81768177bool AAMemoryBehaviorFloating::followUsersOfUseIn(Attributor &A, const Use &U,8178const Instruction *UserI) {8179// The loaded value is unrelated to the pointer argument, no need to8180// follow the users of the load.8181if (isa<LoadInst>(UserI) || isa<ReturnInst>(UserI))8182return false;81838184// By default we follow all uses assuming UserI might leak information on U,8185// we have special handling for call sites operands though.8186const auto *CB = dyn_cast<CallBase>(UserI);8187if (!CB || !CB->isArgOperand(&U))8188return true;81898190// If the use is a call argument known not to be captured, the users of8191// the call do not need to be visited because they have to be unrelated to8192// the input. Note that this check is not trivial even though we disallow8193// general capturing of the underlying argument. The reason is that the8194// call might the argument "through return", which we allow and for which we8195// need to check call users.8196if (U.get()->getType()->isPointerTy()) {8197unsigned ArgNo = CB->getArgOperandNo(&U);8198bool IsKnownNoCapture;8199return !AA::hasAssumedIRAttr<Attribute::NoCapture>(8200A, this, IRPosition::callsite_argument(*CB, ArgNo),8201DepClassTy::OPTIONAL, IsKnownNoCapture);8202}82038204return true;8205}82068207void AAMemoryBehaviorFloating::analyzeUseIn(Attributor &A, const Use &U,8208const Instruction *UserI) {8209assert(UserI->mayReadOrWriteMemory());82108211switch (UserI->getOpcode()) {8212default:8213// TODO: Handle all atomics and other side-effect operations we know of.8214break;8215case Instruction::Load:8216// Loads cause the NO_READS property to disappear.8217removeAssumedBits(NO_READS);8218return;82198220case Instruction::Store:8221// Stores cause the NO_WRITES property to disappear if the use is the8222// pointer operand. Note that while capturing was taken care of somewhere8223// else we need to deal with stores of the value that is not looked through.8224if (cast<StoreInst>(UserI)->getPointerOperand() == U.get())8225removeAssumedBits(NO_WRITES);8226else8227indicatePessimisticFixpoint();8228return;82298230case Instruction::Call:8231case Instruction::CallBr:8232case Instruction::Invoke: {8233// For call sites we look at the argument memory behavior attribute (this8234// could be recursive!) in order to restrict our own state.8235const auto *CB = cast<CallBase>(UserI);82368237// Give up on operand bundles.8238if (CB->isBundleOperand(&U)) {8239indicatePessimisticFixpoint();8240return;8241}82428243// Calling a function does read the function pointer, maybe write it if the8244// function is self-modifying.8245if (CB->isCallee(&U)) {8246removeAssumedBits(NO_READS);8247break;8248}82498250// Adjust the possible access behavior based on the information on the8251// argument.8252IRPosition Pos;8253if (U.get()->getType()->isPointerTy())8254Pos = IRPosition::callsite_argument(*CB, CB->getArgOperandNo(&U));8255else8256Pos = IRPosition::callsite_function(*CB);8257const auto *MemBehaviorAA =8258A.getAAFor<AAMemoryBehavior>(*this, Pos, DepClassTy::OPTIONAL);8259if (!MemBehaviorAA)8260break;8261// "assumed" has at most the same bits as the MemBehaviorAA assumed8262// and at least "known".8263intersectAssumedBits(MemBehaviorAA->getAssumed());8264return;8265}8266};82678268// Generally, look at the "may-properties" and adjust the assumed state if we8269// did not trigger special handling before.8270if (UserI->mayReadFromMemory())8271removeAssumedBits(NO_READS);8272if (UserI->mayWriteToMemory())8273removeAssumedBits(NO_WRITES);8274}8275} // namespace82768277/// -------------------- Memory Locations Attributes ---------------------------8278/// Includes read-none, argmemonly, inaccessiblememonly,8279/// inaccessiblememorargmemonly8280/// ----------------------------------------------------------------------------82818282std::string AAMemoryLocation::getMemoryLocationsAsStr(8283AAMemoryLocation::MemoryLocationsKind MLK) {8284if (0 == (MLK & AAMemoryLocation::NO_LOCATIONS))8285return "all memory";8286if (MLK == AAMemoryLocation::NO_LOCATIONS)8287return "no memory";8288std::string S = "memory:";8289if (0 == (MLK & AAMemoryLocation::NO_LOCAL_MEM))8290S += "stack,";8291if (0 == (MLK & AAMemoryLocation::NO_CONST_MEM))8292S += "constant,";8293if (0 == (MLK & AAMemoryLocation::NO_GLOBAL_INTERNAL_MEM))8294S += "internal global,";8295if (0 == (MLK & AAMemoryLocation::NO_GLOBAL_EXTERNAL_MEM))8296S += "external global,";8297if (0 == (MLK & AAMemoryLocation::NO_ARGUMENT_MEM))8298S += "argument,";8299if (0 == (MLK & AAMemoryLocation::NO_INACCESSIBLE_MEM))8300S += "inaccessible,";8301if (0 == (MLK & AAMemoryLocation::NO_MALLOCED_MEM))8302S += "malloced,";8303if (0 == (MLK & AAMemoryLocation::NO_UNKOWN_MEM))8304S += "unknown,";8305S.pop_back();8306return S;8307}83088309namespace {8310struct AAMemoryLocationImpl : public AAMemoryLocation {83118312AAMemoryLocationImpl(const IRPosition &IRP, Attributor &A)8313: AAMemoryLocation(IRP, A), Allocator(A.Allocator) {8314AccessKind2Accesses.fill(nullptr);8315}83168317~AAMemoryLocationImpl() {8318// The AccessSets are allocated via a BumpPtrAllocator, we call8319// the destructor manually.8320for (AccessSet *AS : AccessKind2Accesses)8321if (AS)8322AS->~AccessSet();8323}83248325/// See AbstractAttribute::initialize(...).8326void initialize(Attributor &A) override {8327intersectAssumedBits(BEST_STATE);8328getKnownStateFromValue(A, getIRPosition(), getState());8329AAMemoryLocation::initialize(A);8330}83318332/// Return the memory behavior information encoded in the IR for \p IRP.8333static void getKnownStateFromValue(Attributor &A, const IRPosition &IRP,8334BitIntegerState &State,8335bool IgnoreSubsumingPositions = false) {8336// For internal functions we ignore `argmemonly` and8337// `inaccessiblememorargmemonly` as we might break it via interprocedural8338// constant propagation. It is unclear if this is the best way but it is8339// unlikely this will cause real performance problems. If we are deriving8340// attributes for the anchor function we even remove the attribute in8341// addition to ignoring it.8342// TODO: A better way to handle this would be to add ~NO_GLOBAL_MEM /8343// MemoryEffects::Other as a possible location.8344bool UseArgMemOnly = true;8345Function *AnchorFn = IRP.getAnchorScope();8346if (AnchorFn && A.isRunOn(*AnchorFn))8347UseArgMemOnly = !AnchorFn->hasLocalLinkage();83488349SmallVector<Attribute, 2> Attrs;8350A.getAttrs(IRP, {Attribute::Memory}, Attrs, IgnoreSubsumingPositions);8351for (const Attribute &Attr : Attrs) {8352// TODO: We can map MemoryEffects to Attributor locations more precisely.8353MemoryEffects ME = Attr.getMemoryEffects();8354if (ME.doesNotAccessMemory()) {8355State.addKnownBits(NO_LOCAL_MEM | NO_CONST_MEM);8356continue;8357}8358if (ME.onlyAccessesInaccessibleMem()) {8359State.addKnownBits(inverseLocation(NO_INACCESSIBLE_MEM, true, true));8360continue;8361}8362if (ME.onlyAccessesArgPointees()) {8363if (UseArgMemOnly)8364State.addKnownBits(inverseLocation(NO_ARGUMENT_MEM, true, true));8365else {8366// Remove location information, only keep read/write info.8367ME = MemoryEffects(ME.getModRef());8368A.manifestAttrs(IRP,8369Attribute::getWithMemoryEffects(8370IRP.getAnchorValue().getContext(), ME),8371/*ForceReplace*/ true);8372}8373continue;8374}8375if (ME.onlyAccessesInaccessibleOrArgMem()) {8376if (UseArgMemOnly)8377State.addKnownBits(inverseLocation(8378NO_INACCESSIBLE_MEM | NO_ARGUMENT_MEM, true, true));8379else {8380// Remove location information, only keep read/write info.8381ME = MemoryEffects(ME.getModRef());8382A.manifestAttrs(IRP,8383Attribute::getWithMemoryEffects(8384IRP.getAnchorValue().getContext(), ME),8385/*ForceReplace*/ true);8386}8387continue;8388}8389}8390}83918392/// See AbstractAttribute::getDeducedAttributes(...).8393void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,8394SmallVectorImpl<Attribute> &Attrs) const override {8395// TODO: We can map Attributor locations to MemoryEffects more precisely.8396assert(Attrs.size() == 0);8397if (getIRPosition().getPositionKind() == IRPosition::IRP_FUNCTION) {8398if (isAssumedReadNone())8399Attrs.push_back(8400Attribute::getWithMemoryEffects(Ctx, MemoryEffects::none()));8401else if (isAssumedInaccessibleMemOnly())8402Attrs.push_back(Attribute::getWithMemoryEffects(8403Ctx, MemoryEffects::inaccessibleMemOnly()));8404else if (isAssumedArgMemOnly())8405Attrs.push_back(8406Attribute::getWithMemoryEffects(Ctx, MemoryEffects::argMemOnly()));8407else if (isAssumedInaccessibleOrArgMemOnly())8408Attrs.push_back(Attribute::getWithMemoryEffects(8409Ctx, MemoryEffects::inaccessibleOrArgMemOnly()));8410}8411assert(Attrs.size() <= 1);8412}84138414/// See AbstractAttribute::manifest(...).8415ChangeStatus manifest(Attributor &A) override {8416// TODO: If AAMemoryLocation and AAMemoryBehavior are merged, we could8417// provide per-location modref information here.8418const IRPosition &IRP = getIRPosition();84198420SmallVector<Attribute, 1> DeducedAttrs;8421getDeducedAttributes(A, IRP.getAnchorValue().getContext(), DeducedAttrs);8422if (DeducedAttrs.size() != 1)8423return ChangeStatus::UNCHANGED;8424MemoryEffects ME = DeducedAttrs[0].getMemoryEffects();84258426return A.manifestAttrs(IRP, Attribute::getWithMemoryEffects(8427IRP.getAnchorValue().getContext(), ME));8428}84298430/// See AAMemoryLocation::checkForAllAccessesToMemoryKind(...).8431bool checkForAllAccessesToMemoryKind(8432function_ref<bool(const Instruction *, const Value *, AccessKind,8433MemoryLocationsKind)>8434Pred,8435MemoryLocationsKind RequestedMLK) const override {8436if (!isValidState())8437return false;84388439MemoryLocationsKind AssumedMLK = getAssumedNotAccessedLocation();8440if (AssumedMLK == NO_LOCATIONS)8441return true;84428443unsigned Idx = 0;8444for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS;8445CurMLK *= 2, ++Idx) {8446if (CurMLK & RequestedMLK)8447continue;84488449if (const AccessSet *Accesses = AccessKind2Accesses[Idx])8450for (const AccessInfo &AI : *Accesses)8451if (!Pred(AI.I, AI.Ptr, AI.Kind, CurMLK))8452return false;8453}84548455return true;8456}84578458ChangeStatus indicatePessimisticFixpoint() override {8459// If we give up and indicate a pessimistic fixpoint this instruction will8460// become an access for all potential access kinds:8461// TODO: Add pointers for argmemonly and globals to improve the results of8462// checkForAllAccessesToMemoryKind.8463bool Changed = false;8464MemoryLocationsKind KnownMLK = getKnown();8465Instruction *I = dyn_cast<Instruction>(&getAssociatedValue());8466for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2)8467if (!(CurMLK & KnownMLK))8468updateStateAndAccessesMap(getState(), CurMLK, I, nullptr, Changed,8469getAccessKindFromInst(I));8470return AAMemoryLocation::indicatePessimisticFixpoint();8471}84728473protected:8474/// Helper struct to tie together an instruction that has a read or write8475/// effect with the pointer it accesses (if any).8476struct AccessInfo {84778478/// The instruction that caused the access.8479const Instruction *I;84808481/// The base pointer that is accessed, or null if unknown.8482const Value *Ptr;84838484/// The kind of access (read/write/read+write).8485AccessKind Kind;84868487bool operator==(const AccessInfo &RHS) const {8488return I == RHS.I && Ptr == RHS.Ptr && Kind == RHS.Kind;8489}8490bool operator()(const AccessInfo &LHS, const AccessInfo &RHS) const {8491if (LHS.I != RHS.I)8492return LHS.I < RHS.I;8493if (LHS.Ptr != RHS.Ptr)8494return LHS.Ptr < RHS.Ptr;8495if (LHS.Kind != RHS.Kind)8496return LHS.Kind < RHS.Kind;8497return false;8498}8499};85008501/// Mapping from *single* memory location kinds, e.g., LOCAL_MEM with the8502/// value of NO_LOCAL_MEM, to the accesses encountered for this memory kind.8503using AccessSet = SmallSet<AccessInfo, 2, AccessInfo>;8504std::array<AccessSet *, llvm::CTLog2<VALID_STATE>()> AccessKind2Accesses;85058506/// Categorize the pointer arguments of CB that might access memory in8507/// AccessedLoc and update the state and access map accordingly.8508void8509categorizeArgumentPointerLocations(Attributor &A, CallBase &CB,8510AAMemoryLocation::StateType &AccessedLocs,8511bool &Changed);85128513/// Return the kind(s) of location that may be accessed by \p V.8514AAMemoryLocation::MemoryLocationsKind8515categorizeAccessedLocations(Attributor &A, Instruction &I, bool &Changed);85168517/// Return the access kind as determined by \p I.8518AccessKind getAccessKindFromInst(const Instruction *I) {8519AccessKind AK = READ_WRITE;8520if (I) {8521AK = I->mayReadFromMemory() ? READ : NONE;8522AK = AccessKind(AK | (I->mayWriteToMemory() ? WRITE : NONE));8523}8524return AK;8525}85268527/// Update the state \p State and the AccessKind2Accesses given that \p I is8528/// an access of kind \p AK to a \p MLK memory location with the access8529/// pointer \p Ptr.8530void updateStateAndAccessesMap(AAMemoryLocation::StateType &State,8531MemoryLocationsKind MLK, const Instruction *I,8532const Value *Ptr, bool &Changed,8533AccessKind AK = READ_WRITE) {85348535assert(isPowerOf2_32(MLK) && "Expected a single location set!");8536auto *&Accesses = AccessKind2Accesses[llvm::Log2_32(MLK)];8537if (!Accesses)8538Accesses = new (Allocator) AccessSet();8539Changed |= Accesses->insert(AccessInfo{I, Ptr, AK}).second;8540if (MLK == NO_UNKOWN_MEM)8541MLK = NO_LOCATIONS;8542State.removeAssumedBits(MLK);8543}85448545/// Determine the underlying locations kinds for \p Ptr, e.g., globals or8546/// arguments, and update the state and access map accordingly.8547void categorizePtrValue(Attributor &A, const Instruction &I, const Value &Ptr,8548AAMemoryLocation::StateType &State, bool &Changed,8549unsigned AccessAS = 0);85508551/// Used to allocate access sets.8552BumpPtrAllocator &Allocator;8553};85548555void AAMemoryLocationImpl::categorizePtrValue(8556Attributor &A, const Instruction &I, const Value &Ptr,8557AAMemoryLocation::StateType &State, bool &Changed, unsigned AccessAS) {8558LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Categorize pointer locations for "8559<< Ptr << " ["8560<< getMemoryLocationsAsStr(State.getAssumed()) << "]\n");85618562auto Pred = [&](Value &Obj) {8563unsigned ObjectAS = Obj.getType()->getPointerAddressSpace();8564// TODO: recognize the TBAA used for constant accesses.8565MemoryLocationsKind MLK = NO_LOCATIONS;85668567// Filter accesses to constant (GPU) memory if we have an AS at the access8568// site or the object is known to actually have the associated AS.8569if ((AccessAS == (unsigned)AA::GPUAddressSpace::Constant ||8570(ObjectAS == (unsigned)AA::GPUAddressSpace::Constant &&8571isIdentifiedObject(&Obj))) &&8572AA::isGPU(*I.getModule()))8573return true;85748575if (isa<UndefValue>(&Obj))8576return true;8577if (isa<Argument>(&Obj)) {8578// TODO: For now we do not treat byval arguments as local copies performed8579// on the call edge, though, we should. To make that happen we need to8580// teach various passes, e.g., DSE, about the copy effect of a byval. That8581// would also allow us to mark functions only accessing byval arguments as8582// readnone again, arguably their accesses have no effect outside of the8583// function, like accesses to allocas.8584MLK = NO_ARGUMENT_MEM;8585} else if (auto *GV = dyn_cast<GlobalValue>(&Obj)) {8586// Reading constant memory is not treated as a read "effect" by the8587// function attr pass so we won't neither. Constants defined by TBAA are8588// similar. (We know we do not write it because it is constant.)8589if (auto *GVar = dyn_cast<GlobalVariable>(GV))8590if (GVar->isConstant())8591return true;85928593if (GV->hasLocalLinkage())8594MLK = NO_GLOBAL_INTERNAL_MEM;8595else8596MLK = NO_GLOBAL_EXTERNAL_MEM;8597} else if (isa<ConstantPointerNull>(&Obj) &&8598(!NullPointerIsDefined(getAssociatedFunction(), AccessAS) ||8599!NullPointerIsDefined(getAssociatedFunction(), ObjectAS))) {8600return true;8601} else if (isa<AllocaInst>(&Obj)) {8602MLK = NO_LOCAL_MEM;8603} else if (const auto *CB = dyn_cast<CallBase>(&Obj)) {8604bool IsKnownNoAlias;8605if (AA::hasAssumedIRAttr<Attribute::NoAlias>(8606A, this, IRPosition::callsite_returned(*CB), DepClassTy::OPTIONAL,8607IsKnownNoAlias))8608MLK = NO_MALLOCED_MEM;8609else8610MLK = NO_UNKOWN_MEM;8611} else {8612MLK = NO_UNKOWN_MEM;8613}86148615assert(MLK != NO_LOCATIONS && "No location specified!");8616LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Ptr value can be categorized: "8617<< Obj << " -> " << getMemoryLocationsAsStr(MLK) << "\n");8618updateStateAndAccessesMap(State, MLK, &I, &Obj, Changed,8619getAccessKindFromInst(&I));86208621return true;8622};86238624const auto *AA = A.getAAFor<AAUnderlyingObjects>(8625*this, IRPosition::value(Ptr), DepClassTy::OPTIONAL);8626if (!AA || !AA->forallUnderlyingObjects(Pred, AA::Intraprocedural)) {8627LLVM_DEBUG(8628dbgs() << "[AAMemoryLocation] Pointer locations not categorized\n");8629updateStateAndAccessesMap(State, NO_UNKOWN_MEM, &I, nullptr, Changed,8630getAccessKindFromInst(&I));8631return;8632}86338634LLVM_DEBUG(8635dbgs() << "[AAMemoryLocation] Accessed locations with pointer locations: "8636<< getMemoryLocationsAsStr(State.getAssumed()) << "\n");8637}86388639void AAMemoryLocationImpl::categorizeArgumentPointerLocations(8640Attributor &A, CallBase &CB, AAMemoryLocation::StateType &AccessedLocs,8641bool &Changed) {8642for (unsigned ArgNo = 0, E = CB.arg_size(); ArgNo < E; ++ArgNo) {86438644// Skip non-pointer arguments.8645const Value *ArgOp = CB.getArgOperand(ArgNo);8646if (!ArgOp->getType()->isPtrOrPtrVectorTy())8647continue;86488649// Skip readnone arguments.8650const IRPosition &ArgOpIRP = IRPosition::callsite_argument(CB, ArgNo);8651const auto *ArgOpMemLocationAA =8652A.getAAFor<AAMemoryBehavior>(*this, ArgOpIRP, DepClassTy::OPTIONAL);86538654if (ArgOpMemLocationAA && ArgOpMemLocationAA->isAssumedReadNone())8655continue;86568657// Categorize potentially accessed pointer arguments as if there was an8658// access instruction with them as pointer.8659categorizePtrValue(A, CB, *ArgOp, AccessedLocs, Changed);8660}8661}86628663AAMemoryLocation::MemoryLocationsKind8664AAMemoryLocationImpl::categorizeAccessedLocations(Attributor &A, Instruction &I,8665bool &Changed) {8666LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Categorize accessed locations for "8667<< I << "\n");86688669AAMemoryLocation::StateType AccessedLocs;8670AccessedLocs.intersectAssumedBits(NO_LOCATIONS);86718672if (auto *CB = dyn_cast<CallBase>(&I)) {86738674// First check if we assume any memory is access is visible.8675const auto *CBMemLocationAA = A.getAAFor<AAMemoryLocation>(8676*this, IRPosition::callsite_function(*CB), DepClassTy::OPTIONAL);8677LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Categorize call site: " << I8678<< " [" << CBMemLocationAA << "]\n");8679if (!CBMemLocationAA) {8680updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &I, nullptr,8681Changed, getAccessKindFromInst(&I));8682return NO_UNKOWN_MEM;8683}86848685if (CBMemLocationAA->isAssumedReadNone())8686return NO_LOCATIONS;86878688if (CBMemLocationAA->isAssumedInaccessibleMemOnly()) {8689updateStateAndAccessesMap(AccessedLocs, NO_INACCESSIBLE_MEM, &I, nullptr,8690Changed, getAccessKindFromInst(&I));8691return AccessedLocs.getAssumed();8692}86938694uint32_t CBAssumedNotAccessedLocs =8695CBMemLocationAA->getAssumedNotAccessedLocation();86968697// Set the argmemonly and global bit as we handle them separately below.8698uint32_t CBAssumedNotAccessedLocsNoArgMem =8699CBAssumedNotAccessedLocs | NO_ARGUMENT_MEM | NO_GLOBAL_MEM;87008701for (MemoryLocationsKind CurMLK = 1; CurMLK < NO_LOCATIONS; CurMLK *= 2) {8702if (CBAssumedNotAccessedLocsNoArgMem & CurMLK)8703continue;8704updateStateAndAccessesMap(AccessedLocs, CurMLK, &I, nullptr, Changed,8705getAccessKindFromInst(&I));8706}87078708// Now handle global memory if it might be accessed. This is slightly tricky8709// as NO_GLOBAL_MEM has multiple bits set.8710bool HasGlobalAccesses = ((~CBAssumedNotAccessedLocs) & NO_GLOBAL_MEM);8711if (HasGlobalAccesses) {8712auto AccessPred = [&](const Instruction *, const Value *Ptr,8713AccessKind Kind, MemoryLocationsKind MLK) {8714updateStateAndAccessesMap(AccessedLocs, MLK, &I, Ptr, Changed,8715getAccessKindFromInst(&I));8716return true;8717};8718if (!CBMemLocationAA->checkForAllAccessesToMemoryKind(8719AccessPred, inverseLocation(NO_GLOBAL_MEM, false, false)))8720return AccessedLocs.getWorstState();8721}87228723LLVM_DEBUG(8724dbgs() << "[AAMemoryLocation] Accessed state before argument handling: "8725<< getMemoryLocationsAsStr(AccessedLocs.getAssumed()) << "\n");87268727// Now handle argument memory if it might be accessed.8728bool HasArgAccesses = ((~CBAssumedNotAccessedLocs) & NO_ARGUMENT_MEM);8729if (HasArgAccesses)8730categorizeArgumentPointerLocations(A, *CB, AccessedLocs, Changed);87318732LLVM_DEBUG(8733dbgs() << "[AAMemoryLocation] Accessed state after argument handling: "8734<< getMemoryLocationsAsStr(AccessedLocs.getAssumed()) << "\n");87358736return AccessedLocs.getAssumed();8737}87388739if (const Value *Ptr = getPointerOperand(&I, /* AllowVolatile */ true)) {8740LLVM_DEBUG(8741dbgs() << "[AAMemoryLocation] Categorize memory access with pointer: "8742<< I << " [" << *Ptr << "]\n");8743categorizePtrValue(A, I, *Ptr, AccessedLocs, Changed,8744Ptr->getType()->getPointerAddressSpace());8745return AccessedLocs.getAssumed();8746}87478748LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Failed to categorize instruction: "8749<< I << "\n");8750updateStateAndAccessesMap(AccessedLocs, NO_UNKOWN_MEM, &I, nullptr, Changed,8751getAccessKindFromInst(&I));8752return AccessedLocs.getAssumed();8753}87548755/// An AA to represent the memory behavior function attributes.8756struct AAMemoryLocationFunction final : public AAMemoryLocationImpl {8757AAMemoryLocationFunction(const IRPosition &IRP, Attributor &A)8758: AAMemoryLocationImpl(IRP, A) {}87598760/// See AbstractAttribute::updateImpl(Attributor &A).8761ChangeStatus updateImpl(Attributor &A) override {87628763const auto *MemBehaviorAA =8764A.getAAFor<AAMemoryBehavior>(*this, getIRPosition(), DepClassTy::NONE);8765if (MemBehaviorAA && MemBehaviorAA->isAssumedReadNone()) {8766if (MemBehaviorAA->isKnownReadNone())8767return indicateOptimisticFixpoint();8768assert(isAssumedReadNone() &&8769"AAMemoryLocation was not read-none but AAMemoryBehavior was!");8770A.recordDependence(*MemBehaviorAA, *this, DepClassTy::OPTIONAL);8771return ChangeStatus::UNCHANGED;8772}87738774// The current assumed state used to determine a change.8775auto AssumedState = getAssumed();8776bool Changed = false;87778778auto CheckRWInst = [&](Instruction &I) {8779MemoryLocationsKind MLK = categorizeAccessedLocations(A, I, Changed);8780LLVM_DEBUG(dbgs() << "[AAMemoryLocation] Accessed locations for " << I8781<< ": " << getMemoryLocationsAsStr(MLK) << "\n");8782removeAssumedBits(inverseLocation(MLK, false, false));8783// Stop once only the valid bit set in the *not assumed location*, thus8784// once we don't actually exclude any memory locations in the state.8785return getAssumedNotAccessedLocation() != VALID_STATE;8786};87878788bool UsedAssumedInformation = false;8789if (!A.checkForAllReadWriteInstructions(CheckRWInst, *this,8790UsedAssumedInformation))8791return indicatePessimisticFixpoint();87928793Changed |= AssumedState != getAssumed();8794return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;8795}87968797/// See AbstractAttribute::trackStatistics()8798void trackStatistics() const override {8799if (isAssumedReadNone())8800STATS_DECLTRACK_FN_ATTR(readnone)8801else if (isAssumedArgMemOnly())8802STATS_DECLTRACK_FN_ATTR(argmemonly)8803else if (isAssumedInaccessibleMemOnly())8804STATS_DECLTRACK_FN_ATTR(inaccessiblememonly)8805else if (isAssumedInaccessibleOrArgMemOnly())8806STATS_DECLTRACK_FN_ATTR(inaccessiblememorargmemonly)8807}8808};88098810/// AAMemoryLocation attribute for call sites.8811struct AAMemoryLocationCallSite final : AAMemoryLocationImpl {8812AAMemoryLocationCallSite(const IRPosition &IRP, Attributor &A)8813: AAMemoryLocationImpl(IRP, A) {}88148815/// See AbstractAttribute::updateImpl(...).8816ChangeStatus updateImpl(Attributor &A) override {8817// TODO: Once we have call site specific value information we can provide8818// call site specific liveness liveness information and then it makes8819// sense to specialize attributes for call sites arguments instead of8820// redirecting requests to the callee argument.8821Function *F = getAssociatedFunction();8822const IRPosition &FnPos = IRPosition::function(*F);8823auto *FnAA =8824A.getAAFor<AAMemoryLocation>(*this, FnPos, DepClassTy::REQUIRED);8825if (!FnAA)8826return indicatePessimisticFixpoint();8827bool Changed = false;8828auto AccessPred = [&](const Instruction *I, const Value *Ptr,8829AccessKind Kind, MemoryLocationsKind MLK) {8830updateStateAndAccessesMap(getState(), MLK, I, Ptr, Changed,8831getAccessKindFromInst(I));8832return true;8833};8834if (!FnAA->checkForAllAccessesToMemoryKind(AccessPred, ALL_LOCATIONS))8835return indicatePessimisticFixpoint();8836return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;8837}88388839/// See AbstractAttribute::trackStatistics()8840void trackStatistics() const override {8841if (isAssumedReadNone())8842STATS_DECLTRACK_CS_ATTR(readnone)8843}8844};8845} // namespace88468847/// ------------------ denormal-fp-math Attribute -------------------------88488849namespace {8850struct AADenormalFPMathImpl : public AADenormalFPMath {8851AADenormalFPMathImpl(const IRPosition &IRP, Attributor &A)8852: AADenormalFPMath(IRP, A) {}88538854const std::string getAsStr(Attributor *A) const override {8855std::string Str("AADenormalFPMath[");8856raw_string_ostream OS(Str);88578858DenormalState Known = getKnown();8859if (Known.Mode.isValid())8860OS << "denormal-fp-math=" << Known.Mode;8861else8862OS << "invalid";88638864if (Known.ModeF32.isValid())8865OS << " denormal-fp-math-f32=" << Known.ModeF32;8866OS << ']';8867return Str;8868}8869};88708871struct AADenormalFPMathFunction final : AADenormalFPMathImpl {8872AADenormalFPMathFunction(const IRPosition &IRP, Attributor &A)8873: AADenormalFPMathImpl(IRP, A) {}88748875void initialize(Attributor &A) override {8876const Function *F = getAnchorScope();8877DenormalMode Mode = F->getDenormalModeRaw();8878DenormalMode ModeF32 = F->getDenormalModeF32Raw();88798880// TODO: Handling this here prevents handling the case where a callee has a8881// fixed denormal-fp-math with dynamic denormal-fp-math-f32, but called from8882// a function with a fully fixed mode.8883if (ModeF32 == DenormalMode::getInvalid())8884ModeF32 = Mode;8885Known = DenormalState{Mode, ModeF32};8886if (isModeFixed())8887indicateFixpoint();8888}88898890ChangeStatus updateImpl(Attributor &A) override {8891ChangeStatus Change = ChangeStatus::UNCHANGED;88928893auto CheckCallSite = [=, &Change, &A](AbstractCallSite CS) {8894Function *Caller = CS.getInstruction()->getFunction();8895LLVM_DEBUG(dbgs() << "[AADenormalFPMath] Call " << Caller->getName()8896<< "->" << getAssociatedFunction()->getName() << '\n');88978898const auto *CallerInfo = A.getAAFor<AADenormalFPMath>(8899*this, IRPosition::function(*Caller), DepClassTy::REQUIRED);8900if (!CallerInfo)8901return false;89028903Change = Change | clampStateAndIndicateChange(this->getState(),8904CallerInfo->getState());8905return true;8906};89078908bool AllCallSitesKnown = true;8909if (!A.checkForAllCallSites(CheckCallSite, *this, true, AllCallSitesKnown))8910return indicatePessimisticFixpoint();89118912if (Change == ChangeStatus::CHANGED && isModeFixed())8913indicateFixpoint();8914return Change;8915}89168917ChangeStatus manifest(Attributor &A) override {8918LLVMContext &Ctx = getAssociatedFunction()->getContext();89198920SmallVector<Attribute, 2> AttrToAdd;8921SmallVector<StringRef, 2> AttrToRemove;8922if (Known.Mode == DenormalMode::getDefault()) {8923AttrToRemove.push_back("denormal-fp-math");8924} else {8925AttrToAdd.push_back(8926Attribute::get(Ctx, "denormal-fp-math", Known.Mode.str()));8927}89288929if (Known.ModeF32 != Known.Mode) {8930AttrToAdd.push_back(8931Attribute::get(Ctx, "denormal-fp-math-f32", Known.ModeF32.str()));8932} else {8933AttrToRemove.push_back("denormal-fp-math-f32");8934}89358936auto &IRP = getIRPosition();89378938// TODO: There should be a combined add and remove API.8939return A.removeAttrs(IRP, AttrToRemove) |8940A.manifestAttrs(IRP, AttrToAdd, /*ForceReplace=*/true);8941}89428943void trackStatistics() const override {8944STATS_DECLTRACK_FN_ATTR(denormal_fp_math)8945}8946};8947} // namespace89488949/// ------------------ Value Constant Range Attribute -------------------------89508951namespace {8952struct AAValueConstantRangeImpl : AAValueConstantRange {8953using StateType = IntegerRangeState;8954AAValueConstantRangeImpl(const IRPosition &IRP, Attributor &A)8955: AAValueConstantRange(IRP, A) {}89568957/// See AbstractAttribute::initialize(..).8958void initialize(Attributor &A) override {8959if (A.hasSimplificationCallback(getIRPosition())) {8960indicatePessimisticFixpoint();8961return;8962}89638964// Intersect a range given by SCEV.8965intersectKnown(getConstantRangeFromSCEV(A, getCtxI()));89668967// Intersect a range given by LVI.8968intersectKnown(getConstantRangeFromLVI(A, getCtxI()));8969}89708971/// See AbstractAttribute::getAsStr().8972const std::string getAsStr(Attributor *A) const override {8973std::string Str;8974llvm::raw_string_ostream OS(Str);8975OS << "range(" << getBitWidth() << ")<";8976getKnown().print(OS);8977OS << " / ";8978getAssumed().print(OS);8979OS << ">";8980return Str;8981}89828983/// Helper function to get a SCEV expr for the associated value at program8984/// point \p I.8985const SCEV *getSCEV(Attributor &A, const Instruction *I = nullptr) const {8986if (!getAnchorScope())8987return nullptr;89888989ScalarEvolution *SE =8990A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(8991*getAnchorScope());89928993LoopInfo *LI = A.getInfoCache().getAnalysisResultForFunction<LoopAnalysis>(8994*getAnchorScope());89958996if (!SE || !LI)8997return nullptr;89988999const SCEV *S = SE->getSCEV(&getAssociatedValue());9000if (!I)9001return S;90029003return SE->getSCEVAtScope(S, LI->getLoopFor(I->getParent()));9004}90059006/// Helper function to get a range from SCEV for the associated value at9007/// program point \p I.9008ConstantRange getConstantRangeFromSCEV(Attributor &A,9009const Instruction *I = nullptr) const {9010if (!getAnchorScope())9011return getWorstState(getBitWidth());90129013ScalarEvolution *SE =9014A.getInfoCache().getAnalysisResultForFunction<ScalarEvolutionAnalysis>(9015*getAnchorScope());90169017const SCEV *S = getSCEV(A, I);9018if (!SE || !S)9019return getWorstState(getBitWidth());90209021return SE->getUnsignedRange(S);9022}90239024/// Helper function to get a range from LVI for the associated value at9025/// program point \p I.9026ConstantRange9027getConstantRangeFromLVI(Attributor &A,9028const Instruction *CtxI = nullptr) const {9029if (!getAnchorScope())9030return getWorstState(getBitWidth());90319032LazyValueInfo *LVI =9033A.getInfoCache().getAnalysisResultForFunction<LazyValueAnalysis>(9034*getAnchorScope());90359036if (!LVI || !CtxI)9037return getWorstState(getBitWidth());9038return LVI->getConstantRange(&getAssociatedValue(),9039const_cast<Instruction *>(CtxI),9040/*UndefAllowed*/ false);9041}90429043/// Return true if \p CtxI is valid for querying outside analyses.9044/// This basically makes sure we do not ask intra-procedural analysis9045/// about a context in the wrong function or a context that violates9046/// dominance assumptions they might have. The \p AllowAACtxI flag indicates9047/// if the original context of this AA is OK or should be considered invalid.9048bool isValidCtxInstructionForOutsideAnalysis(Attributor &A,9049const Instruction *CtxI,9050bool AllowAACtxI) const {9051if (!CtxI || (!AllowAACtxI && CtxI == getCtxI()))9052return false;90539054// Our context might be in a different function, neither intra-procedural9055// analysis (ScalarEvolution nor LazyValueInfo) can handle that.9056if (!AA::isValidInScope(getAssociatedValue(), CtxI->getFunction()))9057return false;90589059// If the context is not dominated by the value there are paths to the9060// context that do not define the value. This cannot be handled by9061// LazyValueInfo so we need to bail.9062if (auto *I = dyn_cast<Instruction>(&getAssociatedValue())) {9063InformationCache &InfoCache = A.getInfoCache();9064const DominatorTree *DT =9065InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(9066*I->getFunction());9067return DT && DT->dominates(I, CtxI);9068}90699070return true;9071}90729073/// See AAValueConstantRange::getKnownConstantRange(..).9074ConstantRange9075getKnownConstantRange(Attributor &A,9076const Instruction *CtxI = nullptr) const override {9077if (!isValidCtxInstructionForOutsideAnalysis(A, CtxI,9078/* AllowAACtxI */ false))9079return getKnown();90809081ConstantRange LVIR = getConstantRangeFromLVI(A, CtxI);9082ConstantRange SCEVR = getConstantRangeFromSCEV(A, CtxI);9083return getKnown().intersectWith(SCEVR).intersectWith(LVIR);9084}90859086/// See AAValueConstantRange::getAssumedConstantRange(..).9087ConstantRange9088getAssumedConstantRange(Attributor &A,9089const Instruction *CtxI = nullptr) const override {9090// TODO: Make SCEV use Attributor assumption.9091// We may be able to bound a variable range via assumptions in9092// Attributor. ex.) If x is assumed to be in [1, 3] and y is known to9093// evolve to x^2 + x, then we can say that y is in [2, 12].9094if (!isValidCtxInstructionForOutsideAnalysis(A, CtxI,9095/* AllowAACtxI */ false))9096return getAssumed();90979098ConstantRange LVIR = getConstantRangeFromLVI(A, CtxI);9099ConstantRange SCEVR = getConstantRangeFromSCEV(A, CtxI);9100return getAssumed().intersectWith(SCEVR).intersectWith(LVIR);9101}91029103/// Helper function to create MDNode for range metadata.9104static MDNode *9105getMDNodeForConstantRange(Type *Ty, LLVMContext &Ctx,9106const ConstantRange &AssumedConstantRange) {9107Metadata *LowAndHigh[] = {ConstantAsMetadata::get(ConstantInt::get(9108Ty, AssumedConstantRange.getLower())),9109ConstantAsMetadata::get(ConstantInt::get(9110Ty, AssumedConstantRange.getUpper()))};9111return MDNode::get(Ctx, LowAndHigh);9112}91139114/// Return true if \p Assumed is included in \p KnownRanges.9115static bool isBetterRange(const ConstantRange &Assumed, MDNode *KnownRanges) {91169117if (Assumed.isFullSet())9118return false;91199120if (!KnownRanges)9121return true;91229123// If multiple ranges are annotated in IR, we give up to annotate assumed9124// range for now.91259126// TODO: If there exists a known range which containts assumed range, we9127// can say assumed range is better.9128if (KnownRanges->getNumOperands() > 2)9129return false;91309131ConstantInt *Lower =9132mdconst::extract<ConstantInt>(KnownRanges->getOperand(0));9133ConstantInt *Upper =9134mdconst::extract<ConstantInt>(KnownRanges->getOperand(1));91359136ConstantRange Known(Lower->getValue(), Upper->getValue());9137return Known.contains(Assumed) && Known != Assumed;9138}91399140/// Helper function to set range metadata.9141static bool9142setRangeMetadataIfisBetterRange(Instruction *I,9143const ConstantRange &AssumedConstantRange) {9144auto *OldRangeMD = I->getMetadata(LLVMContext::MD_range);9145if (isBetterRange(AssumedConstantRange, OldRangeMD)) {9146if (!AssumedConstantRange.isEmptySet()) {9147I->setMetadata(LLVMContext::MD_range,9148getMDNodeForConstantRange(I->getType(), I->getContext(),9149AssumedConstantRange));9150return true;9151}9152}9153return false;9154}91559156/// See AbstractAttribute::manifest()9157ChangeStatus manifest(Attributor &A) override {9158ChangeStatus Changed = ChangeStatus::UNCHANGED;9159ConstantRange AssumedConstantRange = getAssumedConstantRange(A);9160assert(!AssumedConstantRange.isFullSet() && "Invalid state");91619162auto &V = getAssociatedValue();9163if (!AssumedConstantRange.isEmptySet() &&9164!AssumedConstantRange.isSingleElement()) {9165if (Instruction *I = dyn_cast<Instruction>(&V)) {9166assert(I == getCtxI() && "Should not annotate an instruction which is "9167"not the context instruction");9168if (isa<CallInst>(I) || isa<LoadInst>(I))9169if (setRangeMetadataIfisBetterRange(I, AssumedConstantRange))9170Changed = ChangeStatus::CHANGED;9171}9172}91739174return Changed;9175}9176};91779178struct AAValueConstantRangeArgument final9179: AAArgumentFromCallSiteArguments<9180AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,9181true /* BridgeCallBaseContext */> {9182using Base = AAArgumentFromCallSiteArguments<9183AAValueConstantRange, AAValueConstantRangeImpl, IntegerRangeState,9184true /* BridgeCallBaseContext */>;9185AAValueConstantRangeArgument(const IRPosition &IRP, Attributor &A)9186: Base(IRP, A) {}91879188/// See AbstractAttribute::trackStatistics()9189void trackStatistics() const override {9190STATS_DECLTRACK_ARG_ATTR(value_range)9191}9192};91939194struct AAValueConstantRangeReturned9195: AAReturnedFromReturnedValues<AAValueConstantRange,9196AAValueConstantRangeImpl,9197AAValueConstantRangeImpl::StateType,9198/* PropogateCallBaseContext */ true> {9199using Base =9200AAReturnedFromReturnedValues<AAValueConstantRange,9201AAValueConstantRangeImpl,9202AAValueConstantRangeImpl::StateType,9203/* PropogateCallBaseContext */ true>;9204AAValueConstantRangeReturned(const IRPosition &IRP, Attributor &A)9205: Base(IRP, A) {}92069207/// See AbstractAttribute::initialize(...).9208void initialize(Attributor &A) override {9209if (!A.isFunctionIPOAmendable(*getAssociatedFunction()))9210indicatePessimisticFixpoint();9211}92129213/// See AbstractAttribute::trackStatistics()9214void trackStatistics() const override {9215STATS_DECLTRACK_FNRET_ATTR(value_range)9216}9217};92189219struct AAValueConstantRangeFloating : AAValueConstantRangeImpl {9220AAValueConstantRangeFloating(const IRPosition &IRP, Attributor &A)9221: AAValueConstantRangeImpl(IRP, A) {}92229223/// See AbstractAttribute::initialize(...).9224void initialize(Attributor &A) override {9225AAValueConstantRangeImpl::initialize(A);9226if (isAtFixpoint())9227return;92289229Value &V = getAssociatedValue();92309231if (auto *C = dyn_cast<ConstantInt>(&V)) {9232unionAssumed(ConstantRange(C->getValue()));9233indicateOptimisticFixpoint();9234return;9235}92369237if (isa<UndefValue>(&V)) {9238// Collapse the undef state to 0.9239unionAssumed(ConstantRange(APInt(getBitWidth(), 0)));9240indicateOptimisticFixpoint();9241return;9242}92439244if (isa<CallBase>(&V))9245return;92469247if (isa<BinaryOperator>(&V) || isa<CmpInst>(&V) || isa<CastInst>(&V))9248return;92499250// If it is a load instruction with range metadata, use it.9251if (LoadInst *LI = dyn_cast<LoadInst>(&V))9252if (auto *RangeMD = LI->getMetadata(LLVMContext::MD_range)) {9253intersectKnown(getConstantRangeFromMetadata(*RangeMD));9254return;9255}92569257// We can work with PHI and select instruction as we traverse their operands9258// during update.9259if (isa<SelectInst>(V) || isa<PHINode>(V))9260return;92619262// Otherwise we give up.9263indicatePessimisticFixpoint();92649265LLVM_DEBUG(dbgs() << "[AAValueConstantRange] We give up: "9266<< getAssociatedValue() << "\n");9267}92689269bool calculateBinaryOperator(9270Attributor &A, BinaryOperator *BinOp, IntegerRangeState &T,9271const Instruction *CtxI,9272SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {9273Value *LHS = BinOp->getOperand(0);9274Value *RHS = BinOp->getOperand(1);92759276// Simplify the operands first.9277bool UsedAssumedInformation = false;9278const auto &SimplifiedLHS = A.getAssumedSimplified(9279IRPosition::value(*LHS, getCallBaseContext()), *this,9280UsedAssumedInformation, AA::Interprocedural);9281if (!SimplifiedLHS.has_value())9282return true;9283if (!*SimplifiedLHS)9284return false;9285LHS = *SimplifiedLHS;92869287const auto &SimplifiedRHS = A.getAssumedSimplified(9288IRPosition::value(*RHS, getCallBaseContext()), *this,9289UsedAssumedInformation, AA::Interprocedural);9290if (!SimplifiedRHS.has_value())9291return true;9292if (!*SimplifiedRHS)9293return false;9294RHS = *SimplifiedRHS;92959296// TODO: Allow non integers as well.9297if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy())9298return false;92999300auto *LHSAA = A.getAAFor<AAValueConstantRange>(9301*this, IRPosition::value(*LHS, getCallBaseContext()),9302DepClassTy::REQUIRED);9303if (!LHSAA)9304return false;9305QuerriedAAs.push_back(LHSAA);9306auto LHSAARange = LHSAA->getAssumedConstantRange(A, CtxI);93079308auto *RHSAA = A.getAAFor<AAValueConstantRange>(9309*this, IRPosition::value(*RHS, getCallBaseContext()),9310DepClassTy::REQUIRED);9311if (!RHSAA)9312return false;9313QuerriedAAs.push_back(RHSAA);9314auto RHSAARange = RHSAA->getAssumedConstantRange(A, CtxI);93159316auto AssumedRange = LHSAARange.binaryOp(BinOp->getOpcode(), RHSAARange);93179318T.unionAssumed(AssumedRange);93199320// TODO: Track a known state too.93219322return T.isValidState();9323}93249325bool calculateCastInst(9326Attributor &A, CastInst *CastI, IntegerRangeState &T,9327const Instruction *CtxI,9328SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {9329assert(CastI->getNumOperands() == 1 && "Expected cast to be unary!");9330// TODO: Allow non integers as well.9331Value *OpV = CastI->getOperand(0);93329333// Simplify the operand first.9334bool UsedAssumedInformation = false;9335const auto &SimplifiedOpV = A.getAssumedSimplified(9336IRPosition::value(*OpV, getCallBaseContext()), *this,9337UsedAssumedInformation, AA::Interprocedural);9338if (!SimplifiedOpV.has_value())9339return true;9340if (!*SimplifiedOpV)9341return false;9342OpV = *SimplifiedOpV;93439344if (!OpV->getType()->isIntegerTy())9345return false;93469347auto *OpAA = A.getAAFor<AAValueConstantRange>(9348*this, IRPosition::value(*OpV, getCallBaseContext()),9349DepClassTy::REQUIRED);9350if (!OpAA)9351return false;9352QuerriedAAs.push_back(OpAA);9353T.unionAssumed(OpAA->getAssumed().castOp(CastI->getOpcode(),9354getState().getBitWidth()));9355return T.isValidState();9356}93579358bool9359calculateCmpInst(Attributor &A, CmpInst *CmpI, IntegerRangeState &T,9360const Instruction *CtxI,9361SmallVectorImpl<const AAValueConstantRange *> &QuerriedAAs) {9362Value *LHS = CmpI->getOperand(0);9363Value *RHS = CmpI->getOperand(1);93649365// Simplify the operands first.9366bool UsedAssumedInformation = false;9367const auto &SimplifiedLHS = A.getAssumedSimplified(9368IRPosition::value(*LHS, getCallBaseContext()), *this,9369UsedAssumedInformation, AA::Interprocedural);9370if (!SimplifiedLHS.has_value())9371return true;9372if (!*SimplifiedLHS)9373return false;9374LHS = *SimplifiedLHS;93759376const auto &SimplifiedRHS = A.getAssumedSimplified(9377IRPosition::value(*RHS, getCallBaseContext()), *this,9378UsedAssumedInformation, AA::Interprocedural);9379if (!SimplifiedRHS.has_value())9380return true;9381if (!*SimplifiedRHS)9382return false;9383RHS = *SimplifiedRHS;93849385// TODO: Allow non integers as well.9386if (!LHS->getType()->isIntegerTy() || !RHS->getType()->isIntegerTy())9387return false;93889389auto *LHSAA = A.getAAFor<AAValueConstantRange>(9390*this, IRPosition::value(*LHS, getCallBaseContext()),9391DepClassTy::REQUIRED);9392if (!LHSAA)9393return false;9394QuerriedAAs.push_back(LHSAA);9395auto *RHSAA = A.getAAFor<AAValueConstantRange>(9396*this, IRPosition::value(*RHS, getCallBaseContext()),9397DepClassTy::REQUIRED);9398if (!RHSAA)9399return false;9400QuerriedAAs.push_back(RHSAA);9401auto LHSAARange = LHSAA->getAssumedConstantRange(A, CtxI);9402auto RHSAARange = RHSAA->getAssumedConstantRange(A, CtxI);94039404// If one of them is empty set, we can't decide.9405if (LHSAARange.isEmptySet() || RHSAARange.isEmptySet())9406return true;94079408bool MustTrue = false, MustFalse = false;94099410auto AllowedRegion =9411ConstantRange::makeAllowedICmpRegion(CmpI->getPredicate(), RHSAARange);94129413if (AllowedRegion.intersectWith(LHSAARange).isEmptySet())9414MustFalse = true;94159416if (LHSAARange.icmp(CmpI->getPredicate(), RHSAARange))9417MustTrue = true;94189419assert((!MustTrue || !MustFalse) &&9420"Either MustTrue or MustFalse should be false!");94219422if (MustTrue)9423T.unionAssumed(ConstantRange(APInt(/* numBits */ 1, /* val */ 1)));9424else if (MustFalse)9425T.unionAssumed(ConstantRange(APInt(/* numBits */ 1, /* val */ 0)));9426else9427T.unionAssumed(ConstantRange(/* BitWidth */ 1, /* isFullSet */ true));94289429LLVM_DEBUG(dbgs() << "[AAValueConstantRange] " << *CmpI << " after "9430<< (MustTrue ? "true" : (MustFalse ? "false" : "unknown"))9431<< ": " << T << "\n\t" << *LHSAA << "\t<op>\n\t"9432<< *RHSAA);94339434// TODO: Track a known state too.9435return T.isValidState();9436}94379438/// See AbstractAttribute::updateImpl(...).9439ChangeStatus updateImpl(Attributor &A) override {94409441IntegerRangeState T(getBitWidth());9442auto VisitValueCB = [&](Value &V, const Instruction *CtxI) -> bool {9443Instruction *I = dyn_cast<Instruction>(&V);9444if (!I || isa<CallBase>(I)) {94459446// Simplify the operand first.9447bool UsedAssumedInformation = false;9448const auto &SimplifiedOpV = A.getAssumedSimplified(9449IRPosition::value(V, getCallBaseContext()), *this,9450UsedAssumedInformation, AA::Interprocedural);9451if (!SimplifiedOpV.has_value())9452return true;9453if (!*SimplifiedOpV)9454return false;9455Value *VPtr = *SimplifiedOpV;94569457// If the value is not instruction, we query AA to Attributor.9458const auto *AA = A.getAAFor<AAValueConstantRange>(9459*this, IRPosition::value(*VPtr, getCallBaseContext()),9460DepClassTy::REQUIRED);94619462// Clamp operator is not used to utilize a program point CtxI.9463if (AA)9464T.unionAssumed(AA->getAssumedConstantRange(A, CtxI));9465else9466return false;94679468return T.isValidState();9469}94709471SmallVector<const AAValueConstantRange *, 4> QuerriedAAs;9472if (auto *BinOp = dyn_cast<BinaryOperator>(I)) {9473if (!calculateBinaryOperator(A, BinOp, T, CtxI, QuerriedAAs))9474return false;9475} else if (auto *CmpI = dyn_cast<CmpInst>(I)) {9476if (!calculateCmpInst(A, CmpI, T, CtxI, QuerriedAAs))9477return false;9478} else if (auto *CastI = dyn_cast<CastInst>(I)) {9479if (!calculateCastInst(A, CastI, T, CtxI, QuerriedAAs))9480return false;9481} else {9482// Give up with other instructions.9483// TODO: Add other instructions94849485T.indicatePessimisticFixpoint();9486return false;9487}94889489// Catch circular reasoning in a pessimistic way for now.9490// TODO: Check how the range evolves and if we stripped anything, see also9491// AADereferenceable or AAAlign for similar situations.9492for (const AAValueConstantRange *QueriedAA : QuerriedAAs) {9493if (QueriedAA != this)9494continue;9495// If we are in a stady state we do not need to worry.9496if (T.getAssumed() == getState().getAssumed())9497continue;9498T.indicatePessimisticFixpoint();9499}95009501return T.isValidState();9502};95039504if (!VisitValueCB(getAssociatedValue(), getCtxI()))9505return indicatePessimisticFixpoint();95069507// Ensure that long def-use chains can't cause circular reasoning either by9508// introducing a cutoff below.9509if (clampStateAndIndicateChange(getState(), T) == ChangeStatus::UNCHANGED)9510return ChangeStatus::UNCHANGED;9511if (++NumChanges > MaxNumChanges) {9512LLVM_DEBUG(dbgs() << "[AAValueConstantRange] performed " << NumChanges9513<< " but only " << MaxNumChanges9514<< " are allowed to avoid cyclic reasoning.");9515return indicatePessimisticFixpoint();9516}9517return ChangeStatus::CHANGED;9518}95199520/// See AbstractAttribute::trackStatistics()9521void trackStatistics() const override {9522STATS_DECLTRACK_FLOATING_ATTR(value_range)9523}95249525/// Tracker to bail after too many widening steps of the constant range.9526int NumChanges = 0;95279528/// Upper bound for the number of allowed changes (=widening steps) for the9529/// constant range before we give up.9530static constexpr int MaxNumChanges = 5;9531};95329533struct AAValueConstantRangeFunction : AAValueConstantRangeImpl {9534AAValueConstantRangeFunction(const IRPosition &IRP, Attributor &A)9535: AAValueConstantRangeImpl(IRP, A) {}95369537/// See AbstractAttribute::initialize(...).9538ChangeStatus updateImpl(Attributor &A) override {9539llvm_unreachable("AAValueConstantRange(Function|CallSite)::updateImpl will "9540"not be called");9541}95429543/// See AbstractAttribute::trackStatistics()9544void trackStatistics() const override { STATS_DECLTRACK_FN_ATTR(value_range) }9545};95469547struct AAValueConstantRangeCallSite : AAValueConstantRangeFunction {9548AAValueConstantRangeCallSite(const IRPosition &IRP, Attributor &A)9549: AAValueConstantRangeFunction(IRP, A) {}95509551/// See AbstractAttribute::trackStatistics()9552void trackStatistics() const override { STATS_DECLTRACK_CS_ATTR(value_range) }9553};95549555struct AAValueConstantRangeCallSiteReturned9556: AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,9557AAValueConstantRangeImpl::StateType,9558/* IntroduceCallBaseContext */ true> {9559AAValueConstantRangeCallSiteReturned(const IRPosition &IRP, Attributor &A)9560: AACalleeToCallSite<AAValueConstantRange, AAValueConstantRangeImpl,9561AAValueConstantRangeImpl::StateType,9562/* IntroduceCallBaseContext */ true>(IRP, A) {}95639564/// See AbstractAttribute::initialize(...).9565void initialize(Attributor &A) override {9566// If it is a load instruction with range metadata, use the metadata.9567if (CallInst *CI = dyn_cast<CallInst>(&getAssociatedValue()))9568if (auto *RangeMD = CI->getMetadata(LLVMContext::MD_range))9569intersectKnown(getConstantRangeFromMetadata(*RangeMD));95709571AAValueConstantRangeImpl::initialize(A);9572}95739574/// See AbstractAttribute::trackStatistics()9575void trackStatistics() const override {9576STATS_DECLTRACK_CSRET_ATTR(value_range)9577}9578};9579struct AAValueConstantRangeCallSiteArgument : AAValueConstantRangeFloating {9580AAValueConstantRangeCallSiteArgument(const IRPosition &IRP, Attributor &A)9581: AAValueConstantRangeFloating(IRP, A) {}95829583/// See AbstractAttribute::manifest()9584ChangeStatus manifest(Attributor &A) override {9585return ChangeStatus::UNCHANGED;9586}95879588/// See AbstractAttribute::trackStatistics()9589void trackStatistics() const override {9590STATS_DECLTRACK_CSARG_ATTR(value_range)9591}9592};9593} // namespace95949595/// ------------------ Potential Values Attribute -------------------------95969597namespace {9598struct AAPotentialConstantValuesImpl : AAPotentialConstantValues {9599using StateType = PotentialConstantIntValuesState;96009601AAPotentialConstantValuesImpl(const IRPosition &IRP, Attributor &A)9602: AAPotentialConstantValues(IRP, A) {}96039604/// See AbstractAttribute::initialize(..).9605void initialize(Attributor &A) override {9606if (A.hasSimplificationCallback(getIRPosition()))9607indicatePessimisticFixpoint();9608else9609AAPotentialConstantValues::initialize(A);9610}96119612bool fillSetWithConstantValues(Attributor &A, const IRPosition &IRP, SetTy &S,9613bool &ContainsUndef, bool ForSelf) {9614SmallVector<AA::ValueAndContext> Values;9615bool UsedAssumedInformation = false;9616if (!A.getAssumedSimplifiedValues(IRP, *this, Values, AA::Interprocedural,9617UsedAssumedInformation)) {9618// Avoid recursion when the caller is computing constant values for this9619// IRP itself.9620if (ForSelf)9621return false;9622if (!IRP.getAssociatedType()->isIntegerTy())9623return false;9624auto *PotentialValuesAA = A.getAAFor<AAPotentialConstantValues>(9625*this, IRP, DepClassTy::REQUIRED);9626if (!PotentialValuesAA || !PotentialValuesAA->getState().isValidState())9627return false;9628ContainsUndef = PotentialValuesAA->getState().undefIsContained();9629S = PotentialValuesAA->getState().getAssumedSet();9630return true;9631}96329633// Copy all the constant values, except UndefValue. ContainsUndef is true9634// iff Values contains only UndefValue instances. If there are other known9635// constants, then UndefValue is dropped.9636ContainsUndef = false;9637for (auto &It : Values) {9638if (isa<UndefValue>(It.getValue())) {9639ContainsUndef = true;9640continue;9641}9642auto *CI = dyn_cast<ConstantInt>(It.getValue());9643if (!CI)9644return false;9645S.insert(CI->getValue());9646}9647ContainsUndef &= S.empty();96489649return true;9650}96519652/// See AbstractAttribute::getAsStr().9653const std::string getAsStr(Attributor *A) const override {9654std::string Str;9655llvm::raw_string_ostream OS(Str);9656OS << getState();9657return Str;9658}96599660/// See AbstractAttribute::updateImpl(...).9661ChangeStatus updateImpl(Attributor &A) override {9662return indicatePessimisticFixpoint();9663}9664};96659666struct AAPotentialConstantValuesArgument final9667: AAArgumentFromCallSiteArguments<AAPotentialConstantValues,9668AAPotentialConstantValuesImpl,9669PotentialConstantIntValuesState> {9670using Base = AAArgumentFromCallSiteArguments<AAPotentialConstantValues,9671AAPotentialConstantValuesImpl,9672PotentialConstantIntValuesState>;9673AAPotentialConstantValuesArgument(const IRPosition &IRP, Attributor &A)9674: Base(IRP, A) {}96759676/// See AbstractAttribute::trackStatistics()9677void trackStatistics() const override {9678STATS_DECLTRACK_ARG_ATTR(potential_values)9679}9680};96819682struct AAPotentialConstantValuesReturned9683: AAReturnedFromReturnedValues<AAPotentialConstantValues,9684AAPotentialConstantValuesImpl> {9685using Base = AAReturnedFromReturnedValues<AAPotentialConstantValues,9686AAPotentialConstantValuesImpl>;9687AAPotentialConstantValuesReturned(const IRPosition &IRP, Attributor &A)9688: Base(IRP, A) {}96899690void initialize(Attributor &A) override {9691if (!A.isFunctionIPOAmendable(*getAssociatedFunction()))9692indicatePessimisticFixpoint();9693Base::initialize(A);9694}96959696/// See AbstractAttribute::trackStatistics()9697void trackStatistics() const override {9698STATS_DECLTRACK_FNRET_ATTR(potential_values)9699}9700};97019702struct AAPotentialConstantValuesFloating : AAPotentialConstantValuesImpl {9703AAPotentialConstantValuesFloating(const IRPosition &IRP, Attributor &A)9704: AAPotentialConstantValuesImpl(IRP, A) {}97059706/// See AbstractAttribute::initialize(..).9707void initialize(Attributor &A) override {9708AAPotentialConstantValuesImpl::initialize(A);9709if (isAtFixpoint())9710return;97119712Value &V = getAssociatedValue();97139714if (auto *C = dyn_cast<ConstantInt>(&V)) {9715unionAssumed(C->getValue());9716indicateOptimisticFixpoint();9717return;9718}97199720if (isa<UndefValue>(&V)) {9721unionAssumedWithUndef();9722indicateOptimisticFixpoint();9723return;9724}97259726if (isa<BinaryOperator>(&V) || isa<ICmpInst>(&V) || isa<CastInst>(&V))9727return;97289729if (isa<SelectInst>(V) || isa<PHINode>(V) || isa<LoadInst>(V))9730return;97319732indicatePessimisticFixpoint();97339734LLVM_DEBUG(dbgs() << "[AAPotentialConstantValues] We give up: "9735<< getAssociatedValue() << "\n");9736}97379738static bool calculateICmpInst(const ICmpInst *ICI, const APInt &LHS,9739const APInt &RHS) {9740return ICmpInst::compare(LHS, RHS, ICI->getPredicate());9741}97429743static APInt calculateCastInst(const CastInst *CI, const APInt &Src,9744uint32_t ResultBitWidth) {9745Instruction::CastOps CastOp = CI->getOpcode();9746switch (CastOp) {9747default:9748llvm_unreachable("unsupported or not integer cast");9749case Instruction::Trunc:9750return Src.trunc(ResultBitWidth);9751case Instruction::SExt:9752return Src.sext(ResultBitWidth);9753case Instruction::ZExt:9754return Src.zext(ResultBitWidth);9755case Instruction::BitCast:9756return Src;9757}9758}97599760static APInt calculateBinaryOperator(const BinaryOperator *BinOp,9761const APInt &LHS, const APInt &RHS,9762bool &SkipOperation, bool &Unsupported) {9763Instruction::BinaryOps BinOpcode = BinOp->getOpcode();9764// Unsupported is set to true when the binary operator is not supported.9765// SkipOperation is set to true when UB occur with the given operand pair9766// (LHS, RHS).9767// TODO: we should look at nsw and nuw keywords to handle operations9768// that create poison or undef value.9769switch (BinOpcode) {9770default:9771Unsupported = true;9772return LHS;9773case Instruction::Add:9774return LHS + RHS;9775case Instruction::Sub:9776return LHS - RHS;9777case Instruction::Mul:9778return LHS * RHS;9779case Instruction::UDiv:9780if (RHS.isZero()) {9781SkipOperation = true;9782return LHS;9783}9784return LHS.udiv(RHS);9785case Instruction::SDiv:9786if (RHS.isZero()) {9787SkipOperation = true;9788return LHS;9789}9790return LHS.sdiv(RHS);9791case Instruction::URem:9792if (RHS.isZero()) {9793SkipOperation = true;9794return LHS;9795}9796return LHS.urem(RHS);9797case Instruction::SRem:9798if (RHS.isZero()) {9799SkipOperation = true;9800return LHS;9801}9802return LHS.srem(RHS);9803case Instruction::Shl:9804return LHS.shl(RHS);9805case Instruction::LShr:9806return LHS.lshr(RHS);9807case Instruction::AShr:9808return LHS.ashr(RHS);9809case Instruction::And:9810return LHS & RHS;9811case Instruction::Or:9812return LHS | RHS;9813case Instruction::Xor:9814return LHS ^ RHS;9815}9816}98179818bool calculateBinaryOperatorAndTakeUnion(const BinaryOperator *BinOp,9819const APInt &LHS, const APInt &RHS) {9820bool SkipOperation = false;9821bool Unsupported = false;9822APInt Result =9823calculateBinaryOperator(BinOp, LHS, RHS, SkipOperation, Unsupported);9824if (Unsupported)9825return false;9826// If SkipOperation is true, we can ignore this operand pair (L, R).9827if (!SkipOperation)9828unionAssumed(Result);9829return isValidState();9830}98319832ChangeStatus updateWithICmpInst(Attributor &A, ICmpInst *ICI) {9833auto AssumedBefore = getAssumed();9834Value *LHS = ICI->getOperand(0);9835Value *RHS = ICI->getOperand(1);98369837bool LHSContainsUndef = false, RHSContainsUndef = false;9838SetTy LHSAAPVS, RHSAAPVS;9839if (!fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS,9840LHSContainsUndef, /* ForSelf */ false) ||9841!fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS,9842RHSContainsUndef, /* ForSelf */ false))9843return indicatePessimisticFixpoint();98449845// TODO: make use of undef flag to limit potential values aggressively.9846bool MaybeTrue = false, MaybeFalse = false;9847const APInt Zero(RHS->getType()->getIntegerBitWidth(), 0);9848if (LHSContainsUndef && RHSContainsUndef) {9849// The result of any comparison between undefs can be soundly replaced9850// with undef.9851unionAssumedWithUndef();9852} else if (LHSContainsUndef) {9853for (const APInt &R : RHSAAPVS) {9854bool CmpResult = calculateICmpInst(ICI, Zero, R);9855MaybeTrue |= CmpResult;9856MaybeFalse |= !CmpResult;9857if (MaybeTrue & MaybeFalse)9858return indicatePessimisticFixpoint();9859}9860} else if (RHSContainsUndef) {9861for (const APInt &L : LHSAAPVS) {9862bool CmpResult = calculateICmpInst(ICI, L, Zero);9863MaybeTrue |= CmpResult;9864MaybeFalse |= !CmpResult;9865if (MaybeTrue & MaybeFalse)9866return indicatePessimisticFixpoint();9867}9868} else {9869for (const APInt &L : LHSAAPVS) {9870for (const APInt &R : RHSAAPVS) {9871bool CmpResult = calculateICmpInst(ICI, L, R);9872MaybeTrue |= CmpResult;9873MaybeFalse |= !CmpResult;9874if (MaybeTrue & MaybeFalse)9875return indicatePessimisticFixpoint();9876}9877}9878}9879if (MaybeTrue)9880unionAssumed(APInt(/* numBits */ 1, /* val */ 1));9881if (MaybeFalse)9882unionAssumed(APInt(/* numBits */ 1, /* val */ 0));9883return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED9884: ChangeStatus::CHANGED;9885}98869887ChangeStatus updateWithSelectInst(Attributor &A, SelectInst *SI) {9888auto AssumedBefore = getAssumed();9889Value *LHS = SI->getTrueValue();9890Value *RHS = SI->getFalseValue();98919892bool UsedAssumedInformation = false;9893std::optional<Constant *> C = A.getAssumedConstant(9894*SI->getCondition(), *this, UsedAssumedInformation);98959896// Check if we only need one operand.9897bool OnlyLeft = false, OnlyRight = false;9898if (C && *C && (*C)->isOneValue())9899OnlyLeft = true;9900else if (C && *C && (*C)->isZeroValue())9901OnlyRight = true;99029903bool LHSContainsUndef = false, RHSContainsUndef = false;9904SetTy LHSAAPVS, RHSAAPVS;9905if (!OnlyRight &&9906!fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS,9907LHSContainsUndef, /* ForSelf */ false))9908return indicatePessimisticFixpoint();99099910if (!OnlyLeft &&9911!fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS,9912RHSContainsUndef, /* ForSelf */ false))9913return indicatePessimisticFixpoint();99149915if (OnlyLeft || OnlyRight) {9916// select (true/false), lhs, rhs9917auto *OpAA = OnlyLeft ? &LHSAAPVS : &RHSAAPVS;9918auto Undef = OnlyLeft ? LHSContainsUndef : RHSContainsUndef;99199920if (Undef)9921unionAssumedWithUndef();9922else {9923for (const auto &It : *OpAA)9924unionAssumed(It);9925}99269927} else if (LHSContainsUndef && RHSContainsUndef) {9928// select i1 *, undef , undef => undef9929unionAssumedWithUndef();9930} else {9931for (const auto &It : LHSAAPVS)9932unionAssumed(It);9933for (const auto &It : RHSAAPVS)9934unionAssumed(It);9935}9936return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED9937: ChangeStatus::CHANGED;9938}99399940ChangeStatus updateWithCastInst(Attributor &A, CastInst *CI) {9941auto AssumedBefore = getAssumed();9942if (!CI->isIntegerCast())9943return indicatePessimisticFixpoint();9944assert(CI->getNumOperands() == 1 && "Expected cast to be unary!");9945uint32_t ResultBitWidth = CI->getDestTy()->getIntegerBitWidth();9946Value *Src = CI->getOperand(0);99479948bool SrcContainsUndef = false;9949SetTy SrcPVS;9950if (!fillSetWithConstantValues(A, IRPosition::value(*Src), SrcPVS,9951SrcContainsUndef, /* ForSelf */ false))9952return indicatePessimisticFixpoint();99539954if (SrcContainsUndef)9955unionAssumedWithUndef();9956else {9957for (const APInt &S : SrcPVS) {9958APInt T = calculateCastInst(CI, S, ResultBitWidth);9959unionAssumed(T);9960}9961}9962return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED9963: ChangeStatus::CHANGED;9964}99659966ChangeStatus updateWithBinaryOperator(Attributor &A, BinaryOperator *BinOp) {9967auto AssumedBefore = getAssumed();9968Value *LHS = BinOp->getOperand(0);9969Value *RHS = BinOp->getOperand(1);99709971bool LHSContainsUndef = false, RHSContainsUndef = false;9972SetTy LHSAAPVS, RHSAAPVS;9973if (!fillSetWithConstantValues(A, IRPosition::value(*LHS), LHSAAPVS,9974LHSContainsUndef, /* ForSelf */ false) ||9975!fillSetWithConstantValues(A, IRPosition::value(*RHS), RHSAAPVS,9976RHSContainsUndef, /* ForSelf */ false))9977return indicatePessimisticFixpoint();99789979const APInt Zero = APInt(LHS->getType()->getIntegerBitWidth(), 0);99809981// TODO: make use of undef flag to limit potential values aggressively.9982if (LHSContainsUndef && RHSContainsUndef) {9983if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, Zero))9984return indicatePessimisticFixpoint();9985} else if (LHSContainsUndef) {9986for (const APInt &R : RHSAAPVS) {9987if (!calculateBinaryOperatorAndTakeUnion(BinOp, Zero, R))9988return indicatePessimisticFixpoint();9989}9990} else if (RHSContainsUndef) {9991for (const APInt &L : LHSAAPVS) {9992if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, Zero))9993return indicatePessimisticFixpoint();9994}9995} else {9996for (const APInt &L : LHSAAPVS) {9997for (const APInt &R : RHSAAPVS) {9998if (!calculateBinaryOperatorAndTakeUnion(BinOp, L, R))9999return indicatePessimisticFixpoint();10000}10001}10002}10003return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED10004: ChangeStatus::CHANGED;10005}1000610007ChangeStatus updateWithInstruction(Attributor &A, Instruction *Inst) {10008auto AssumedBefore = getAssumed();10009SetTy Incoming;10010bool ContainsUndef;10011if (!fillSetWithConstantValues(A, IRPosition::value(*Inst), Incoming,10012ContainsUndef, /* ForSelf */ true))10013return indicatePessimisticFixpoint();10014if (ContainsUndef) {10015unionAssumedWithUndef();10016} else {10017for (const auto &It : Incoming)10018unionAssumed(It);10019}10020return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED10021: ChangeStatus::CHANGED;10022}1002310024/// See AbstractAttribute::updateImpl(...).10025ChangeStatus updateImpl(Attributor &A) override {10026Value &V = getAssociatedValue();10027Instruction *I = dyn_cast<Instruction>(&V);1002810029if (auto *ICI = dyn_cast<ICmpInst>(I))10030return updateWithICmpInst(A, ICI);1003110032if (auto *SI = dyn_cast<SelectInst>(I))10033return updateWithSelectInst(A, SI);1003410035if (auto *CI = dyn_cast<CastInst>(I))10036return updateWithCastInst(A, CI);1003710038if (auto *BinOp = dyn_cast<BinaryOperator>(I))10039return updateWithBinaryOperator(A, BinOp);1004010041if (isa<PHINode>(I) || isa<LoadInst>(I))10042return updateWithInstruction(A, I);1004310044return indicatePessimisticFixpoint();10045}1004610047/// See AbstractAttribute::trackStatistics()10048void trackStatistics() const override {10049STATS_DECLTRACK_FLOATING_ATTR(potential_values)10050}10051};1005210053struct AAPotentialConstantValuesFunction : AAPotentialConstantValuesImpl {10054AAPotentialConstantValuesFunction(const IRPosition &IRP, Attributor &A)10055: AAPotentialConstantValuesImpl(IRP, A) {}1005610057/// See AbstractAttribute::initialize(...).10058ChangeStatus updateImpl(Attributor &A) override {10059llvm_unreachable(10060"AAPotentialConstantValues(Function|CallSite)::updateImpl will "10061"not be called");10062}1006310064/// See AbstractAttribute::trackStatistics()10065void trackStatistics() const override {10066STATS_DECLTRACK_FN_ATTR(potential_values)10067}10068};1006910070struct AAPotentialConstantValuesCallSite : AAPotentialConstantValuesFunction {10071AAPotentialConstantValuesCallSite(const IRPosition &IRP, Attributor &A)10072: AAPotentialConstantValuesFunction(IRP, A) {}1007310074/// See AbstractAttribute::trackStatistics()10075void trackStatistics() const override {10076STATS_DECLTRACK_CS_ATTR(potential_values)10077}10078};1007910080struct AAPotentialConstantValuesCallSiteReturned10081: AACalleeToCallSite<AAPotentialConstantValues,10082AAPotentialConstantValuesImpl> {10083AAPotentialConstantValuesCallSiteReturned(const IRPosition &IRP,10084Attributor &A)10085: AACalleeToCallSite<AAPotentialConstantValues,10086AAPotentialConstantValuesImpl>(IRP, A) {}1008710088/// See AbstractAttribute::trackStatistics()10089void trackStatistics() const override {10090STATS_DECLTRACK_CSRET_ATTR(potential_values)10091}10092};1009310094struct AAPotentialConstantValuesCallSiteArgument10095: AAPotentialConstantValuesFloating {10096AAPotentialConstantValuesCallSiteArgument(const IRPosition &IRP,10097Attributor &A)10098: AAPotentialConstantValuesFloating(IRP, A) {}1009910100/// See AbstractAttribute::initialize(..).10101void initialize(Attributor &A) override {10102AAPotentialConstantValuesImpl::initialize(A);10103if (isAtFixpoint())10104return;1010510106Value &V = getAssociatedValue();1010710108if (auto *C = dyn_cast<ConstantInt>(&V)) {10109unionAssumed(C->getValue());10110indicateOptimisticFixpoint();10111return;10112}1011310114if (isa<UndefValue>(&V)) {10115unionAssumedWithUndef();10116indicateOptimisticFixpoint();10117return;10118}10119}1012010121/// See AbstractAttribute::updateImpl(...).10122ChangeStatus updateImpl(Attributor &A) override {10123Value &V = getAssociatedValue();10124auto AssumedBefore = getAssumed();10125auto *AA = A.getAAFor<AAPotentialConstantValues>(10126*this, IRPosition::value(V), DepClassTy::REQUIRED);10127if (!AA)10128return indicatePessimisticFixpoint();10129const auto &S = AA->getAssumed();10130unionAssumed(S);10131return AssumedBefore == getAssumed() ? ChangeStatus::UNCHANGED10132: ChangeStatus::CHANGED;10133}1013410135/// See AbstractAttribute::trackStatistics()10136void trackStatistics() const override {10137STATS_DECLTRACK_CSARG_ATTR(potential_values)10138}10139};10140} // namespace1014110142/// ------------------------ NoUndef Attribute ---------------------------------10143bool AANoUndef::isImpliedByIR(Attributor &A, const IRPosition &IRP,10144Attribute::AttrKind ImpliedAttributeKind,10145bool IgnoreSubsumingPositions) {10146assert(ImpliedAttributeKind == Attribute::NoUndef &&10147"Unexpected attribute kind");10148if (A.hasAttr(IRP, {Attribute::NoUndef}, IgnoreSubsumingPositions,10149Attribute::NoUndef))10150return true;1015110152Value &Val = IRP.getAssociatedValue();10153if (IRP.getPositionKind() != IRPosition::IRP_RETURNED &&10154isGuaranteedNotToBeUndefOrPoison(&Val)) {10155LLVMContext &Ctx = Val.getContext();10156A.manifestAttrs(IRP, Attribute::get(Ctx, Attribute::NoUndef));10157return true;10158}1015910160return false;10161}1016210163namespace {10164struct AANoUndefImpl : AANoUndef {10165AANoUndefImpl(const IRPosition &IRP, Attributor &A) : AANoUndef(IRP, A) {}1016610167/// See AbstractAttribute::initialize(...).10168void initialize(Attributor &A) override {10169Value &V = getAssociatedValue();10170if (isa<UndefValue>(V))10171indicatePessimisticFixpoint();10172assert(!isImpliedByIR(A, getIRPosition(), Attribute::NoUndef));10173}1017410175/// See followUsesInMBEC10176bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I,10177AANoUndef::StateType &State) {10178const Value *UseV = U->get();10179const DominatorTree *DT = nullptr;10180AssumptionCache *AC = nullptr;10181InformationCache &InfoCache = A.getInfoCache();10182if (Function *F = getAnchorScope()) {10183DT = InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*F);10184AC = InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*F);10185}10186State.setKnown(isGuaranteedNotToBeUndefOrPoison(UseV, AC, I, DT));10187bool TrackUse = false;10188// Track use for instructions which must produce undef or poison bits when10189// at least one operand contains such bits.10190if (isa<CastInst>(*I) || isa<GetElementPtrInst>(*I))10191TrackUse = true;10192return TrackUse;10193}1019410195/// See AbstractAttribute::getAsStr().10196const std::string getAsStr(Attributor *A) const override {10197return getAssumed() ? "noundef" : "may-undef-or-poison";10198}1019910200ChangeStatus manifest(Attributor &A) override {10201// We don't manifest noundef attribute for dead positions because the10202// associated values with dead positions would be replaced with undef10203// values.10204bool UsedAssumedInformation = false;10205if (A.isAssumedDead(getIRPosition(), nullptr, nullptr,10206UsedAssumedInformation))10207return ChangeStatus::UNCHANGED;10208// A position whose simplified value does not have any value is10209// considered to be dead. We don't manifest noundef in such positions for10210// the same reason above.10211if (!A.getAssumedSimplified(getIRPosition(), *this, UsedAssumedInformation,10212AA::Interprocedural)10213.has_value())10214return ChangeStatus::UNCHANGED;10215return AANoUndef::manifest(A);10216}10217};1021810219struct AANoUndefFloating : public AANoUndefImpl {10220AANoUndefFloating(const IRPosition &IRP, Attributor &A)10221: AANoUndefImpl(IRP, A) {}1022210223/// See AbstractAttribute::initialize(...).10224void initialize(Attributor &A) override {10225AANoUndefImpl::initialize(A);10226if (!getState().isAtFixpoint() && getAnchorScope() &&10227!getAnchorScope()->isDeclaration())10228if (Instruction *CtxI = getCtxI())10229followUsesInMBEC(*this, A, getState(), *CtxI);10230}1023110232/// See AbstractAttribute::updateImpl(...).10233ChangeStatus updateImpl(Attributor &A) override {10234auto VisitValueCB = [&](const IRPosition &IRP) -> bool {10235bool IsKnownNoUndef;10236return AA::hasAssumedIRAttr<Attribute::NoUndef>(10237A, this, IRP, DepClassTy::REQUIRED, IsKnownNoUndef);10238};1023910240bool Stripped;10241bool UsedAssumedInformation = false;10242Value *AssociatedValue = &getAssociatedValue();10243SmallVector<AA::ValueAndContext> Values;10244if (!A.getAssumedSimplifiedValues(getIRPosition(), *this, Values,10245AA::AnyScope, UsedAssumedInformation))10246Stripped = false;10247else10248Stripped =10249Values.size() != 1 || Values.front().getValue() != AssociatedValue;1025010251if (!Stripped) {10252// If we haven't stripped anything we might still be able to use a10253// different AA, but only if the IRP changes. Effectively when we10254// interpret this not as a call site value but as a floating/argument10255// value.10256const IRPosition AVIRP = IRPosition::value(*AssociatedValue);10257if (AVIRP == getIRPosition() || !VisitValueCB(AVIRP))10258return indicatePessimisticFixpoint();10259return ChangeStatus::UNCHANGED;10260}1026110262for (const auto &VAC : Values)10263if (!VisitValueCB(IRPosition::value(*VAC.getValue())))10264return indicatePessimisticFixpoint();1026510266return ChangeStatus::UNCHANGED;10267}1026810269/// See AbstractAttribute::trackStatistics()10270void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noundef) }10271};1027210273struct AANoUndefReturned final10274: AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl> {10275AANoUndefReturned(const IRPosition &IRP, Attributor &A)10276: AAReturnedFromReturnedValues<AANoUndef, AANoUndefImpl>(IRP, A) {}1027710278/// See AbstractAttribute::trackStatistics()10279void trackStatistics() const override { STATS_DECLTRACK_FNRET_ATTR(noundef) }10280};1028110282struct AANoUndefArgument final10283: AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl> {10284AANoUndefArgument(const IRPosition &IRP, Attributor &A)10285: AAArgumentFromCallSiteArguments<AANoUndef, AANoUndefImpl>(IRP, A) {}1028610287/// See AbstractAttribute::trackStatistics()10288void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(noundef) }10289};1029010291struct AANoUndefCallSiteArgument final : AANoUndefFloating {10292AANoUndefCallSiteArgument(const IRPosition &IRP, Attributor &A)10293: AANoUndefFloating(IRP, A) {}1029410295/// See AbstractAttribute::trackStatistics()10296void trackStatistics() const override { STATS_DECLTRACK_CSARG_ATTR(noundef) }10297};1029810299struct AANoUndefCallSiteReturned final10300: AACalleeToCallSite<AANoUndef, AANoUndefImpl> {10301AANoUndefCallSiteReturned(const IRPosition &IRP, Attributor &A)10302: AACalleeToCallSite<AANoUndef, AANoUndefImpl>(IRP, A) {}1030310304/// See AbstractAttribute::trackStatistics()10305void trackStatistics() const override { STATS_DECLTRACK_CSRET_ATTR(noundef) }10306};1030710308/// ------------------------ NoFPClass Attribute -------------------------------1030910310struct AANoFPClassImpl : AANoFPClass {10311AANoFPClassImpl(const IRPosition &IRP, Attributor &A) : AANoFPClass(IRP, A) {}1031210313void initialize(Attributor &A) override {10314const IRPosition &IRP = getIRPosition();1031510316Value &V = IRP.getAssociatedValue();10317if (isa<UndefValue>(V)) {10318indicateOptimisticFixpoint();10319return;10320}1032110322SmallVector<Attribute> Attrs;10323A.getAttrs(getIRPosition(), {Attribute::NoFPClass}, Attrs, false);10324for (const auto &Attr : Attrs) {10325addKnownBits(Attr.getNoFPClass());10326}1032710328const DataLayout &DL = A.getDataLayout();10329if (getPositionKind() != IRPosition::IRP_RETURNED) {10330KnownFPClass KnownFPClass = computeKnownFPClass(&V, DL);10331addKnownBits(~KnownFPClass.KnownFPClasses);10332}1033310334if (Instruction *CtxI = getCtxI())10335followUsesInMBEC(*this, A, getState(), *CtxI);10336}1033710338/// See followUsesInMBEC10339bool followUseInMBEC(Attributor &A, const Use *U, const Instruction *I,10340AANoFPClass::StateType &State) {10341// TODO: Determine what instructions can be looked through.10342auto *CB = dyn_cast<CallBase>(I);10343if (!CB)10344return false;1034510346if (!CB->isArgOperand(U))10347return false;1034810349unsigned ArgNo = CB->getArgOperandNo(U);10350IRPosition IRP = IRPosition::callsite_argument(*CB, ArgNo);10351if (auto *NoFPAA = A.getAAFor<AANoFPClass>(*this, IRP, DepClassTy::NONE))10352State.addKnownBits(NoFPAA->getState().getKnown());10353return false;10354}1035510356const std::string getAsStr(Attributor *A) const override {10357std::string Result = "nofpclass";10358raw_string_ostream OS(Result);10359OS << getKnownNoFPClass() << '/' << getAssumedNoFPClass();10360return Result;10361}1036210363void getDeducedAttributes(Attributor &A, LLVMContext &Ctx,10364SmallVectorImpl<Attribute> &Attrs) const override {10365Attrs.emplace_back(Attribute::getWithNoFPClass(Ctx, getAssumedNoFPClass()));10366}10367};1036810369struct AANoFPClassFloating : public AANoFPClassImpl {10370AANoFPClassFloating(const IRPosition &IRP, Attributor &A)10371: AANoFPClassImpl(IRP, A) {}1037210373/// See AbstractAttribute::updateImpl(...).10374ChangeStatus updateImpl(Attributor &A) override {10375SmallVector<AA::ValueAndContext> Values;10376bool UsedAssumedInformation = false;10377if (!A.getAssumedSimplifiedValues(getIRPosition(), *this, Values,10378AA::AnyScope, UsedAssumedInformation)) {10379Values.push_back({getAssociatedValue(), getCtxI()});10380}1038110382StateType T;10383auto VisitValueCB = [&](Value &V, const Instruction *CtxI) -> bool {10384const auto *AA = A.getAAFor<AANoFPClass>(*this, IRPosition::value(V),10385DepClassTy::REQUIRED);10386if (!AA || this == AA) {10387T.indicatePessimisticFixpoint();10388} else {10389const AANoFPClass::StateType &S =10390static_cast<const AANoFPClass::StateType &>(AA->getState());10391T ^= S;10392}10393return T.isValidState();10394};1039510396for (const auto &VAC : Values)10397if (!VisitValueCB(*VAC.getValue(), VAC.getCtxI()))10398return indicatePessimisticFixpoint();1039910400return clampStateAndIndicateChange(getState(), T);10401}1040210403/// See AbstractAttribute::trackStatistics()10404void trackStatistics() const override {10405STATS_DECLTRACK_FNRET_ATTR(nofpclass)10406}10407};1040810409struct AANoFPClassReturned final10410: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,10411AANoFPClassImpl::StateType, false,10412Attribute::None, false> {10413AANoFPClassReturned(const IRPosition &IRP, Attributor &A)10414: AAReturnedFromReturnedValues<AANoFPClass, AANoFPClassImpl,10415AANoFPClassImpl::StateType, false,10416Attribute::None, false>(IRP, A) {}1041710418/// See AbstractAttribute::trackStatistics()10419void trackStatistics() const override {10420STATS_DECLTRACK_FNRET_ATTR(nofpclass)10421}10422};1042310424struct AANoFPClassArgument final10425: AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl> {10426AANoFPClassArgument(const IRPosition &IRP, Attributor &A)10427: AAArgumentFromCallSiteArguments<AANoFPClass, AANoFPClassImpl>(IRP, A) {}1042810429/// See AbstractAttribute::trackStatistics()10430void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(nofpclass) }10431};1043210433struct AANoFPClassCallSiteArgument final : AANoFPClassFloating {10434AANoFPClassCallSiteArgument(const IRPosition &IRP, Attributor &A)10435: AANoFPClassFloating(IRP, A) {}1043610437/// See AbstractAttribute::trackStatistics()10438void trackStatistics() const override {10439STATS_DECLTRACK_CSARG_ATTR(nofpclass)10440}10441};1044210443struct AANoFPClassCallSiteReturned final10444: AACalleeToCallSite<AANoFPClass, AANoFPClassImpl> {10445AANoFPClassCallSiteReturned(const IRPosition &IRP, Attributor &A)10446: AACalleeToCallSite<AANoFPClass, AANoFPClassImpl>(IRP, A) {}1044710448/// See AbstractAttribute::trackStatistics()10449void trackStatistics() const override {10450STATS_DECLTRACK_CSRET_ATTR(nofpclass)10451}10452};1045310454struct AACallEdgesImpl : public AACallEdges {10455AACallEdgesImpl(const IRPosition &IRP, Attributor &A) : AACallEdges(IRP, A) {}1045610457const SetVector<Function *> &getOptimisticEdges() const override {10458return CalledFunctions;10459}1046010461bool hasUnknownCallee() const override { return HasUnknownCallee; }1046210463bool hasNonAsmUnknownCallee() const override {10464return HasUnknownCalleeNonAsm;10465}1046610467const std::string getAsStr(Attributor *A) const override {10468return "CallEdges[" + std::to_string(HasUnknownCallee) + "," +10469std::to_string(CalledFunctions.size()) + "]";10470}1047110472void trackStatistics() const override {}1047310474protected:10475void addCalledFunction(Function *Fn, ChangeStatus &Change) {10476if (CalledFunctions.insert(Fn)) {10477Change = ChangeStatus::CHANGED;10478LLVM_DEBUG(dbgs() << "[AACallEdges] New call edge: " << Fn->getName()10479<< "\n");10480}10481}1048210483void setHasUnknownCallee(bool NonAsm, ChangeStatus &Change) {10484if (!HasUnknownCallee)10485Change = ChangeStatus::CHANGED;10486if (NonAsm && !HasUnknownCalleeNonAsm)10487Change = ChangeStatus::CHANGED;10488HasUnknownCalleeNonAsm |= NonAsm;10489HasUnknownCallee = true;10490}1049110492private:10493/// Optimistic set of functions that might be called by this position.10494SetVector<Function *> CalledFunctions;1049510496/// Is there any call with a unknown callee.10497bool HasUnknownCallee = false;1049810499/// Is there any call with a unknown callee, excluding any inline asm.10500bool HasUnknownCalleeNonAsm = false;10501};1050210503struct AACallEdgesCallSite : public AACallEdgesImpl {10504AACallEdgesCallSite(const IRPosition &IRP, Attributor &A)10505: AACallEdgesImpl(IRP, A) {}10506/// See AbstractAttribute::updateImpl(...).10507ChangeStatus updateImpl(Attributor &A) override {10508ChangeStatus Change = ChangeStatus::UNCHANGED;1050910510auto VisitValue = [&](Value &V, const Instruction *CtxI) -> bool {10511if (Function *Fn = dyn_cast<Function>(&V)) {10512addCalledFunction(Fn, Change);10513} else {10514LLVM_DEBUG(dbgs() << "[AACallEdges] Unrecognized value: " << V << "\n");10515setHasUnknownCallee(true, Change);10516}1051710518// Explore all values.10519return true;10520};1052110522SmallVector<AA::ValueAndContext> Values;10523// Process any value that we might call.10524auto ProcessCalledOperand = [&](Value *V, Instruction *CtxI) {10525if (isa<Constant>(V)) {10526VisitValue(*V, CtxI);10527return;10528}1052910530bool UsedAssumedInformation = false;10531Values.clear();10532if (!A.getAssumedSimplifiedValues(IRPosition::value(*V), *this, Values,10533AA::AnyScope, UsedAssumedInformation)) {10534Values.push_back({*V, CtxI});10535}10536for (auto &VAC : Values)10537VisitValue(*VAC.getValue(), VAC.getCtxI());10538};1053910540CallBase *CB = cast<CallBase>(getCtxI());1054110542if (auto *IA = dyn_cast<InlineAsm>(CB->getCalledOperand())) {10543if (IA->hasSideEffects() &&10544!hasAssumption(*CB->getCaller(), "ompx_no_call_asm") &&10545!hasAssumption(*CB, "ompx_no_call_asm")) {10546setHasUnknownCallee(false, Change);10547}10548return Change;10549}1055010551if (CB->isIndirectCall())10552if (auto *IndirectCallAA = A.getAAFor<AAIndirectCallInfo>(10553*this, getIRPosition(), DepClassTy::OPTIONAL))10554if (IndirectCallAA->foreachCallee(10555[&](Function *Fn) { return VisitValue(*Fn, CB); }))10556return Change;1055710558// The most simple case.10559ProcessCalledOperand(CB->getCalledOperand(), CB);1056010561// Process callback functions.10562SmallVector<const Use *, 4u> CallbackUses;10563AbstractCallSite::getCallbackUses(*CB, CallbackUses);10564for (const Use *U : CallbackUses)10565ProcessCalledOperand(U->get(), CB);1056610567return Change;10568}10569};1057010571struct AACallEdgesFunction : public AACallEdgesImpl {10572AACallEdgesFunction(const IRPosition &IRP, Attributor &A)10573: AACallEdgesImpl(IRP, A) {}1057410575/// See AbstractAttribute::updateImpl(...).10576ChangeStatus updateImpl(Attributor &A) override {10577ChangeStatus Change = ChangeStatus::UNCHANGED;1057810579auto ProcessCallInst = [&](Instruction &Inst) {10580CallBase &CB = cast<CallBase>(Inst);1058110582auto *CBEdges = A.getAAFor<AACallEdges>(10583*this, IRPosition::callsite_function(CB), DepClassTy::REQUIRED);10584if (!CBEdges)10585return false;10586if (CBEdges->hasNonAsmUnknownCallee())10587setHasUnknownCallee(true, Change);10588if (CBEdges->hasUnknownCallee())10589setHasUnknownCallee(false, Change);1059010591for (Function *F : CBEdges->getOptimisticEdges())10592addCalledFunction(F, Change);1059310594return true;10595};1059610597// Visit all callable instructions.10598bool UsedAssumedInformation = false;10599if (!A.checkForAllCallLikeInstructions(ProcessCallInst, *this,10600UsedAssumedInformation,10601/* CheckBBLivenessOnly */ true)) {10602// If we haven't looked at all call like instructions, assume that there10603// are unknown callees.10604setHasUnknownCallee(true, Change);10605}1060610607return Change;10608}10609};1061010611/// -------------------AAInterFnReachability Attribute--------------------------1061210613struct AAInterFnReachabilityFunction10614: public CachedReachabilityAA<AAInterFnReachability, Function> {10615using Base = CachedReachabilityAA<AAInterFnReachability, Function>;10616AAInterFnReachabilityFunction(const IRPosition &IRP, Attributor &A)10617: Base(IRP, A) {}1061810619bool instructionCanReach(10620Attributor &A, const Instruction &From, const Function &To,10621const AA::InstExclusionSetTy *ExclusionSet) const override {10622assert(From.getFunction() == getAnchorScope() && "Queried the wrong AA!");10623auto *NonConstThis = const_cast<AAInterFnReachabilityFunction *>(this);1062410625RQITy StackRQI(A, From, To, ExclusionSet, false);10626typename RQITy::Reachable Result;10627if (!NonConstThis->checkQueryCache(A, StackRQI, Result))10628return NonConstThis->isReachableImpl(A, StackRQI,10629/*IsTemporaryRQI=*/true);10630return Result == RQITy::Reachable::Yes;10631}1063210633bool isReachableImpl(Attributor &A, RQITy &RQI,10634bool IsTemporaryRQI) override {10635const Instruction *EntryI =10636&RQI.From->getFunction()->getEntryBlock().front();10637if (EntryI != RQI.From &&10638!instructionCanReach(A, *EntryI, *RQI.To, nullptr))10639return rememberResult(A, RQITy::Reachable::No, RQI, false,10640IsTemporaryRQI);1064110642auto CheckReachableCallBase = [&](CallBase *CB) {10643auto *CBEdges = A.getAAFor<AACallEdges>(10644*this, IRPosition::callsite_function(*CB), DepClassTy::OPTIONAL);10645if (!CBEdges || !CBEdges->getState().isValidState())10646return false;10647// TODO Check To backwards in this case.10648if (CBEdges->hasUnknownCallee())10649return false;1065010651for (Function *Fn : CBEdges->getOptimisticEdges()) {10652if (Fn == RQI.To)10653return false;1065410655if (Fn->isDeclaration()) {10656if (Fn->hasFnAttribute(Attribute::NoCallback))10657continue;10658// TODO Check To backwards in this case.10659return false;10660}1066110662if (Fn == getAnchorScope()) {10663if (EntryI == RQI.From)10664continue;10665return false;10666}1066710668const AAInterFnReachability *InterFnReachability =10669A.getAAFor<AAInterFnReachability>(*this, IRPosition::function(*Fn),10670DepClassTy::OPTIONAL);1067110672const Instruction &FnFirstInst = Fn->getEntryBlock().front();10673if (!InterFnReachability ||10674InterFnReachability->instructionCanReach(A, FnFirstInst, *RQI.To,10675RQI.ExclusionSet))10676return false;10677}10678return true;10679};1068010681const auto *IntraFnReachability = A.getAAFor<AAIntraFnReachability>(10682*this, IRPosition::function(*RQI.From->getFunction()),10683DepClassTy::OPTIONAL);1068410685// Determine call like instructions that we can reach from the inst.10686auto CheckCallBase = [&](Instruction &CBInst) {10687// There are usually less nodes in the call graph, check inter function10688// reachability first.10689if (CheckReachableCallBase(cast<CallBase>(&CBInst)))10690return true;10691return IntraFnReachability && !IntraFnReachability->isAssumedReachable(10692A, *RQI.From, CBInst, RQI.ExclusionSet);10693};1069410695bool UsedExclusionSet = /* conservative */ true;10696bool UsedAssumedInformation = false;10697if (!A.checkForAllCallLikeInstructions(CheckCallBase, *this,10698UsedAssumedInformation,10699/* CheckBBLivenessOnly */ true))10700return rememberResult(A, RQITy::Reachable::Yes, RQI, UsedExclusionSet,10701IsTemporaryRQI);1070210703return rememberResult(A, RQITy::Reachable::No, RQI, UsedExclusionSet,10704IsTemporaryRQI);10705}1070610707void trackStatistics() const override {}10708};10709} // namespace1071010711template <typename AAType>10712static std::optional<Constant *>10713askForAssumedConstant(Attributor &A, const AbstractAttribute &QueryingAA,10714const IRPosition &IRP, Type &Ty) {10715if (!Ty.isIntegerTy())10716return nullptr;1071710718// This will also pass the call base context.10719const auto *AA = A.getAAFor<AAType>(QueryingAA, IRP, DepClassTy::NONE);10720if (!AA)10721return nullptr;1072210723std::optional<Constant *> COpt = AA->getAssumedConstant(A);1072410725if (!COpt.has_value()) {10726A.recordDependence(*AA, QueryingAA, DepClassTy::OPTIONAL);10727return std::nullopt;10728}10729if (auto *C = *COpt) {10730A.recordDependence(*AA, QueryingAA, DepClassTy::OPTIONAL);10731return C;10732}10733return nullptr;10734}1073510736Value *AAPotentialValues::getSingleValue(10737Attributor &A, const AbstractAttribute &AA, const IRPosition &IRP,10738SmallVectorImpl<AA::ValueAndContext> &Values) {10739Type &Ty = *IRP.getAssociatedType();10740std::optional<Value *> V;10741for (auto &It : Values) {10742V = AA::combineOptionalValuesInAAValueLatice(V, It.getValue(), &Ty);10743if (V.has_value() && !*V)10744break;10745}10746if (!V.has_value())10747return UndefValue::get(&Ty);10748return *V;10749}1075010751namespace {10752struct AAPotentialValuesImpl : AAPotentialValues {10753using StateType = PotentialLLVMValuesState;1075410755AAPotentialValuesImpl(const IRPosition &IRP, Attributor &A)10756: AAPotentialValues(IRP, A) {}1075710758/// See AbstractAttribute::initialize(..).10759void initialize(Attributor &A) override {10760if (A.hasSimplificationCallback(getIRPosition())) {10761indicatePessimisticFixpoint();10762return;10763}10764Value *Stripped = getAssociatedValue().stripPointerCasts();10765if (isa<Constant>(Stripped) && !isa<ConstantExpr>(Stripped)) {10766addValue(A, getState(), *Stripped, getCtxI(), AA::AnyScope,10767getAnchorScope());10768indicateOptimisticFixpoint();10769return;10770}10771AAPotentialValues::initialize(A);10772}1077310774/// See AbstractAttribute::getAsStr().10775const std::string getAsStr(Attributor *A) const override {10776std::string Str;10777llvm::raw_string_ostream OS(Str);10778OS << getState();10779return Str;10780}1078110782template <typename AAType>10783static std::optional<Value *> askOtherAA(Attributor &A,10784const AbstractAttribute &AA,10785const IRPosition &IRP, Type &Ty) {10786if (isa<Constant>(IRP.getAssociatedValue()))10787return &IRP.getAssociatedValue();10788std::optional<Constant *> C = askForAssumedConstant<AAType>(A, AA, IRP, Ty);10789if (!C)10790return std::nullopt;10791if (*C)10792if (auto *CC = AA::getWithType(**C, Ty))10793return CC;10794return nullptr;10795}1079610797virtual void addValue(Attributor &A, StateType &State, Value &V,10798const Instruction *CtxI, AA::ValueScope S,10799Function *AnchorScope) const {1080010801IRPosition ValIRP = IRPosition::value(V);10802if (auto *CB = dyn_cast_or_null<CallBase>(CtxI)) {10803for (const auto &U : CB->args()) {10804if (U.get() != &V)10805continue;10806ValIRP = IRPosition::callsite_argument(*CB, CB->getArgOperandNo(&U));10807break;10808}10809}1081010811Value *VPtr = &V;10812if (ValIRP.getAssociatedType()->isIntegerTy()) {10813Type &Ty = *getAssociatedType();10814std::optional<Value *> SimpleV =10815askOtherAA<AAValueConstantRange>(A, *this, ValIRP, Ty);10816if (SimpleV.has_value() && !*SimpleV) {10817auto *PotentialConstantsAA = A.getAAFor<AAPotentialConstantValues>(10818*this, ValIRP, DepClassTy::OPTIONAL);10819if (PotentialConstantsAA && PotentialConstantsAA->isValidState()) {10820for (const auto &It : PotentialConstantsAA->getAssumedSet())10821State.unionAssumed({{*ConstantInt::get(&Ty, It), nullptr}, S});10822if (PotentialConstantsAA->undefIsContained())10823State.unionAssumed({{*UndefValue::get(&Ty), nullptr}, S});10824return;10825}10826}10827if (!SimpleV.has_value())10828return;1082910830if (*SimpleV)10831VPtr = *SimpleV;10832}1083310834if (isa<ConstantInt>(VPtr))10835CtxI = nullptr;10836if (!AA::isValidInScope(*VPtr, AnchorScope))10837S = AA::ValueScope(S | AA::Interprocedural);1083810839State.unionAssumed({{*VPtr, CtxI}, S});10840}1084110842/// Helper struct to tie a value+context pair together with the scope for10843/// which this is the simplified version.10844struct ItemInfo {10845AA::ValueAndContext I;10846AA::ValueScope S;1084710848bool operator==(const ItemInfo &II) const {10849return II.I == I && II.S == S;10850};10851bool operator<(const ItemInfo &II) const {10852if (I == II.I)10853return S < II.S;10854return I < II.I;10855};10856};1085710858bool recurseForValue(Attributor &A, const IRPosition &IRP, AA::ValueScope S) {10859SmallMapVector<AA::ValueAndContext, int, 8> ValueScopeMap;10860for (auto CS : {AA::Intraprocedural, AA::Interprocedural}) {10861if (!(CS & S))10862continue;1086310864bool UsedAssumedInformation = false;10865SmallVector<AA::ValueAndContext> Values;10866if (!A.getAssumedSimplifiedValues(IRP, this, Values, CS,10867UsedAssumedInformation))10868return false;1086910870for (auto &It : Values)10871ValueScopeMap[It] += CS;10872}10873for (auto &It : ValueScopeMap)10874addValue(A, getState(), *It.first.getValue(), It.first.getCtxI(),10875AA::ValueScope(It.second), getAnchorScope());1087610877return true;10878}1087910880void giveUpOnIntraprocedural(Attributor &A) {10881auto NewS = StateType::getBestState(getState());10882for (const auto &It : getAssumedSet()) {10883if (It.second == AA::Intraprocedural)10884continue;10885addValue(A, NewS, *It.first.getValue(), It.first.getCtxI(),10886AA::Interprocedural, getAnchorScope());10887}10888assert(!undefIsContained() && "Undef should be an explicit value!");10889addValue(A, NewS, getAssociatedValue(), getCtxI(), AA::Intraprocedural,10890getAnchorScope());10891getState() = NewS;10892}1089310894/// See AbstractState::indicatePessimisticFixpoint(...).10895ChangeStatus indicatePessimisticFixpoint() override {10896getState() = StateType::getBestState(getState());10897getState().unionAssumed({{getAssociatedValue(), getCtxI()}, AA::AnyScope});10898AAPotentialValues::indicateOptimisticFixpoint();10899return ChangeStatus::CHANGED;10900}1090110902/// See AbstractAttribute::updateImpl(...).10903ChangeStatus updateImpl(Attributor &A) override {10904return indicatePessimisticFixpoint();10905}1090610907/// See AbstractAttribute::manifest(...).10908ChangeStatus manifest(Attributor &A) override {10909SmallVector<AA::ValueAndContext> Values;10910for (AA::ValueScope S : {AA::Interprocedural, AA::Intraprocedural}) {10911Values.clear();10912if (!getAssumedSimplifiedValues(A, Values, S))10913continue;10914Value &OldV = getAssociatedValue();10915if (isa<UndefValue>(OldV))10916continue;10917Value *NewV = getSingleValue(A, *this, getIRPosition(), Values);10918if (!NewV || NewV == &OldV)10919continue;10920if (getCtxI() &&10921!AA::isValidAtPosition({*NewV, *getCtxI()}, A.getInfoCache()))10922continue;10923if (A.changeAfterManifest(getIRPosition(), *NewV))10924return ChangeStatus::CHANGED;10925}10926return ChangeStatus::UNCHANGED;10927}1092810929bool getAssumedSimplifiedValues(10930Attributor &A, SmallVectorImpl<AA::ValueAndContext> &Values,10931AA::ValueScope S, bool RecurseForSelectAndPHI = false) const override {10932if (!isValidState())10933return false;10934bool UsedAssumedInformation = false;10935for (const auto &It : getAssumedSet())10936if (It.second & S) {10937if (RecurseForSelectAndPHI && (isa<PHINode>(It.first.getValue()) ||10938isa<SelectInst>(It.first.getValue()))) {10939if (A.getAssumedSimplifiedValues(10940IRPosition::inst(*cast<Instruction>(It.first.getValue())),10941this, Values, S, UsedAssumedInformation))10942continue;10943}10944Values.push_back(It.first);10945}10946assert(!undefIsContained() && "Undef should be an explicit value!");10947return true;10948}10949};1095010951struct AAPotentialValuesFloating : AAPotentialValuesImpl {10952AAPotentialValuesFloating(const IRPosition &IRP, Attributor &A)10953: AAPotentialValuesImpl(IRP, A) {}1095410955/// See AbstractAttribute::updateImpl(...).10956ChangeStatus updateImpl(Attributor &A) override {10957auto AssumedBefore = getAssumed();1095810959genericValueTraversal(A, &getAssociatedValue());1096010961return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED10962: ChangeStatus::CHANGED;10963}1096410965/// Helper struct to remember which AAIsDead instances we actually used.10966struct LivenessInfo {10967const AAIsDead *LivenessAA = nullptr;10968bool AnyDead = false;10969};1097010971/// Check if \p Cmp is a comparison we can simplify.10972///10973/// We handle multiple cases, one in which at least one operand is an10974/// (assumed) nullptr. If so, try to simplify it using AANonNull on the other10975/// operand. Return true if successful, in that case Worklist will be updated.10976bool handleCmp(Attributor &A, Value &Cmp, Value *LHS, Value *RHS,10977CmpInst::Predicate Pred, ItemInfo II,10978SmallVectorImpl<ItemInfo> &Worklist) {1097910980// Simplify the operands first.10981bool UsedAssumedInformation = false;10982SmallVector<AA::ValueAndContext> LHSValues, RHSValues;10983auto GetSimplifiedValues = [&](Value &V,10984SmallVector<AA::ValueAndContext> &Values) {10985if (!A.getAssumedSimplifiedValues(10986IRPosition::value(V, getCallBaseContext()), this, Values,10987AA::Intraprocedural, UsedAssumedInformation)) {10988Values.clear();10989Values.push_back(AA::ValueAndContext{V, II.I.getCtxI()});10990}10991return Values.empty();10992};10993if (GetSimplifiedValues(*LHS, LHSValues))10994return true;10995if (GetSimplifiedValues(*RHS, RHSValues))10996return true;1099710998LLVMContext &Ctx = LHS->getContext();1099911000InformationCache &InfoCache = A.getInfoCache();11001Instruction *CmpI = dyn_cast<Instruction>(&Cmp);11002Function *F = CmpI ? CmpI->getFunction() : nullptr;11003const auto *DT =11004F ? InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*F)11005: nullptr;11006const auto *TLI =11007F ? A.getInfoCache().getTargetLibraryInfoForFunction(*F) : nullptr;11008auto *AC =11009F ? InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*F)11010: nullptr;1101111012const DataLayout &DL = A.getDataLayout();11013SimplifyQuery Q(DL, TLI, DT, AC, CmpI);1101411015auto CheckPair = [&](Value &LHSV, Value &RHSV) {11016if (isa<UndefValue>(LHSV) || isa<UndefValue>(RHSV)) {11017addValue(A, getState(), *UndefValue::get(Cmp.getType()),11018/* CtxI */ nullptr, II.S, getAnchorScope());11019return true;11020}1102111022// Handle the trivial case first in which we don't even need to think11023// about null or non-null.11024if (&LHSV == &RHSV &&11025(CmpInst::isTrueWhenEqual(Pred) || CmpInst::isFalseWhenEqual(Pred))) {11026Constant *NewV = ConstantInt::get(Type::getInt1Ty(Ctx),11027CmpInst::isTrueWhenEqual(Pred));11028addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,11029getAnchorScope());11030return true;11031}1103211033auto *TypedLHS = AA::getWithType(LHSV, *LHS->getType());11034auto *TypedRHS = AA::getWithType(RHSV, *RHS->getType());11035if (TypedLHS && TypedRHS) {11036Value *NewV = simplifyCmpInst(Pred, TypedLHS, TypedRHS, Q);11037if (NewV && NewV != &Cmp) {11038addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,11039getAnchorScope());11040return true;11041}11042}1104311044// From now on we only handle equalities (==, !=).11045if (!CmpInst::isEquality(Pred))11046return false;1104711048bool LHSIsNull = isa<ConstantPointerNull>(LHSV);11049bool RHSIsNull = isa<ConstantPointerNull>(RHSV);11050if (!LHSIsNull && !RHSIsNull)11051return false;1105211053// Left is the nullptr ==/!= non-nullptr case. We'll use AANonNull on the11054// non-nullptr operand and if we assume it's non-null we can conclude the11055// result of the comparison.11056assert((LHSIsNull || RHSIsNull) &&11057"Expected nullptr versus non-nullptr comparison at this point");1105811059// The index is the operand that we assume is not null.11060unsigned PtrIdx = LHSIsNull;11061bool IsKnownNonNull;11062bool IsAssumedNonNull = AA::hasAssumedIRAttr<Attribute::NonNull>(11063A, this, IRPosition::value(*(PtrIdx ? &RHSV : &LHSV)),11064DepClassTy::REQUIRED, IsKnownNonNull);11065if (!IsAssumedNonNull)11066return false;1106711068// The new value depends on the predicate, true for != and false for ==.11069Constant *NewV =11070ConstantInt::get(Type::getInt1Ty(Ctx), Pred == CmpInst::ICMP_NE);11071addValue(A, getState(), *NewV, /* CtxI */ nullptr, II.S,11072getAnchorScope());11073return true;11074};1107511076for (auto &LHSValue : LHSValues)11077for (auto &RHSValue : RHSValues)11078if (!CheckPair(*LHSValue.getValue(), *RHSValue.getValue()))11079return false;11080return true;11081}1108211083bool handleSelectInst(Attributor &A, SelectInst &SI, ItemInfo II,11084SmallVectorImpl<ItemInfo> &Worklist) {11085const Instruction *CtxI = II.I.getCtxI();11086bool UsedAssumedInformation = false;1108711088std::optional<Constant *> C =11089A.getAssumedConstant(*SI.getCondition(), *this, UsedAssumedInformation);11090bool NoValueYet = !C.has_value();11091if (NoValueYet || isa_and_nonnull<UndefValue>(*C))11092return true;11093if (auto *CI = dyn_cast_or_null<ConstantInt>(*C)) {11094if (CI->isZero())11095Worklist.push_back({{*SI.getFalseValue(), CtxI}, II.S});11096else11097Worklist.push_back({{*SI.getTrueValue(), CtxI}, II.S});11098} else if (&SI == &getAssociatedValue()) {11099// We could not simplify the condition, assume both values.11100Worklist.push_back({{*SI.getTrueValue(), CtxI}, II.S});11101Worklist.push_back({{*SI.getFalseValue(), CtxI}, II.S});11102} else {11103std::optional<Value *> SimpleV = A.getAssumedSimplified(11104IRPosition::inst(SI), *this, UsedAssumedInformation, II.S);11105if (!SimpleV.has_value())11106return true;11107if (*SimpleV) {11108addValue(A, getState(), **SimpleV, CtxI, II.S, getAnchorScope());11109return true;11110}11111return false;11112}11113return true;11114}1111511116bool handleLoadInst(Attributor &A, LoadInst &LI, ItemInfo II,11117SmallVectorImpl<ItemInfo> &Worklist) {11118SmallSetVector<Value *, 4> PotentialCopies;11119SmallSetVector<Instruction *, 4> PotentialValueOrigins;11120bool UsedAssumedInformation = false;11121if (!AA::getPotentiallyLoadedValues(A, LI, PotentialCopies,11122PotentialValueOrigins, *this,11123UsedAssumedInformation,11124/* OnlyExact */ true)) {11125LLVM_DEBUG(dbgs() << "[AAPotentialValues] Failed to get potentially "11126"loaded values for load instruction "11127<< LI << "\n");11128return false;11129}1113011131// Do not simplify loads that are only used in llvm.assume if we cannot also11132// remove all stores that may feed into the load. The reason is that the11133// assume is probably worth something as long as the stores are around.11134InformationCache &InfoCache = A.getInfoCache();11135if (InfoCache.isOnlyUsedByAssume(LI)) {11136if (!llvm::all_of(PotentialValueOrigins, [&](Instruction *I) {11137if (!I || isa<AssumeInst>(I))11138return true;11139if (auto *SI = dyn_cast<StoreInst>(I))11140return A.isAssumedDead(SI->getOperandUse(0), this,11141/* LivenessAA */ nullptr,11142UsedAssumedInformation,11143/* CheckBBLivenessOnly */ false);11144return A.isAssumedDead(*I, this, /* LivenessAA */ nullptr,11145UsedAssumedInformation,11146/* CheckBBLivenessOnly */ false);11147})) {11148LLVM_DEBUG(dbgs() << "[AAPotentialValues] Load is onl used by assumes "11149"and we cannot delete all the stores: "11150<< LI << "\n");11151return false;11152}11153}1115411155// Values have to be dynamically unique or we loose the fact that a11156// single llvm::Value might represent two runtime values (e.g.,11157// stack locations in different recursive calls).11158const Instruction *CtxI = II.I.getCtxI();11159bool ScopeIsLocal = (II.S & AA::Intraprocedural);11160bool AllLocal = ScopeIsLocal;11161bool DynamicallyUnique = llvm::all_of(PotentialCopies, [&](Value *PC) {11162AllLocal &= AA::isValidInScope(*PC, getAnchorScope());11163return AA::isDynamicallyUnique(A, *this, *PC);11164});11165if (!DynamicallyUnique) {11166LLVM_DEBUG(dbgs() << "[AAPotentialValues] Not all potentially loaded "11167"values are dynamically unique: "11168<< LI << "\n");11169return false;11170}1117111172for (auto *PotentialCopy : PotentialCopies) {11173if (AllLocal) {11174Worklist.push_back({{*PotentialCopy, CtxI}, II.S});11175} else {11176Worklist.push_back({{*PotentialCopy, CtxI}, AA::Interprocedural});11177}11178}11179if (!AllLocal && ScopeIsLocal)11180addValue(A, getState(), LI, CtxI, AA::Intraprocedural, getAnchorScope());11181return true;11182}1118311184bool handlePHINode(11185Attributor &A, PHINode &PHI, ItemInfo II,11186SmallVectorImpl<ItemInfo> &Worklist,11187SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {11188auto GetLivenessInfo = [&](const Function &F) -> LivenessInfo & {11189LivenessInfo &LI = LivenessAAs[&F];11190if (!LI.LivenessAA)11191LI.LivenessAA = A.getAAFor<AAIsDead>(*this, IRPosition::function(F),11192DepClassTy::NONE);11193return LI;11194};1119511196if (&PHI == &getAssociatedValue()) {11197LivenessInfo &LI = GetLivenessInfo(*PHI.getFunction());11198const auto *CI =11199A.getInfoCache().getAnalysisResultForFunction<CycleAnalysis>(11200*PHI.getFunction());1120111202Cycle *C = nullptr;11203bool CyclePHI = mayBeInCycle(CI, &PHI, /* HeaderOnly */ true, &C);11204for (unsigned u = 0, e = PHI.getNumIncomingValues(); u < e; u++) {11205BasicBlock *IncomingBB = PHI.getIncomingBlock(u);11206if (LI.LivenessAA &&11207LI.LivenessAA->isEdgeDead(IncomingBB, PHI.getParent())) {11208LI.AnyDead = true;11209continue;11210}11211Value *V = PHI.getIncomingValue(u);11212if (V == &PHI)11213continue;1121411215// If the incoming value is not the PHI but an instruction in the same11216// cycle we might have multiple versions of it flying around.11217if (CyclePHI && isa<Instruction>(V) &&11218(!C || C->contains(cast<Instruction>(V)->getParent())))11219return false;1122011221Worklist.push_back({{*V, IncomingBB->getTerminator()}, II.S});11222}11223return true;11224}1122511226bool UsedAssumedInformation = false;11227std::optional<Value *> SimpleV = A.getAssumedSimplified(11228IRPosition::inst(PHI), *this, UsedAssumedInformation, II.S);11229if (!SimpleV.has_value())11230return true;11231if (!(*SimpleV))11232return false;11233addValue(A, getState(), **SimpleV, &PHI, II.S, getAnchorScope());11234return true;11235}1123611237/// Use the generic, non-optimistic InstSimplfy functionality if we managed to11238/// simplify any operand of the instruction \p I. Return true if successful,11239/// in that case Worklist will be updated.11240bool handleGenericInst(Attributor &A, Instruction &I, ItemInfo II,11241SmallVectorImpl<ItemInfo> &Worklist) {11242bool SomeSimplified = false;11243bool UsedAssumedInformation = false;1124411245SmallVector<Value *, 8> NewOps(I.getNumOperands());11246int Idx = 0;11247for (Value *Op : I.operands()) {11248const auto &SimplifiedOp = A.getAssumedSimplified(11249IRPosition::value(*Op, getCallBaseContext()), *this,11250UsedAssumedInformation, AA::Intraprocedural);11251// If we are not sure about any operand we are not sure about the entire11252// instruction, we'll wait.11253if (!SimplifiedOp.has_value())11254return true;1125511256if (*SimplifiedOp)11257NewOps[Idx] = *SimplifiedOp;11258else11259NewOps[Idx] = Op;1126011261SomeSimplified |= (NewOps[Idx] != Op);11262++Idx;11263}1126411265// We won't bother with the InstSimplify interface if we didn't simplify any11266// operand ourselves.11267if (!SomeSimplified)11268return false;1126911270InformationCache &InfoCache = A.getInfoCache();11271Function *F = I.getFunction();11272const auto *DT =11273InfoCache.getAnalysisResultForFunction<DominatorTreeAnalysis>(*F);11274const auto *TLI = A.getInfoCache().getTargetLibraryInfoForFunction(*F);11275auto *AC = InfoCache.getAnalysisResultForFunction<AssumptionAnalysis>(*F);1127611277const DataLayout &DL = I.getDataLayout();11278SimplifyQuery Q(DL, TLI, DT, AC, &I);11279Value *NewV = simplifyInstructionWithOperands(&I, NewOps, Q);11280if (!NewV || NewV == &I)11281return false;1128211283LLVM_DEBUG(dbgs() << "Generic inst " << I << " assumed simplified to "11284<< *NewV << "\n");11285Worklist.push_back({{*NewV, II.I.getCtxI()}, II.S});11286return true;11287}1128811289bool simplifyInstruction(11290Attributor &A, Instruction &I, ItemInfo II,11291SmallVectorImpl<ItemInfo> &Worklist,11292SmallMapVector<const Function *, LivenessInfo, 4> &LivenessAAs) {11293if (auto *CI = dyn_cast<CmpInst>(&I))11294return handleCmp(A, *CI, CI->getOperand(0), CI->getOperand(1),11295CI->getPredicate(), II, Worklist);1129611297switch (I.getOpcode()) {11298case Instruction::Select:11299return handleSelectInst(A, cast<SelectInst>(I), II, Worklist);11300case Instruction::PHI:11301return handlePHINode(A, cast<PHINode>(I), II, Worklist, LivenessAAs);11302case Instruction::Load:11303return handleLoadInst(A, cast<LoadInst>(I), II, Worklist);11304default:11305return handleGenericInst(A, I, II, Worklist);11306};11307return false;11308}1130911310void genericValueTraversal(Attributor &A, Value *InitialV) {11311SmallMapVector<const Function *, LivenessInfo, 4> LivenessAAs;1131211313SmallSet<ItemInfo, 16> Visited;11314SmallVector<ItemInfo, 16> Worklist;11315Worklist.push_back({{*InitialV, getCtxI()}, AA::AnyScope});1131611317int Iteration = 0;11318do {11319ItemInfo II = Worklist.pop_back_val();11320Value *V = II.I.getValue();11321assert(V);11322const Instruction *CtxI = II.I.getCtxI();11323AA::ValueScope S = II.S;1132411325// Check if we should process the current value. To prevent endless11326// recursion keep a record of the values we followed!11327if (!Visited.insert(II).second)11328continue;1132911330// Make sure we limit the compile time for complex expressions.11331if (Iteration++ >= MaxPotentialValuesIterations) {11332LLVM_DEBUG(dbgs() << "Generic value traversal reached iteration limit: "11333<< Iteration << "!\n");11334addValue(A, getState(), *V, CtxI, S, getAnchorScope());11335continue;11336}1133711338// Explicitly look through calls with a "returned" attribute if we do11339// not have a pointer as stripPointerCasts only works on them.11340Value *NewV = nullptr;11341if (V->getType()->isPointerTy()) {11342NewV = AA::getWithType(*V->stripPointerCasts(), *V->getType());11343} else {11344if (auto *CB = dyn_cast<CallBase>(V))11345if (auto *Callee =11346dyn_cast_if_present<Function>(CB->getCalledOperand())) {11347for (Argument &Arg : Callee->args())11348if (Arg.hasReturnedAttr()) {11349NewV = CB->getArgOperand(Arg.getArgNo());11350break;11351}11352}11353}11354if (NewV && NewV != V) {11355Worklist.push_back({{*NewV, CtxI}, S});11356continue;11357}1135811359if (auto *I = dyn_cast<Instruction>(V)) {11360if (simplifyInstruction(A, *I, II, Worklist, LivenessAAs))11361continue;11362}1136311364if (V != InitialV || isa<Argument>(V))11365if (recurseForValue(A, IRPosition::value(*V), II.S))11366continue;1136711368// If we haven't stripped anything we give up.11369if (V == InitialV && CtxI == getCtxI()) {11370indicatePessimisticFixpoint();11371return;11372}1137311374addValue(A, getState(), *V, CtxI, S, getAnchorScope());11375} while (!Worklist.empty());1137611377// If we actually used liveness information so we have to record a11378// dependence.11379for (auto &It : LivenessAAs)11380if (It.second.AnyDead)11381A.recordDependence(*It.second.LivenessAA, *this, DepClassTy::OPTIONAL);11382}1138311384/// See AbstractAttribute::trackStatistics()11385void trackStatistics() const override {11386STATS_DECLTRACK_FLOATING_ATTR(potential_values)11387}11388};1138911390struct AAPotentialValuesArgument final : AAPotentialValuesImpl {11391using Base = AAPotentialValuesImpl;11392AAPotentialValuesArgument(const IRPosition &IRP, Attributor &A)11393: Base(IRP, A) {}1139411395/// See AbstractAttribute::initialize(..).11396void initialize(Attributor &A) override {11397auto &Arg = cast<Argument>(getAssociatedValue());11398if (Arg.hasPointeeInMemoryValueAttr())11399indicatePessimisticFixpoint();11400}1140111402/// See AbstractAttribute::updateImpl(...).11403ChangeStatus updateImpl(Attributor &A) override {11404auto AssumedBefore = getAssumed();1140511406unsigned ArgNo = getCalleeArgNo();1140711408bool UsedAssumedInformation = false;11409SmallVector<AA::ValueAndContext> Values;11410auto CallSitePred = [&](AbstractCallSite ACS) {11411const auto CSArgIRP = IRPosition::callsite_argument(ACS, ArgNo);11412if (CSArgIRP.getPositionKind() == IRP_INVALID)11413return false;1141411415if (!A.getAssumedSimplifiedValues(CSArgIRP, this, Values,11416AA::Interprocedural,11417UsedAssumedInformation))11418return false;1141911420return isValidState();11421};1142211423if (!A.checkForAllCallSites(CallSitePred, *this,11424/* RequireAllCallSites */ true,11425UsedAssumedInformation))11426return indicatePessimisticFixpoint();1142711428Function *Fn = getAssociatedFunction();11429bool AnyNonLocal = false;11430for (auto &It : Values) {11431if (isa<Constant>(It.getValue())) {11432addValue(A, getState(), *It.getValue(), It.getCtxI(), AA::AnyScope,11433getAnchorScope());11434continue;11435}11436if (!AA::isDynamicallyUnique(A, *this, *It.getValue()))11437return indicatePessimisticFixpoint();1143811439if (auto *Arg = dyn_cast<Argument>(It.getValue()))11440if (Arg->getParent() == Fn) {11441addValue(A, getState(), *It.getValue(), It.getCtxI(), AA::AnyScope,11442getAnchorScope());11443continue;11444}11445addValue(A, getState(), *It.getValue(), It.getCtxI(), AA::Interprocedural,11446getAnchorScope());11447AnyNonLocal = true;11448}11449assert(!undefIsContained() && "Undef should be an explicit value!");11450if (AnyNonLocal)11451giveUpOnIntraprocedural(A);1145211453return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED11454: ChangeStatus::CHANGED;11455}1145611457/// See AbstractAttribute::trackStatistics()11458void trackStatistics() const override {11459STATS_DECLTRACK_ARG_ATTR(potential_values)11460}11461};1146211463struct AAPotentialValuesReturned : public AAPotentialValuesFloating {11464using Base = AAPotentialValuesFloating;11465AAPotentialValuesReturned(const IRPosition &IRP, Attributor &A)11466: Base(IRP, A) {}1146711468/// See AbstractAttribute::initialize(..).11469void initialize(Attributor &A) override {11470Function *F = getAssociatedFunction();11471if (!F || F->isDeclaration() || F->getReturnType()->isVoidTy()) {11472indicatePessimisticFixpoint();11473return;11474}1147511476for (Argument &Arg : F->args())11477if (Arg.hasReturnedAttr()) {11478addValue(A, getState(), Arg, nullptr, AA::AnyScope, F);11479ReturnedArg = &Arg;11480break;11481}11482if (!A.isFunctionIPOAmendable(*F) ||11483A.hasSimplificationCallback(getIRPosition())) {11484if (!ReturnedArg)11485indicatePessimisticFixpoint();11486else11487indicateOptimisticFixpoint();11488}11489}1149011491/// See AbstractAttribute::updateImpl(...).11492ChangeStatus updateImpl(Attributor &A) override {11493auto AssumedBefore = getAssumed();11494bool UsedAssumedInformation = false;1149511496SmallVector<AA::ValueAndContext> Values;11497Function *AnchorScope = getAnchorScope();11498auto HandleReturnedValue = [&](Value &V, Instruction *CtxI,11499bool AddValues) {11500for (AA::ValueScope S : {AA::Interprocedural, AA::Intraprocedural}) {11501Values.clear();11502if (!A.getAssumedSimplifiedValues(IRPosition::value(V), this, Values, S,11503UsedAssumedInformation,11504/* RecurseForSelectAndPHI */ true))11505return false;11506if (!AddValues)11507continue;11508for (const AA::ValueAndContext &VAC : Values)11509addValue(A, getState(), *VAC.getValue(),11510VAC.getCtxI() ? VAC.getCtxI() : CtxI, S, AnchorScope);11511}11512return true;11513};1151411515if (ReturnedArg) {11516HandleReturnedValue(*ReturnedArg, nullptr, true);11517} else {11518auto RetInstPred = [&](Instruction &RetI) {11519bool AddValues = true;11520if (isa<PHINode>(RetI.getOperand(0)) ||11521isa<SelectInst>(RetI.getOperand(0))) {11522addValue(A, getState(), *RetI.getOperand(0), &RetI, AA::AnyScope,11523AnchorScope);11524AddValues = false;11525}11526return HandleReturnedValue(*RetI.getOperand(0), &RetI, AddValues);11527};1152811529if (!A.checkForAllInstructions(RetInstPred, *this, {Instruction::Ret},11530UsedAssumedInformation,11531/* CheckBBLivenessOnly */ true))11532return indicatePessimisticFixpoint();11533}1153411535return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED11536: ChangeStatus::CHANGED;11537}1153811539void addValue(Attributor &A, StateType &State, Value &V,11540const Instruction *CtxI, AA::ValueScope S,11541Function *AnchorScope) const override {11542Function *F = getAssociatedFunction();11543if (auto *CB = dyn_cast<CallBase>(&V))11544if (CB->getCalledOperand() == F)11545return;11546Base::addValue(A, State, V, CtxI, S, AnchorScope);11547}1154811549ChangeStatus manifest(Attributor &A) override {11550if (ReturnedArg)11551return ChangeStatus::UNCHANGED;11552SmallVector<AA::ValueAndContext> Values;11553if (!getAssumedSimplifiedValues(A, Values, AA::ValueScope::Intraprocedural,11554/* RecurseForSelectAndPHI */ true))11555return ChangeStatus::UNCHANGED;11556Value *NewVal = getSingleValue(A, *this, getIRPosition(), Values);11557if (!NewVal)11558return ChangeStatus::UNCHANGED;1155911560ChangeStatus Changed = ChangeStatus::UNCHANGED;11561if (auto *Arg = dyn_cast<Argument>(NewVal)) {11562STATS_DECLTRACK(UniqueReturnValue, FunctionReturn,11563"Number of function with unique return");11564Changed |= A.manifestAttrs(11565IRPosition::argument(*Arg),11566{Attribute::get(Arg->getContext(), Attribute::Returned)});11567STATS_DECLTRACK_ARG_ATTR(returned);11568}1156911570auto RetInstPred = [&](Instruction &RetI) {11571Value *RetOp = RetI.getOperand(0);11572if (isa<UndefValue>(RetOp) || RetOp == NewVal)11573return true;11574if (AA::isValidAtPosition({*NewVal, RetI}, A.getInfoCache()))11575if (A.changeUseAfterManifest(RetI.getOperandUse(0), *NewVal))11576Changed = ChangeStatus::CHANGED;11577return true;11578};11579bool UsedAssumedInformation = false;11580(void)A.checkForAllInstructions(RetInstPred, *this, {Instruction::Ret},11581UsedAssumedInformation,11582/* CheckBBLivenessOnly */ true);11583return Changed;11584}1158511586ChangeStatus indicatePessimisticFixpoint() override {11587return AAPotentialValues::indicatePessimisticFixpoint();11588}1158911590/// See AbstractAttribute::trackStatistics()11591void trackStatistics() const override{11592STATS_DECLTRACK_FNRET_ATTR(potential_values)}1159311594/// The argumented with an existing `returned` attribute.11595Argument *ReturnedArg = nullptr;11596};1159711598struct AAPotentialValuesFunction : AAPotentialValuesImpl {11599AAPotentialValuesFunction(const IRPosition &IRP, Attributor &A)11600: AAPotentialValuesImpl(IRP, A) {}1160111602/// See AbstractAttribute::updateImpl(...).11603ChangeStatus updateImpl(Attributor &A) override {11604llvm_unreachable("AAPotentialValues(Function|CallSite)::updateImpl will "11605"not be called");11606}1160711608/// See AbstractAttribute::trackStatistics()11609void trackStatistics() const override {11610STATS_DECLTRACK_FN_ATTR(potential_values)11611}11612};1161311614struct AAPotentialValuesCallSite : AAPotentialValuesFunction {11615AAPotentialValuesCallSite(const IRPosition &IRP, Attributor &A)11616: AAPotentialValuesFunction(IRP, A) {}1161711618/// See AbstractAttribute::trackStatistics()11619void trackStatistics() const override {11620STATS_DECLTRACK_CS_ATTR(potential_values)11621}11622};1162311624struct AAPotentialValuesCallSiteReturned : AAPotentialValuesImpl {11625AAPotentialValuesCallSiteReturned(const IRPosition &IRP, Attributor &A)11626: AAPotentialValuesImpl(IRP, A) {}1162711628/// See AbstractAttribute::updateImpl(...).11629ChangeStatus updateImpl(Attributor &A) override {11630auto AssumedBefore = getAssumed();1163111632Function *Callee = getAssociatedFunction();11633if (!Callee)11634return indicatePessimisticFixpoint();1163511636bool UsedAssumedInformation = false;11637auto *CB = cast<CallBase>(getCtxI());11638if (CB->isMustTailCall() &&11639!A.isAssumedDead(IRPosition::inst(*CB), this, nullptr,11640UsedAssumedInformation))11641return indicatePessimisticFixpoint();1164211643SmallVector<AA::ValueAndContext> Values;11644if (!A.getAssumedSimplifiedValues(IRPosition::returned(*Callee), this,11645Values, AA::Intraprocedural,11646UsedAssumedInformation))11647return indicatePessimisticFixpoint();1164811649Function *Caller = CB->getCaller();1165011651bool AnyNonLocal = false;11652for (auto &It : Values) {11653Value *V = It.getValue();11654std::optional<Value *> CallerV = A.translateArgumentToCallSiteContent(11655V, *CB, *this, UsedAssumedInformation);11656if (!CallerV.has_value()) {11657// Nothing to do as long as no value was determined.11658continue;11659}11660V = *CallerV ? *CallerV : V;11661if (AA::isDynamicallyUnique(A, *this, *V) &&11662AA::isValidInScope(*V, Caller)) {11663if (*CallerV) {11664SmallVector<AA::ValueAndContext> ArgValues;11665IRPosition IRP = IRPosition::value(*V);11666if (auto *Arg = dyn_cast<Argument>(V))11667if (Arg->getParent() == CB->getCalledOperand())11668IRP = IRPosition::callsite_argument(*CB, Arg->getArgNo());11669if (recurseForValue(A, IRP, AA::AnyScope))11670continue;11671}11672addValue(A, getState(), *V, CB, AA::AnyScope, getAnchorScope());11673} else {11674AnyNonLocal = true;11675break;11676}11677}11678if (AnyNonLocal) {11679Values.clear();11680if (!A.getAssumedSimplifiedValues(IRPosition::returned(*Callee), this,11681Values, AA::Interprocedural,11682UsedAssumedInformation))11683return indicatePessimisticFixpoint();11684AnyNonLocal = false;11685getState() = PotentialLLVMValuesState::getBestState();11686for (auto &It : Values) {11687Value *V = It.getValue();11688if (!AA::isDynamicallyUnique(A, *this, *V))11689return indicatePessimisticFixpoint();11690if (AA::isValidInScope(*V, Caller)) {11691addValue(A, getState(), *V, CB, AA::AnyScope, getAnchorScope());11692} else {11693AnyNonLocal = true;11694addValue(A, getState(), *V, CB, AA::Interprocedural,11695getAnchorScope());11696}11697}11698if (AnyNonLocal)11699giveUpOnIntraprocedural(A);11700}11701return (AssumedBefore == getAssumed()) ? ChangeStatus::UNCHANGED11702: ChangeStatus::CHANGED;11703}1170411705ChangeStatus indicatePessimisticFixpoint() override {11706return AAPotentialValues::indicatePessimisticFixpoint();11707}1170811709/// See AbstractAttribute::trackStatistics()11710void trackStatistics() const override {11711STATS_DECLTRACK_CSRET_ATTR(potential_values)11712}11713};1171411715struct AAPotentialValuesCallSiteArgument : AAPotentialValuesFloating {11716AAPotentialValuesCallSiteArgument(const IRPosition &IRP, Attributor &A)11717: AAPotentialValuesFloating(IRP, A) {}1171811719/// See AbstractAttribute::trackStatistics()11720void trackStatistics() const override {11721STATS_DECLTRACK_CSARG_ATTR(potential_values)11722}11723};11724} // namespace1172511726/// ---------------------- Assumption Propagation ------------------------------11727namespace {11728struct AAAssumptionInfoImpl : public AAAssumptionInfo {11729AAAssumptionInfoImpl(const IRPosition &IRP, Attributor &A,11730const DenseSet<StringRef> &Known)11731: AAAssumptionInfo(IRP, A, Known) {}1173211733/// See AbstractAttribute::manifest(...).11734ChangeStatus manifest(Attributor &A) override {11735// Don't manifest a universal set if it somehow made it here.11736if (getKnown().isUniversal())11737return ChangeStatus::UNCHANGED;1173811739const IRPosition &IRP = getIRPosition();11740SmallVector<StringRef, 0> Set(getAssumed().getSet().begin(),11741getAssumed().getSet().end());11742llvm::sort(Set);11743return A.manifestAttrs(IRP,11744Attribute::get(IRP.getAnchorValue().getContext(),11745AssumptionAttrKey,11746llvm::join(Set, ",")),11747/*ForceReplace=*/true);11748}1174911750bool hasAssumption(const StringRef Assumption) const override {11751return isValidState() && setContains(Assumption);11752}1175311754/// See AbstractAttribute::getAsStr()11755const std::string getAsStr(Attributor *A) const override {11756const SetContents &Known = getKnown();11757const SetContents &Assumed = getAssumed();1175811759SmallVector<StringRef, 0> Set(Known.getSet().begin(), Known.getSet().end());11760llvm::sort(Set);11761const std::string KnownStr = llvm::join(Set, ",");1176211763std::string AssumedStr = "Universal";11764if (!Assumed.isUniversal()) {11765Set.assign(Assumed.getSet().begin(), Assumed.getSet().end());11766AssumedStr = llvm::join(Set, ",");11767}11768return "Known [" + KnownStr + "]," + " Assumed [" + AssumedStr + "]";11769}11770};1177111772/// Propagates assumption information from parent functions to all of their11773/// successors. An assumption can be propagated if the containing function11774/// dominates the called function.11775///11776/// We start with a "known" set of assumptions already valid for the associated11777/// function and an "assumed" set that initially contains all possible11778/// assumptions. The assumed set is inter-procedurally updated by narrowing its11779/// contents as concrete values are known. The concrete values are seeded by the11780/// first nodes that are either entries into the call graph, or contains no11781/// assumptions. Each node is updated as the intersection of the assumed state11782/// with all of its predecessors.11783struct AAAssumptionInfoFunction final : AAAssumptionInfoImpl {11784AAAssumptionInfoFunction(const IRPosition &IRP, Attributor &A)11785: AAAssumptionInfoImpl(IRP, A,11786getAssumptions(*IRP.getAssociatedFunction())) {}1178711788/// See AbstractAttribute::updateImpl(...).11789ChangeStatus updateImpl(Attributor &A) override {11790bool Changed = false;1179111792auto CallSitePred = [&](AbstractCallSite ACS) {11793const auto *AssumptionAA = A.getAAFor<AAAssumptionInfo>(11794*this, IRPosition::callsite_function(*ACS.getInstruction()),11795DepClassTy::REQUIRED);11796if (!AssumptionAA)11797return false;11798// Get the set of assumptions shared by all of this function's callers.11799Changed |= getIntersection(AssumptionAA->getAssumed());11800return !getAssumed().empty() || !getKnown().empty();11801};1180211803bool UsedAssumedInformation = false;11804// Get the intersection of all assumptions held by this node's predecessors.11805// If we don't know all the call sites then this is either an entry into the11806// call graph or an empty node. This node is known to only contain its own11807// assumptions and can be propagated to its successors.11808if (!A.checkForAllCallSites(CallSitePred, *this, true,11809UsedAssumedInformation))11810return indicatePessimisticFixpoint();1181111812return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;11813}1181411815void trackStatistics() const override {}11816};1181711818/// Assumption Info defined for call sites.11819struct AAAssumptionInfoCallSite final : AAAssumptionInfoImpl {1182011821AAAssumptionInfoCallSite(const IRPosition &IRP, Attributor &A)11822: AAAssumptionInfoImpl(IRP, A, getInitialAssumptions(IRP)) {}1182311824/// See AbstractAttribute::initialize(...).11825void initialize(Attributor &A) override {11826const IRPosition &FnPos = IRPosition::function(*getAnchorScope());11827A.getAAFor<AAAssumptionInfo>(*this, FnPos, DepClassTy::REQUIRED);11828}1182911830/// See AbstractAttribute::updateImpl(...).11831ChangeStatus updateImpl(Attributor &A) override {11832const IRPosition &FnPos = IRPosition::function(*getAnchorScope());11833auto *AssumptionAA =11834A.getAAFor<AAAssumptionInfo>(*this, FnPos, DepClassTy::REQUIRED);11835if (!AssumptionAA)11836return indicatePessimisticFixpoint();11837bool Changed = getIntersection(AssumptionAA->getAssumed());11838return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;11839}1184011841/// See AbstractAttribute::trackStatistics()11842void trackStatistics() const override {}1184311844private:11845/// Helper to initialized the known set as all the assumptions this call and11846/// the callee contain.11847DenseSet<StringRef> getInitialAssumptions(const IRPosition &IRP) {11848const CallBase &CB = cast<CallBase>(IRP.getAssociatedValue());11849auto Assumptions = getAssumptions(CB);11850if (const Function *F = CB.getCaller())11851set_union(Assumptions, getAssumptions(*F));11852if (Function *F = IRP.getAssociatedFunction())11853set_union(Assumptions, getAssumptions(*F));11854return Assumptions;11855}11856};11857} // namespace1185811859AACallGraphNode *AACallEdgeIterator::operator*() const {11860return static_cast<AACallGraphNode *>(const_cast<AACallEdges *>(11861A.getOrCreateAAFor<AACallEdges>(IRPosition::function(**I))));11862}1186311864void AttributorCallGraph::print() { llvm::WriteGraph(outs(), this); }1186511866/// ------------------------ UnderlyingObjects ---------------------------------1186711868namespace {11869struct AAUnderlyingObjectsImpl11870: StateWrapper<BooleanState, AAUnderlyingObjects> {11871using BaseTy = StateWrapper<BooleanState, AAUnderlyingObjects>;11872AAUnderlyingObjectsImpl(const IRPosition &IRP, Attributor &A) : BaseTy(IRP) {}1187311874/// See AbstractAttribute::getAsStr().11875const std::string getAsStr(Attributor *A) const override {11876return std::string("UnderlyingObjects ") +11877(isValidState()11878? (std::string("inter #") +11879std::to_string(InterAssumedUnderlyingObjects.size()) +11880" objs" + std::string(", intra #") +11881std::to_string(IntraAssumedUnderlyingObjects.size()) +11882" objs")11883: "<invalid>");11884}1188511886/// See AbstractAttribute::trackStatistics()11887void trackStatistics() const override {}1188811889/// See AbstractAttribute::updateImpl(...).11890ChangeStatus updateImpl(Attributor &A) override {11891auto &Ptr = getAssociatedValue();1189211893auto DoUpdate = [&](SmallSetVector<Value *, 8> &UnderlyingObjects,11894AA::ValueScope Scope) {11895bool UsedAssumedInformation = false;11896SmallPtrSet<Value *, 8> SeenObjects;11897SmallVector<AA::ValueAndContext> Values;1189811899if (!A.getAssumedSimplifiedValues(IRPosition::value(Ptr), *this, Values,11900Scope, UsedAssumedInformation))11901return UnderlyingObjects.insert(&Ptr);1190211903bool Changed = false;1190411905for (unsigned I = 0; I < Values.size(); ++I) {11906auto &VAC = Values[I];11907auto *Obj = VAC.getValue();11908Value *UO = getUnderlyingObject(Obj);11909if (UO && UO != VAC.getValue() && SeenObjects.insert(UO).second) {11910const auto *OtherAA = A.getAAFor<AAUnderlyingObjects>(11911*this, IRPosition::value(*UO), DepClassTy::OPTIONAL);11912auto Pred = [&Values](Value &V) {11913Values.emplace_back(V, nullptr);11914return true;11915};1191611917if (!OtherAA || !OtherAA->forallUnderlyingObjects(Pred, Scope))11918llvm_unreachable(11919"The forall call should not return false at this position");1192011921continue;11922}1192311924if (isa<SelectInst>(Obj)) {11925Changed |= handleIndirect(A, *Obj, UnderlyingObjects, Scope);11926continue;11927}11928if (auto *PHI = dyn_cast<PHINode>(Obj)) {11929// Explicitly look through PHIs as we do not care about dynamically11930// uniqueness.11931for (unsigned u = 0, e = PHI->getNumIncomingValues(); u < e; u++) {11932Changed |= handleIndirect(A, *PHI->getIncomingValue(u),11933UnderlyingObjects, Scope);11934}11935continue;11936}1193711938Changed |= UnderlyingObjects.insert(Obj);11939}1194011941return Changed;11942};1194311944bool Changed = false;11945Changed |= DoUpdate(IntraAssumedUnderlyingObjects, AA::Intraprocedural);11946Changed |= DoUpdate(InterAssumedUnderlyingObjects, AA::Interprocedural);1194711948return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;11949}1195011951bool forallUnderlyingObjects(11952function_ref<bool(Value &)> Pred,11953AA::ValueScope Scope = AA::Interprocedural) const override {11954if (!isValidState())11955return Pred(getAssociatedValue());1195611957auto &AssumedUnderlyingObjects = Scope == AA::Intraprocedural11958? IntraAssumedUnderlyingObjects11959: InterAssumedUnderlyingObjects;11960for (Value *Obj : AssumedUnderlyingObjects)11961if (!Pred(*Obj))11962return false;1196311964return true;11965}1196611967private:11968/// Handle the case where the value is not the actual underlying value, such11969/// as a phi node or a select instruction.11970bool handleIndirect(Attributor &A, Value &V,11971SmallSetVector<Value *, 8> &UnderlyingObjects,11972AA::ValueScope Scope) {11973bool Changed = false;11974const auto *AA = A.getAAFor<AAUnderlyingObjects>(11975*this, IRPosition::value(V), DepClassTy::OPTIONAL);11976auto Pred = [&](Value &V) {11977Changed |= UnderlyingObjects.insert(&V);11978return true;11979};11980if (!AA || !AA->forallUnderlyingObjects(Pred, Scope))11981llvm_unreachable(11982"The forall call should not return false at this position");11983return Changed;11984}1198511986/// All the underlying objects collected so far via intra procedural scope.11987SmallSetVector<Value *, 8> IntraAssumedUnderlyingObjects;11988/// All the underlying objects collected so far via inter procedural scope.11989SmallSetVector<Value *, 8> InterAssumedUnderlyingObjects;11990};1199111992struct AAUnderlyingObjectsFloating final : AAUnderlyingObjectsImpl {11993AAUnderlyingObjectsFloating(const IRPosition &IRP, Attributor &A)11994: AAUnderlyingObjectsImpl(IRP, A) {}11995};1199611997struct AAUnderlyingObjectsArgument final : AAUnderlyingObjectsImpl {11998AAUnderlyingObjectsArgument(const IRPosition &IRP, Attributor &A)11999: AAUnderlyingObjectsImpl(IRP, A) {}12000};1200112002struct AAUnderlyingObjectsCallSite final : AAUnderlyingObjectsImpl {12003AAUnderlyingObjectsCallSite(const IRPosition &IRP, Attributor &A)12004: AAUnderlyingObjectsImpl(IRP, A) {}12005};1200612007struct AAUnderlyingObjectsCallSiteArgument final : AAUnderlyingObjectsImpl {12008AAUnderlyingObjectsCallSiteArgument(const IRPosition &IRP, Attributor &A)12009: AAUnderlyingObjectsImpl(IRP, A) {}12010};1201112012struct AAUnderlyingObjectsReturned final : AAUnderlyingObjectsImpl {12013AAUnderlyingObjectsReturned(const IRPosition &IRP, Attributor &A)12014: AAUnderlyingObjectsImpl(IRP, A) {}12015};1201612017struct AAUnderlyingObjectsCallSiteReturned final : AAUnderlyingObjectsImpl {12018AAUnderlyingObjectsCallSiteReturned(const IRPosition &IRP, Attributor &A)12019: AAUnderlyingObjectsImpl(IRP, A) {}12020};1202112022struct AAUnderlyingObjectsFunction final : AAUnderlyingObjectsImpl {12023AAUnderlyingObjectsFunction(const IRPosition &IRP, Attributor &A)12024: AAUnderlyingObjectsImpl(IRP, A) {}12025};12026} // namespace1202712028/// ------------------------ Global Value Info -------------------------------12029namespace {12030struct AAGlobalValueInfoFloating : public AAGlobalValueInfo {12031AAGlobalValueInfoFloating(const IRPosition &IRP, Attributor &A)12032: AAGlobalValueInfo(IRP, A) {}1203312034/// See AbstractAttribute::initialize(...).12035void initialize(Attributor &A) override {}1203612037bool checkUse(Attributor &A, const Use &U, bool &Follow,12038SmallVectorImpl<const Value *> &Worklist) {12039Instruction *UInst = dyn_cast<Instruction>(U.getUser());12040if (!UInst) {12041Follow = true;12042return true;12043}1204412045LLVM_DEBUG(dbgs() << "[AAGlobalValueInfo] Check use: " << *U.get() << " in "12046<< *UInst << "\n");1204712048if (auto *Cmp = dyn_cast<ICmpInst>(U.getUser())) {12049int Idx = &Cmp->getOperandUse(0) == &U;12050if (isa<Constant>(Cmp->getOperand(Idx)))12051return true;12052return U == &getAnchorValue();12053}1205412055// Explicitly catch return instructions.12056if (isa<ReturnInst>(UInst)) {12057auto CallSitePred = [&](AbstractCallSite ACS) {12058Worklist.push_back(ACS.getInstruction());12059return true;12060};12061bool UsedAssumedInformation = false;12062// TODO: We should traverse the uses or add a "non-call-site" CB.12063if (!A.checkForAllCallSites(CallSitePred, *UInst->getFunction(),12064/*RequireAllCallSites=*/true, this,12065UsedAssumedInformation))12066return false;12067return true;12068}1206912070// For now we only use special logic for call sites. However, the tracker12071// itself knows about a lot of other non-capturing cases already.12072auto *CB = dyn_cast<CallBase>(UInst);12073if (!CB)12074return false;12075// Direct calls are OK uses.12076if (CB->isCallee(&U))12077return true;12078// Non-argument uses are scary.12079if (!CB->isArgOperand(&U))12080return false;12081// TODO: Iterate callees.12082auto *Fn = dyn_cast<Function>(CB->getCalledOperand());12083if (!Fn || !A.isFunctionIPOAmendable(*Fn))12084return false;1208512086unsigned ArgNo = CB->getArgOperandNo(&U);12087Worklist.push_back(Fn->getArg(ArgNo));12088return true;12089}1209012091ChangeStatus updateImpl(Attributor &A) override {12092unsigned NumUsesBefore = Uses.size();1209312094SmallPtrSet<const Value *, 8> Visited;12095SmallVector<const Value *> Worklist;12096Worklist.push_back(&getAnchorValue());1209712098auto UsePred = [&](const Use &U, bool &Follow) -> bool {12099Uses.insert(&U);12100switch (DetermineUseCaptureKind(U, nullptr)) {12101case UseCaptureKind::NO_CAPTURE:12102return checkUse(A, U, Follow, Worklist);12103case UseCaptureKind::MAY_CAPTURE:12104return checkUse(A, U, Follow, Worklist);12105case UseCaptureKind::PASSTHROUGH:12106Follow = true;12107return true;12108}12109return true;12110};12111auto EquivalentUseCB = [&](const Use &OldU, const Use &NewU) {12112Uses.insert(&OldU);12113return true;12114};1211512116while (!Worklist.empty()) {12117const Value *V = Worklist.pop_back_val();12118if (!Visited.insert(V).second)12119continue;12120if (!A.checkForAllUses(UsePred, *this, *V,12121/* CheckBBLivenessOnly */ true,12122DepClassTy::OPTIONAL,12123/* IgnoreDroppableUses */ true, EquivalentUseCB)) {12124return indicatePessimisticFixpoint();12125}12126}1212712128return Uses.size() == NumUsesBefore ? ChangeStatus::UNCHANGED12129: ChangeStatus::CHANGED;12130}1213112132bool isPotentialUse(const Use &U) const override {12133return !isValidState() || Uses.contains(&U);12134}1213512136/// See AbstractAttribute::manifest(...).12137ChangeStatus manifest(Attributor &A) override {12138return ChangeStatus::UNCHANGED;12139}1214012141/// See AbstractAttribute::getAsStr().12142const std::string getAsStr(Attributor *A) const override {12143return "[" + std::to_string(Uses.size()) + " uses]";12144}1214512146void trackStatistics() const override {12147STATS_DECLTRACK_FLOATING_ATTR(GlobalValuesTracked);12148}1214912150private:12151/// Set of (transitive) uses of this GlobalValue.12152SmallPtrSet<const Use *, 8> Uses;12153};12154} // namespace1215512156/// ------------------------ Indirect Call Info -------------------------------12157namespace {12158struct AAIndirectCallInfoCallSite : public AAIndirectCallInfo {12159AAIndirectCallInfoCallSite(const IRPosition &IRP, Attributor &A)12160: AAIndirectCallInfo(IRP, A) {}1216112162/// See AbstractAttribute::initialize(...).12163void initialize(Attributor &A) override {12164auto *MD = getCtxI()->getMetadata(LLVMContext::MD_callees);12165if (!MD && !A.isClosedWorldModule())12166return;1216712168if (MD) {12169for (const auto &Op : MD->operands())12170if (Function *Callee = mdconst::dyn_extract_or_null<Function>(Op))12171PotentialCallees.insert(Callee);12172} else if (A.isClosedWorldModule()) {12173ArrayRef<Function *> IndirectlyCallableFunctions =12174A.getInfoCache().getIndirectlyCallableFunctions(A);12175PotentialCallees.insert(IndirectlyCallableFunctions.begin(),12176IndirectlyCallableFunctions.end());12177}1217812179if (PotentialCallees.empty())12180indicateOptimisticFixpoint();12181}1218212183ChangeStatus updateImpl(Attributor &A) override {12184CallBase *CB = cast<CallBase>(getCtxI());12185const Use &CalleeUse = CB->getCalledOperandUse();12186Value *FP = CB->getCalledOperand();1218712188SmallSetVector<Function *, 4> AssumedCalleesNow;12189bool AllCalleesKnownNow = AllCalleesKnown;1219012191auto CheckPotentialCalleeUse = [&](Function &PotentialCallee,12192bool &UsedAssumedInformation) {12193const auto *GIAA = A.getAAFor<AAGlobalValueInfo>(12194*this, IRPosition::value(PotentialCallee), DepClassTy::OPTIONAL);12195if (!GIAA || GIAA->isPotentialUse(CalleeUse))12196return true;12197UsedAssumedInformation = !GIAA->isAtFixpoint();12198return false;12199};1220012201auto AddPotentialCallees = [&]() {12202for (auto *PotentialCallee : PotentialCallees) {12203bool UsedAssumedInformation = false;12204if (CheckPotentialCalleeUse(*PotentialCallee, UsedAssumedInformation))12205AssumedCalleesNow.insert(PotentialCallee);12206}12207};1220812209// Use simplification to find potential callees, if !callees was present,12210// fallback to that set if necessary.12211bool UsedAssumedInformation = false;12212SmallVector<AA::ValueAndContext> Values;12213if (!A.getAssumedSimplifiedValues(IRPosition::value(*FP), this, Values,12214AA::ValueScope::AnyScope,12215UsedAssumedInformation)) {12216if (PotentialCallees.empty())12217return indicatePessimisticFixpoint();12218AddPotentialCallees();12219}1222012221// Try to find a reason for \p Fn not to be a potential callee. If none was12222// found, add it to the assumed callees set.12223auto CheckPotentialCallee = [&](Function &Fn) {12224if (!PotentialCallees.empty() && !PotentialCallees.count(&Fn))12225return false;1222612227auto &CachedResult = FilterResults[&Fn];12228if (CachedResult.has_value())12229return CachedResult.value();1223012231bool UsedAssumedInformation = false;12232if (!CheckPotentialCalleeUse(Fn, UsedAssumedInformation)) {12233if (!UsedAssumedInformation)12234CachedResult = false;12235return false;12236}1223712238int NumFnArgs = Fn.arg_size();12239int NumCBArgs = CB->arg_size();1224012241// Check if any excess argument (which we fill up with poison) is known to12242// be UB on undef.12243for (int I = NumCBArgs; I < NumFnArgs; ++I) {12244bool IsKnown = false;12245if (AA::hasAssumedIRAttr<Attribute::NoUndef>(12246A, this, IRPosition::argument(*Fn.getArg(I)),12247DepClassTy::OPTIONAL, IsKnown)) {12248if (IsKnown)12249CachedResult = false;12250return false;12251}12252}1225312254CachedResult = true;12255return true;12256};1225712258// Check simplification result, prune known UB callees, also restrict it to12259// the !callees set, if present.12260for (auto &VAC : Values) {12261if (isa<UndefValue>(VAC.getValue()))12262continue;12263if (isa<ConstantPointerNull>(VAC.getValue()) &&12264VAC.getValue()->getType()->getPointerAddressSpace() == 0)12265continue;12266// TODO: Check for known UB, e.g., poison + noundef.12267if (auto *VACFn = dyn_cast<Function>(VAC.getValue())) {12268if (CheckPotentialCallee(*VACFn))12269AssumedCalleesNow.insert(VACFn);12270continue;12271}12272if (!PotentialCallees.empty()) {12273AddPotentialCallees();12274break;12275}12276AllCalleesKnownNow = false;12277}1227812279if (AssumedCalleesNow == AssumedCallees &&12280AllCalleesKnown == AllCalleesKnownNow)12281return ChangeStatus::UNCHANGED;1228212283std::swap(AssumedCallees, AssumedCalleesNow);12284AllCalleesKnown = AllCalleesKnownNow;12285return ChangeStatus::CHANGED;12286}1228712288/// See AbstractAttribute::manifest(...).12289ChangeStatus manifest(Attributor &A) override {12290// If we can't specialize at all, give up now.12291if (!AllCalleesKnown && AssumedCallees.empty())12292return ChangeStatus::UNCHANGED;1229312294CallBase *CB = cast<CallBase>(getCtxI());12295bool UsedAssumedInformation = false;12296if (A.isAssumedDead(*CB, this, /*LivenessAA=*/nullptr,12297UsedAssumedInformation))12298return ChangeStatus::UNCHANGED;1229912300ChangeStatus Changed = ChangeStatus::UNCHANGED;12301Value *FP = CB->getCalledOperand();12302if (FP->getType()->getPointerAddressSpace())12303FP = new AddrSpaceCastInst(FP, PointerType::get(FP->getType(), 0),12304FP->getName() + ".as0", CB->getIterator());1230512306bool CBIsVoid = CB->getType()->isVoidTy();12307BasicBlock::iterator IP = CB->getIterator();12308FunctionType *CSFT = CB->getFunctionType();12309SmallVector<Value *> CSArgs(CB->arg_begin(), CB->arg_end());1231012311// If we know all callees and there are none, the call site is (effectively)12312// dead (or UB).12313if (AssumedCallees.empty()) {12314assert(AllCalleesKnown &&12315"Expected all callees to be known if there are none.");12316A.changeToUnreachableAfterManifest(CB);12317return ChangeStatus::CHANGED;12318}1231912320// Special handling for the single callee case.12321if (AllCalleesKnown && AssumedCallees.size() == 1) {12322auto *NewCallee = AssumedCallees.front();12323if (isLegalToPromote(*CB, NewCallee)) {12324promoteCall(*CB, NewCallee, nullptr);12325return ChangeStatus::CHANGED;12326}12327Instruction *NewCall =12328CallInst::Create(FunctionCallee(CSFT, NewCallee), CSArgs,12329CB->getName(), CB->getIterator());12330if (!CBIsVoid)12331A.changeAfterManifest(IRPosition::callsite_returned(*CB), *NewCall);12332A.deleteAfterManifest(*CB);12333return ChangeStatus::CHANGED;12334}1233512336// For each potential value we create a conditional12337//12338// ```12339// if (ptr == value) value(args);12340// else ...12341// ```12342//12343bool SpecializedForAnyCallees = false;12344bool SpecializedForAllCallees = AllCalleesKnown;12345ICmpInst *LastCmp = nullptr;12346SmallVector<Function *, 8> SkippedAssumedCallees;12347SmallVector<std::pair<CallInst *, Instruction *>> NewCalls;12348for (Function *NewCallee : AssumedCallees) {12349if (!A.shouldSpecializeCallSiteForCallee(*this, *CB, *NewCallee)) {12350SkippedAssumedCallees.push_back(NewCallee);12351SpecializedForAllCallees = false;12352continue;12353}12354SpecializedForAnyCallees = true;1235512356LastCmp = new ICmpInst(IP, llvm::CmpInst::ICMP_EQ, FP, NewCallee);12357Instruction *ThenTI =12358SplitBlockAndInsertIfThen(LastCmp, IP, /* Unreachable */ false);12359BasicBlock *CBBB = CB->getParent();12360A.registerManifestAddedBasicBlock(*ThenTI->getParent());12361A.registerManifestAddedBasicBlock(*IP->getParent());12362auto *SplitTI = cast<BranchInst>(LastCmp->getNextNode());12363BasicBlock *ElseBB;12364if (&*IP == CB) {12365ElseBB = BasicBlock::Create(ThenTI->getContext(), "",12366ThenTI->getFunction(), CBBB);12367A.registerManifestAddedBasicBlock(*ElseBB);12368IP = BranchInst::Create(CBBB, ElseBB)->getIterator();12369SplitTI->replaceUsesOfWith(CBBB, ElseBB);12370} else {12371ElseBB = IP->getParent();12372ThenTI->replaceUsesOfWith(ElseBB, CBBB);12373}12374CastInst *RetBC = nullptr;12375CallInst *NewCall = nullptr;12376if (isLegalToPromote(*CB, NewCallee)) {12377auto *CBClone = cast<CallBase>(CB->clone());12378CBClone->insertBefore(ThenTI);12379NewCall = &cast<CallInst>(promoteCall(*CBClone, NewCallee, &RetBC));12380} else {12381NewCall = CallInst::Create(FunctionCallee(CSFT, NewCallee), CSArgs,12382CB->getName(), ThenTI->getIterator());12383}12384NewCalls.push_back({NewCall, RetBC});12385}1238612387auto AttachCalleeMetadata = [&](CallBase &IndirectCB) {12388if (!AllCalleesKnown)12389return ChangeStatus::UNCHANGED;12390MDBuilder MDB(IndirectCB.getContext());12391MDNode *Callees = MDB.createCallees(SkippedAssumedCallees);12392IndirectCB.setMetadata(LLVMContext::MD_callees, Callees);12393return ChangeStatus::CHANGED;12394};1239512396if (!SpecializedForAnyCallees)12397return AttachCalleeMetadata(*CB);1239812399// Check if we need the fallback indirect call still.12400if (SpecializedForAllCallees) {12401LastCmp->replaceAllUsesWith(ConstantInt::getTrue(LastCmp->getContext()));12402LastCmp->eraseFromParent();12403new UnreachableInst(IP->getContext(), IP);12404IP->eraseFromParent();12405} else {12406auto *CBClone = cast<CallInst>(CB->clone());12407CBClone->setName(CB->getName());12408CBClone->insertBefore(*IP->getParent(), IP);12409NewCalls.push_back({CBClone, nullptr});12410AttachCalleeMetadata(*CBClone);12411}1241212413// Check if we need a PHI to merge the results.12414if (!CBIsVoid) {12415auto *PHI = PHINode::Create(CB->getType(), NewCalls.size(),12416CB->getName() + ".phi",12417CB->getParent()->getFirstInsertionPt());12418for (auto &It : NewCalls) {12419CallBase *NewCall = It.first;12420Instruction *CallRet = It.second ? It.second : It.first;12421if (CallRet->getType() == CB->getType())12422PHI->addIncoming(CallRet, CallRet->getParent());12423else if (NewCall->getType()->isVoidTy())12424PHI->addIncoming(PoisonValue::get(CB->getType()),12425NewCall->getParent());12426else12427llvm_unreachable("Call return should match or be void!");12428}12429A.changeAfterManifest(IRPosition::callsite_returned(*CB), *PHI);12430}1243112432A.deleteAfterManifest(*CB);12433Changed = ChangeStatus::CHANGED;1243412435return Changed;12436}1243712438/// See AbstractAttribute::getAsStr().12439const std::string getAsStr(Attributor *A) const override {12440return std::string(AllCalleesKnown ? "eliminate" : "specialize") +12441" indirect call site with " + std::to_string(AssumedCallees.size()) +12442" functions";12443}1244412445void trackStatistics() const override {12446if (AllCalleesKnown) {12447STATS_DECLTRACK(12448Eliminated, CallSites,12449"Number of indirect call sites eliminated via specialization")12450} else {12451STATS_DECLTRACK(Specialized, CallSites,12452"Number of indirect call sites specialized")12453}12454}1245512456bool foreachCallee(function_ref<bool(Function *)> CB) const override {12457return isValidState() && AllCalleesKnown && all_of(AssumedCallees, CB);12458}1245912460private:12461/// Map to remember filter results.12462DenseMap<Function *, std::optional<bool>> FilterResults;1246312464/// If the !callee metadata was present, this set will contain all potential12465/// callees (superset).12466SmallSetVector<Function *, 4> PotentialCallees;1246712468/// This set contains all currently assumed calllees, which might grow over12469/// time.12470SmallSetVector<Function *, 4> AssumedCallees;1247112472/// Flag to indicate if all possible callees are in the AssumedCallees set or12473/// if there could be others.12474bool AllCalleesKnown = true;12475};12476} // namespace1247712478/// ------------------------ Address Space ------------------------------------12479namespace {12480struct AAAddressSpaceImpl : public AAAddressSpace {12481AAAddressSpaceImpl(const IRPosition &IRP, Attributor &A)12482: AAAddressSpace(IRP, A) {}1248312484int32_t getAddressSpace() const override {12485assert(isValidState() && "the AA is invalid");12486return AssumedAddressSpace;12487}1248812489/// See AbstractAttribute::initialize(...).12490void initialize(Attributor &A) override {12491assert(getAssociatedType()->isPtrOrPtrVectorTy() &&12492"Associated value is not a pointer");12493}1249412495ChangeStatus updateImpl(Attributor &A) override {12496int32_t OldAddressSpace = AssumedAddressSpace;12497auto *AUO = A.getOrCreateAAFor<AAUnderlyingObjects>(getIRPosition(), this,12498DepClassTy::REQUIRED);12499auto Pred = [&](Value &Obj) {12500if (isa<UndefValue>(&Obj))12501return true;12502return takeAddressSpace(Obj.getType()->getPointerAddressSpace());12503};1250412505if (!AUO->forallUnderlyingObjects(Pred))12506return indicatePessimisticFixpoint();1250712508return OldAddressSpace == AssumedAddressSpace ? ChangeStatus::UNCHANGED12509: ChangeStatus::CHANGED;12510}1251112512/// See AbstractAttribute::manifest(...).12513ChangeStatus manifest(Attributor &A) override {12514Value *AssociatedValue = &getAssociatedValue();12515Value *OriginalValue = peelAddrspacecast(AssociatedValue);12516if (getAddressSpace() == NoAddressSpace ||12517static_cast<uint32_t>(getAddressSpace()) ==12518getAssociatedType()->getPointerAddressSpace())12519return ChangeStatus::UNCHANGED;1252012521Type *NewPtrTy = PointerType::get(getAssociatedType()->getContext(),12522static_cast<uint32_t>(getAddressSpace()));12523bool UseOriginalValue =12524OriginalValue->getType()->getPointerAddressSpace() ==12525static_cast<uint32_t>(getAddressSpace());1252612527bool Changed = false;1252812529auto MakeChange = [&](Instruction *I, Use &U) {12530Changed = true;12531if (UseOriginalValue) {12532A.changeUseAfterManifest(U, *OriginalValue);12533return;12534}12535Instruction *CastInst = new AddrSpaceCastInst(OriginalValue, NewPtrTy);12536CastInst->insertBefore(cast<Instruction>(I));12537A.changeUseAfterManifest(U, *CastInst);12538};1253912540auto Pred = [&](const Use &U, bool &) {12541if (U.get() != AssociatedValue)12542return true;12543auto *Inst = dyn_cast<Instruction>(U.getUser());12544if (!Inst)12545return true;12546// This is a WA to make sure we only change uses from the corresponding12547// CGSCC if the AA is run on CGSCC instead of the entire module.12548if (!A.isRunOn(Inst->getFunction()))12549return true;12550if (isa<LoadInst>(Inst))12551MakeChange(Inst, const_cast<Use &>(U));12552if (isa<StoreInst>(Inst)) {12553// We only make changes if the use is the pointer operand.12554if (U.getOperandNo() == 1)12555MakeChange(Inst, const_cast<Use &>(U));12556}12557return true;12558};1255912560// It doesn't matter if we can't check all uses as we can simply12561// conservatively ignore those that can not be visited.12562(void)A.checkForAllUses(Pred, *this, getAssociatedValue(),12563/* CheckBBLivenessOnly */ true);1256412565return Changed ? ChangeStatus::CHANGED : ChangeStatus::UNCHANGED;12566}1256712568/// See AbstractAttribute::getAsStr().12569const std::string getAsStr(Attributor *A) const override {12570if (!isValidState())12571return "addrspace(<invalid>)";12572return "addrspace(" +12573(AssumedAddressSpace == NoAddressSpace12574? "none"12575: std::to_string(AssumedAddressSpace)) +12576")";12577}1257812579private:12580int32_t AssumedAddressSpace = NoAddressSpace;1258112582bool takeAddressSpace(int32_t AS) {12583if (AssumedAddressSpace == NoAddressSpace) {12584AssumedAddressSpace = AS;12585return true;12586}12587return AssumedAddressSpace == AS;12588}1258912590static Value *peelAddrspacecast(Value *V) {12591if (auto *I = dyn_cast<AddrSpaceCastInst>(V))12592return peelAddrspacecast(I->getPointerOperand());12593if (auto *C = dyn_cast<ConstantExpr>(V))12594if (C->getOpcode() == Instruction::AddrSpaceCast)12595return peelAddrspacecast(C->getOperand(0));12596return V;12597}12598};1259912600struct AAAddressSpaceFloating final : AAAddressSpaceImpl {12601AAAddressSpaceFloating(const IRPosition &IRP, Attributor &A)12602: AAAddressSpaceImpl(IRP, A) {}1260312604void trackStatistics() const override {12605STATS_DECLTRACK_FLOATING_ATTR(addrspace);12606}12607};1260812609struct AAAddressSpaceReturned final : AAAddressSpaceImpl {12610AAAddressSpaceReturned(const IRPosition &IRP, Attributor &A)12611: AAAddressSpaceImpl(IRP, A) {}1261212613/// See AbstractAttribute::initialize(...).12614void initialize(Attributor &A) override {12615// TODO: we don't rewrite function argument for now because it will need to12616// rewrite the function signature and all call sites.12617(void)indicatePessimisticFixpoint();12618}1261912620void trackStatistics() const override {12621STATS_DECLTRACK_FNRET_ATTR(addrspace);12622}12623};1262412625struct AAAddressSpaceCallSiteReturned final : AAAddressSpaceImpl {12626AAAddressSpaceCallSiteReturned(const IRPosition &IRP, Attributor &A)12627: AAAddressSpaceImpl(IRP, A) {}1262812629void trackStatistics() const override {12630STATS_DECLTRACK_CSRET_ATTR(addrspace);12631}12632};1263312634struct AAAddressSpaceArgument final : AAAddressSpaceImpl {12635AAAddressSpaceArgument(const IRPosition &IRP, Attributor &A)12636: AAAddressSpaceImpl(IRP, A) {}1263712638void trackStatistics() const override { STATS_DECLTRACK_ARG_ATTR(addrspace); }12639};1264012641struct AAAddressSpaceCallSiteArgument final : AAAddressSpaceImpl {12642AAAddressSpaceCallSiteArgument(const IRPosition &IRP, Attributor &A)12643: AAAddressSpaceImpl(IRP, A) {}1264412645/// See AbstractAttribute::initialize(...).12646void initialize(Attributor &A) override {12647// TODO: we don't rewrite call site argument for now because it will need to12648// rewrite the function signature of the callee.12649(void)indicatePessimisticFixpoint();12650}1265112652void trackStatistics() const override {12653STATS_DECLTRACK_CSARG_ATTR(addrspace);12654}12655};12656} // namespace1265712658/// ----------- Allocation Info ----------12659namespace {12660struct AAAllocationInfoImpl : public AAAllocationInfo {12661AAAllocationInfoImpl(const IRPosition &IRP, Attributor &A)12662: AAAllocationInfo(IRP, A) {}1266312664std::optional<TypeSize> getAllocatedSize() const override {12665assert(isValidState() && "the AA is invalid");12666return AssumedAllocatedSize;12667}1266812669std::optional<TypeSize> findInitialAllocationSize(Instruction *I,12670const DataLayout &DL) {1267112672// TODO: implement case for malloc like instructions12673switch (I->getOpcode()) {12674case Instruction::Alloca: {12675AllocaInst *AI = cast<AllocaInst>(I);12676return AI->getAllocationSize(DL);12677}12678default:12679return std::nullopt;12680}12681}1268212683ChangeStatus updateImpl(Attributor &A) override {1268412685const IRPosition &IRP = getIRPosition();12686Instruction *I = IRP.getCtxI();1268712688// TODO: update check for malloc like calls12689if (!isa<AllocaInst>(I))12690return indicatePessimisticFixpoint();1269112692bool IsKnownNoCapture;12693if (!AA::hasAssumedIRAttr<Attribute::NoCapture>(12694A, this, IRP, DepClassTy::OPTIONAL, IsKnownNoCapture))12695return indicatePessimisticFixpoint();1269612697const AAPointerInfo *PI =12698A.getOrCreateAAFor<AAPointerInfo>(IRP, *this, DepClassTy::REQUIRED);1269912700if (!PI)12701return indicatePessimisticFixpoint();1270212703if (!PI->getState().isValidState())12704return indicatePessimisticFixpoint();1270512706const DataLayout &DL = A.getDataLayout();12707const auto AllocationSize = findInitialAllocationSize(I, DL);1270812709// If allocation size is nullopt, we give up.12710if (!AllocationSize)12711return indicatePessimisticFixpoint();1271212713// For zero sized allocations, we give up.12714// Since we can't reduce further12715if (*AllocationSize == 0)12716return indicatePessimisticFixpoint();1271712718int64_t BinSize = PI->numOffsetBins();1271912720// TODO: implement for multiple bins12721if (BinSize > 1)12722return indicatePessimisticFixpoint();1272312724if (BinSize == 0) {12725auto NewAllocationSize = std::optional<TypeSize>(TypeSize(0, false));12726if (!changeAllocationSize(NewAllocationSize))12727return ChangeStatus::UNCHANGED;12728return ChangeStatus::CHANGED;12729}1273012731// TODO: refactor this to be part of multiple bin case12732const auto &It = PI->begin();1273312734// TODO: handle if Offset is not zero12735if (It->first.Offset != 0)12736return indicatePessimisticFixpoint();1273712738uint64_t SizeOfBin = It->first.Offset + It->first.Size;1273912740if (SizeOfBin >= *AllocationSize)12741return indicatePessimisticFixpoint();1274212743auto NewAllocationSize =12744std::optional<TypeSize>(TypeSize(SizeOfBin * 8, false));1274512746if (!changeAllocationSize(NewAllocationSize))12747return ChangeStatus::UNCHANGED;1274812749return ChangeStatus::CHANGED;12750}1275112752/// See AbstractAttribute::manifest(...).12753ChangeStatus manifest(Attributor &A) override {1275412755assert(isValidState() &&12756"Manifest should only be called if the state is valid.");1275712758Instruction *I = getIRPosition().getCtxI();1275912760auto FixedAllocatedSizeInBits = getAllocatedSize()->getFixedValue();1276112762unsigned long NumBytesToAllocate = (FixedAllocatedSizeInBits + 7) / 8;1276312764switch (I->getOpcode()) {12765// TODO: add case for malloc like calls12766case Instruction::Alloca: {1276712768AllocaInst *AI = cast<AllocaInst>(I);1276912770Type *CharType = Type::getInt8Ty(I->getContext());1277112772auto *NumBytesToValue =12773ConstantInt::get(I->getContext(), APInt(32, NumBytesToAllocate));1277412775BasicBlock::iterator insertPt = AI->getIterator();12776insertPt = std::next(insertPt);12777AllocaInst *NewAllocaInst =12778new AllocaInst(CharType, AI->getAddressSpace(), NumBytesToValue,12779AI->getAlign(), AI->getName(), insertPt);1278012781if (A.changeAfterManifest(IRPosition::inst(*AI), *NewAllocaInst))12782return ChangeStatus::CHANGED;1278312784break;12785}12786default:12787break;12788}1278912790return ChangeStatus::UNCHANGED;12791}1279212793/// See AbstractAttribute::getAsStr().12794const std::string getAsStr(Attributor *A) const override {12795if (!isValidState())12796return "allocationinfo(<invalid>)";12797return "allocationinfo(" +12798(AssumedAllocatedSize == HasNoAllocationSize12799? "none"12800: std::to_string(AssumedAllocatedSize->getFixedValue())) +12801")";12802}1280312804private:12805std::optional<TypeSize> AssumedAllocatedSize = HasNoAllocationSize;1280612807// Maintain the computed allocation size of the object.12808// Returns (bool) weather the size of the allocation was modified or not.12809bool changeAllocationSize(std::optional<TypeSize> Size) {12810if (AssumedAllocatedSize == HasNoAllocationSize ||12811AssumedAllocatedSize != Size) {12812AssumedAllocatedSize = Size;12813return true;12814}12815return false;12816}12817};1281812819struct AAAllocationInfoFloating : AAAllocationInfoImpl {12820AAAllocationInfoFloating(const IRPosition &IRP, Attributor &A)12821: AAAllocationInfoImpl(IRP, A) {}1282212823void trackStatistics() const override {12824STATS_DECLTRACK_FLOATING_ATTR(allocationinfo);12825}12826};1282712828struct AAAllocationInfoReturned : AAAllocationInfoImpl {12829AAAllocationInfoReturned(const IRPosition &IRP, Attributor &A)12830: AAAllocationInfoImpl(IRP, A) {}1283112832/// See AbstractAttribute::initialize(...).12833void initialize(Attributor &A) override {12834// TODO: we don't rewrite function argument for now because it will need to12835// rewrite the function signature and all call sites12836(void)indicatePessimisticFixpoint();12837}1283812839void trackStatistics() const override {12840STATS_DECLTRACK_FNRET_ATTR(allocationinfo);12841}12842};1284312844struct AAAllocationInfoCallSiteReturned : AAAllocationInfoImpl {12845AAAllocationInfoCallSiteReturned(const IRPosition &IRP, Attributor &A)12846: AAAllocationInfoImpl(IRP, A) {}1284712848void trackStatistics() const override {12849STATS_DECLTRACK_CSRET_ATTR(allocationinfo);12850}12851};1285212853struct AAAllocationInfoArgument : AAAllocationInfoImpl {12854AAAllocationInfoArgument(const IRPosition &IRP, Attributor &A)12855: AAAllocationInfoImpl(IRP, A) {}1285612857void trackStatistics() const override {12858STATS_DECLTRACK_ARG_ATTR(allocationinfo);12859}12860};1286112862struct AAAllocationInfoCallSiteArgument : AAAllocationInfoImpl {12863AAAllocationInfoCallSiteArgument(const IRPosition &IRP, Attributor &A)12864: AAAllocationInfoImpl(IRP, A) {}1286512866/// See AbstractAttribute::initialize(...).12867void initialize(Attributor &A) override {1286812869(void)indicatePessimisticFixpoint();12870}1287112872void trackStatistics() const override {12873STATS_DECLTRACK_CSARG_ATTR(allocationinfo);12874}12875};12876} // namespace1287712878const char AANoUnwind::ID = 0;12879const char AANoSync::ID = 0;12880const char AANoFree::ID = 0;12881const char AANonNull::ID = 0;12882const char AAMustProgress::ID = 0;12883const char AANoRecurse::ID = 0;12884const char AANonConvergent::ID = 0;12885const char AAWillReturn::ID = 0;12886const char AAUndefinedBehavior::ID = 0;12887const char AANoAlias::ID = 0;12888const char AAIntraFnReachability::ID = 0;12889const char AANoReturn::ID = 0;12890const char AAIsDead::ID = 0;12891const char AADereferenceable::ID = 0;12892const char AAAlign::ID = 0;12893const char AAInstanceInfo::ID = 0;12894const char AANoCapture::ID = 0;12895const char AAValueSimplify::ID = 0;12896const char AAHeapToStack::ID = 0;12897const char AAPrivatizablePtr::ID = 0;12898const char AAMemoryBehavior::ID = 0;12899const char AAMemoryLocation::ID = 0;12900const char AAValueConstantRange::ID = 0;12901const char AAPotentialConstantValues::ID = 0;12902const char AAPotentialValues::ID = 0;12903const char AANoUndef::ID = 0;12904const char AANoFPClass::ID = 0;12905const char AACallEdges::ID = 0;12906const char AAInterFnReachability::ID = 0;12907const char AAPointerInfo::ID = 0;12908const char AAAssumptionInfo::ID = 0;12909const char AAUnderlyingObjects::ID = 0;12910const char AAAddressSpace::ID = 0;12911const char AAAllocationInfo::ID = 0;12912const char AAIndirectCallInfo::ID = 0;12913const char AAGlobalValueInfo::ID = 0;12914const char AADenormalFPMath::ID = 0;1291512916// Macro magic to create the static generator function for attributes that12917// follow the naming scheme.1291812919#define SWITCH_PK_INV(CLASS, PK, POS_NAME) \12920case IRPosition::PK: \12921llvm_unreachable("Cannot create " #CLASS " for a " POS_NAME " position!");1292212923#define SWITCH_PK_CREATE(CLASS, IRP, PK, SUFFIX) \12924case IRPosition::PK: \12925AA = new (A.Allocator) CLASS##SUFFIX(IRP, A); \12926++NumAAs; \12927break;1292812929#define CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \12930CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \12931CLASS *AA = nullptr; \12932switch (IRP.getPositionKind()) { \12933SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \12934SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \12935SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \12936SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \12937SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \12938SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \12939SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \12940SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \12941} \12942return *AA; \12943}1294412945#define CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \12946CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \12947CLASS *AA = nullptr; \12948switch (IRP.getPositionKind()) { \12949SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \12950SWITCH_PK_INV(CLASS, IRP_FUNCTION, "function") \12951SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \12952SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \12953SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \12954SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \12955SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \12956SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \12957} \12958return *AA; \12959}1296012961#define CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(POS, SUFFIX, CLASS) \12962CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \12963CLASS *AA = nullptr; \12964switch (IRP.getPositionKind()) { \12965SWITCH_PK_CREATE(CLASS, IRP, POS, SUFFIX) \12966default: \12967llvm_unreachable("Cannot create " #CLASS " for position otherthan " #POS \12968" position!"); \12969} \12970return *AA; \12971}1297212973#define CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \12974CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \12975CLASS *AA = nullptr; \12976switch (IRP.getPositionKind()) { \12977SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \12978SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \12979SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \12980SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \12981SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \12982SWITCH_PK_CREATE(CLASS, IRP, IRP_RETURNED, Returned) \12983SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \12984SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \12985} \12986return *AA; \12987}1298812989#define CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \12990CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \12991CLASS *AA = nullptr; \12992switch (IRP.getPositionKind()) { \12993SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \12994SWITCH_PK_INV(CLASS, IRP_ARGUMENT, "argument") \12995SWITCH_PK_INV(CLASS, IRP_FLOAT, "floating") \12996SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \12997SWITCH_PK_INV(CLASS, IRP_CALL_SITE_RETURNED, "call site returned") \12998SWITCH_PK_INV(CLASS, IRP_CALL_SITE_ARGUMENT, "call site argument") \12999SWITCH_PK_INV(CLASS, IRP_CALL_SITE, "call site") \13000SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \13001} \13002return *AA; \13003}1300413005#define CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(CLASS) \13006CLASS &CLASS::createForPosition(const IRPosition &IRP, Attributor &A) { \13007CLASS *AA = nullptr; \13008switch (IRP.getPositionKind()) { \13009SWITCH_PK_INV(CLASS, IRP_INVALID, "invalid") \13010SWITCH_PK_INV(CLASS, IRP_RETURNED, "returned") \13011SWITCH_PK_CREATE(CLASS, IRP, IRP_FUNCTION, Function) \13012SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE, CallSite) \13013SWITCH_PK_CREATE(CLASS, IRP, IRP_FLOAT, Floating) \13014SWITCH_PK_CREATE(CLASS, IRP, IRP_ARGUMENT, Argument) \13015SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_RETURNED, CallSiteReturned) \13016SWITCH_PK_CREATE(CLASS, IRP, IRP_CALL_SITE_ARGUMENT, CallSiteArgument) \13017} \13018return *AA; \13019}1302013021CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUnwind)13022CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoSync)13023CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoRecurse)13024CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAWillReturn)13025CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoReturn)13026CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryLocation)13027CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AACallEdges)13028CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAssumptionInfo)13029CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMustProgress)1303013031CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonNull)13032CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoAlias)13033CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPrivatizablePtr)13034CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADereferenceable)13035CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAlign)13036CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAInstanceInfo)13037CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoCapture)13038CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueConstantRange)13039CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialConstantValues)13040CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPotentialValues)13041CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoUndef)13042CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFPClass)13043CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAPointerInfo)13044CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAddressSpace)13045CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAAllocationInfo)1304613047CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAValueSimplify)13048CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIsDead)13049CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANoFree)13050CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUnderlyingObjects)1305113052CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(IRP_CALL_SITE, CallSite,13053AAIndirectCallInfo)13054CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION(IRP_FLOAT, Floating,13055AAGlobalValueInfo)1305613057CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAHeapToStack)13058CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAUndefinedBehavior)13059CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AANonConvergent)13060CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAIntraFnReachability)13061CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAInterFnReachability)13062CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION(AADenormalFPMath)1306313064CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION(AAMemoryBehavior)1306513066#undef CREATE_FUNCTION_ONLY_ABSTRACT_ATTRIBUTE_FOR_POSITION13067#undef CREATE_FUNCTION_ABSTRACT_ATTRIBUTE_FOR_POSITION13068#undef CREATE_NON_RET_ABSTRACT_ATTRIBUTE_FOR_POSITION13069#undef CREATE_VALUE_ABSTRACT_ATTRIBUTE_FOR_POSITION13070#undef CREATE_ALL_ABSTRACT_ATTRIBUTE_FOR_POSITION13071#undef CREATE_ABSTRACT_ATTRIBUTE_FOR_ONE_POSITION13072#undef SWITCH_PK_CREATE13073#undef SWITCH_PK_INV130741307513076