diff options
author | shadchin <shadchin@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
---|---|---|
committer | Daniil Cherednik <dcherednik@yandex-team.ru> | 2022-02-10 16:44:39 +0300 |
commit | e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0 (patch) | |
tree | 64175d5cadab313b3e7039ebaa06c5bc3295e274 /contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h | |
parent | 2598ef1d0aee359b4b6d5fdd1758916d5907d04f (diff) | |
download | ydb-e9656aae26e0358d5378e5b63dcac5c8dbe0e4d0.tar.gz |
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 2 of 2.
Diffstat (limited to 'contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h')
-rw-r--r-- | contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h | 1200 |
1 files changed, 600 insertions, 600 deletions
diff --git a/contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h b/contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h index fd82945466..96681071db 100644 --- a/contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h +++ b/contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h @@ -104,10 +104,10 @@ #ifndef LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H #define LLVM_TRANSFORMS_IPO_ATTRIBUTOR_H -#include "llvm/ADT/DenseSet.h" -#include "llvm/ADT/GraphTraits.h" +#include "llvm/ADT/DenseSet.h" +#include "llvm/ADT/GraphTraits.h" #include "llvm/ADT/MapVector.h" -#include "llvm/ADT/STLExtras.h" +#include "llvm/ADT/STLExtras.h" #include "llvm/ADT/SetVector.h" #include "llvm/Analysis/AssumeBundleQueries.h" #include "llvm/Analysis/CFG.h" @@ -121,27 +121,27 @@ #include "llvm/IR/ConstantRange.h" #include "llvm/IR/PassManager.h" #include "llvm/Support/Allocator.h" -#include "llvm/Support/Casting.h" -#include "llvm/Support/TimeProfiler.h" +#include "llvm/Support/Casting.h" +#include "llvm/Support/TimeProfiler.h" #include "llvm/Transforms/Utils/CallGraphUpdater.h" namespace llvm { -struct AADepGraphNode; -struct AADepGraph; +struct AADepGraphNode; +struct AADepGraph; struct Attributor; struct AbstractAttribute; struct InformationCache; struct AAIsDead; -class AAManager; -class AAResults; +class AAManager; +class AAResults; class Function; -/// The value passed to the line option that defines the maximal initialization -/// chain length. -extern unsigned MaxInitializationChainLength; - +/// The value passed to the line option that defines the maximal initialization +/// chain length. +extern unsigned MaxInitializationChainLength; + ///{ enum class ChangeStatus { CHANGED, @@ -157,74 +157,74 @@ enum class DepClassTy { }; ///} -/// The data structure for the nodes of a dependency graph -struct AADepGraphNode { -public: - virtual ~AADepGraphNode(){}; - using DepTy = PointerIntPair<AADepGraphNode *, 1>; - -protected: - /// Set of dependency graph nodes which should be updated if this one - /// is updated. The bit encodes if it is optional. - TinyPtrVector<DepTy> Deps; - - static AADepGraphNode *DepGetVal(DepTy &DT) { return DT.getPointer(); } - static AbstractAttribute *DepGetValAA(DepTy &DT) { - return cast<AbstractAttribute>(DT.getPointer()); - } - - operator AbstractAttribute *() { return cast<AbstractAttribute>(this); } - -public: - using iterator = - mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetVal)>; - using aaiterator = - mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetValAA)>; - - aaiterator begin() { return aaiterator(Deps.begin(), &DepGetValAA); } - aaiterator end() { return aaiterator(Deps.end(), &DepGetValAA); } - iterator child_begin() { return iterator(Deps.begin(), &DepGetVal); } - iterator child_end() { return iterator(Deps.end(), &DepGetVal); } - - virtual void print(raw_ostream &OS) const { OS << "AADepNode Impl\n"; } - TinyPtrVector<DepTy> &getDeps() { return Deps; } - - friend struct Attributor; - friend struct AADepGraph; -}; - -/// The data structure for the dependency graph -/// -/// Note that in this graph if there is an edge from A to B (A -> B), -/// then it means that B depends on A, and when the state of A is -/// updated, node B should also be updated -struct AADepGraph { - AADepGraph() {} - ~AADepGraph() {} - - using DepTy = AADepGraphNode::DepTy; - static AADepGraphNode *DepGetVal(DepTy &DT) { return DT.getPointer(); } - using iterator = - mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetVal)>; - - /// There is no root node for the dependency graph. But the SCCIterator - /// requires a single entry point, so we maintain a fake("synthetic") root - /// node that depends on every node. - AADepGraphNode SyntheticRoot; - AADepGraphNode *GetEntryNode() { return &SyntheticRoot; } - - iterator begin() { return SyntheticRoot.child_begin(); } - iterator end() { return SyntheticRoot.child_end(); } - - void viewGraph(); - - /// Dump graph to file - void dumpGraph(); - - /// Print dependency graph - void print(); -}; - +/// The data structure for the nodes of a dependency graph +struct AADepGraphNode { +public: + virtual ~AADepGraphNode(){}; + using DepTy = PointerIntPair<AADepGraphNode *, 1>; + +protected: + /// Set of dependency graph nodes which should be updated if this one + /// is updated. The bit encodes if it is optional. + TinyPtrVector<DepTy> Deps; + + static AADepGraphNode *DepGetVal(DepTy &DT) { return DT.getPointer(); } + static AbstractAttribute *DepGetValAA(DepTy &DT) { + return cast<AbstractAttribute>(DT.getPointer()); + } + + operator AbstractAttribute *() { return cast<AbstractAttribute>(this); } + +public: + using iterator = + mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetVal)>; + using aaiterator = + mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetValAA)>; + + aaiterator begin() { return aaiterator(Deps.begin(), &DepGetValAA); } + aaiterator end() { return aaiterator(Deps.end(), &DepGetValAA); } + iterator child_begin() { return iterator(Deps.begin(), &DepGetVal); } + iterator child_end() { return iterator(Deps.end(), &DepGetVal); } + + virtual void print(raw_ostream &OS) const { OS << "AADepNode Impl\n"; } + TinyPtrVector<DepTy> &getDeps() { return Deps; } + + friend struct Attributor; + friend struct AADepGraph; +}; + +/// The data structure for the dependency graph +/// +/// Note that in this graph if there is an edge from A to B (A -> B), +/// then it means that B depends on A, and when the state of A is +/// updated, node B should also be updated +struct AADepGraph { + AADepGraph() {} + ~AADepGraph() {} + + using DepTy = AADepGraphNode::DepTy; + static AADepGraphNode *DepGetVal(DepTy &DT) { return DT.getPointer(); } + using iterator = + mapped_iterator<TinyPtrVector<DepTy>::iterator, decltype(&DepGetVal)>; + + /// There is no root node for the dependency graph. But the SCCIterator + /// requires a single entry point, so we maintain a fake("synthetic") root + /// node that depends on every node. + AADepGraphNode SyntheticRoot; + AADepGraphNode *GetEntryNode() { return &SyntheticRoot; } + + iterator begin() { return SyntheticRoot.child_begin(); } + iterator end() { return SyntheticRoot.child_end(); } + + void viewGraph(); + + /// Dump graph to file + void dumpGraph(); + + /// Print dependency graph + void print(); +}; + /// Helper to describe and deal with positions in the LLVM-IR. /// /// A position in the IR is described by an anchor value and an "offset" that @@ -344,14 +344,14 @@ struct IRPosition { /// Return the associated function, if any. Function *getAssociatedFunction() const { - if (auto *CB = dyn_cast<CallBase>(&getAnchorValue())) { - // We reuse the logic that associates callback calles to arguments of a - // call site here to identify the callback callee as the associated - // function. - if (Argument *Arg = getAssociatedArgument()) - return Arg->getParent(); + if (auto *CB = dyn_cast<CallBase>(&getAnchorValue())) { + // We reuse the logic that associates callback calles to arguments of a + // call site here to identify the callback callee as the associated + // function. + if (Argument *Arg = getAssociatedArgument()) + return Arg->getParent(); return CB->getCalledFunction(); - } + } return getAnchorScope(); } @@ -399,11 +399,11 @@ struct IRPosition { /// Return the value this abstract attribute is associated with. Value &getAssociatedValue() const { - if (getCallSiteArgNo() < 0 || isa<Argument>(&getAnchorValue())) + if (getCallSiteArgNo() < 0 || isa<Argument>(&getAnchorValue())) return getAnchorValue(); assert(isa<CallBase>(&getAnchorValue()) && "Expected a call base!"); - return *cast<CallBase>(&getAnchorValue()) - ->getArgOperand(getCallSiteArgNo()); + return *cast<CallBase>(&getAnchorValue()) + ->getArgOperand(getCallSiteArgNo()); } /// Return the type this abstract attribute is associated with. @@ -413,24 +413,24 @@ struct IRPosition { return getAssociatedValue().getType(); } - /// Return the callee argument number of the associated value if it is an - /// argument or call site argument, otherwise a negative value. In contrast to - /// `getCallSiteArgNo` this method will always return the "argument number" - /// from the perspective of the callee. This may not the same as the call site - /// if this is a callback call. - int getCalleeArgNo() const { - return getArgNo(/* CallbackCalleeArgIfApplicable */ true); - } - - /// Return the call site argument number of the associated value if it is an - /// argument or call site argument, otherwise a negative value. In contrast to - /// `getCalleArgNo` this method will always return the "operand number" from - /// the perspective of the call site. This may not the same as the callee - /// perspective if this is a callback call. - int getCallSiteArgNo() const { - return getArgNo(/* CallbackCalleeArgIfApplicable */ false); - } - + /// Return the callee argument number of the associated value if it is an + /// argument or call site argument, otherwise a negative value. In contrast to + /// `getCallSiteArgNo` this method will always return the "argument number" + /// from the perspective of the callee. This may not the same as the call site + /// if this is a callback call. + int getCalleeArgNo() const { + return getArgNo(/* CallbackCalleeArgIfApplicable */ true); + } + + /// Return the call site argument number of the associated value if it is an + /// argument or call site argument, otherwise a negative value. In contrast to + /// `getCalleArgNo` this method will always return the "operand number" from + /// the perspective of the call site. This may not the same as the callee + /// perspective if this is a callback call. + int getCallSiteArgNo() const { + return getArgNo(/* CallbackCalleeArgIfApplicable */ false); + } + /// Return the index in the attribute list for this position. unsigned getAttrIdx() const { switch (getPositionKind()) { @@ -445,7 +445,7 @@ struct IRPosition { return AttributeList::ReturnIndex; case IRPosition::IRP_ARGUMENT: case IRPosition::IRP_CALL_SITE_ARGUMENT: - return getCallSiteArgNo() + AttributeList::FirstArgIndex; + return getCallSiteArgNo() + AttributeList::FirstArgIndex; } llvm_unreachable( "There is no attribute index for a floating or invalid position!"); @@ -530,17 +530,17 @@ struct IRPosition { } } - /// Return true if the position is an argument or call site argument. - bool isArgumentPosition() const { - switch (getPositionKind()) { - case IRPosition::IRP_ARGUMENT: - case IRPosition::IRP_CALL_SITE_ARGUMENT: - return true; - default: - return false; - } - } - + /// Return true if the position is an argument or call site argument. + bool isArgumentPosition() const { + switch (getPositionKind()) { + case IRPosition::IRP_ARGUMENT: + case IRPosition::IRP_CALL_SITE_ARGUMENT: + return true; + default: + return false; + } + } + /// Special DenseMap key values. /// ///{ @@ -587,25 +587,25 @@ private: verify(); } - /// Return the callee argument number of the associated value if it is an - /// argument or call site argument. See also `getCalleeArgNo` and - /// `getCallSiteArgNo`. - int getArgNo(bool CallbackCalleeArgIfApplicable) const { - if (CallbackCalleeArgIfApplicable) - if (Argument *Arg = getAssociatedArgument()) - return Arg->getArgNo(); - switch (getPositionKind()) { - case IRPosition::IRP_ARGUMENT: - return cast<Argument>(getAsValuePtr())->getArgNo(); - case IRPosition::IRP_CALL_SITE_ARGUMENT: { - Use &U = *getAsUsePtr(); - return cast<CallBase>(U.getUser())->getArgOperandNo(&U); - } - default: - return -1; - } - } - + /// Return the callee argument number of the associated value if it is an + /// argument or call site argument. See also `getCalleeArgNo` and + /// `getCallSiteArgNo`. + int getArgNo(bool CallbackCalleeArgIfApplicable) const { + if (CallbackCalleeArgIfApplicable) + if (Argument *Arg = getAssociatedArgument()) + return Arg->getArgNo(); + switch (getPositionKind()) { + case IRPosition::IRP_ARGUMENT: + return cast<Argument>(getAsValuePtr())->getArgNo(); + case IRPosition::IRP_CALL_SITE_ARGUMENT: { + Use &U = *getAsUsePtr(); + return cast<CallBase>(U.getUser())->getArgOperandNo(&U); + } + default: + return -1; + } + } + /// IRPosition for the use \p U. The position kind \p PK needs to be /// IRP_CALL_SITE_ARGUMENT, the anchor value is the user, the associated value /// the used value. @@ -769,10 +769,10 @@ struct InformationCache { [&](const Function &F) { return AG.getAnalysis<PostDominatorTreeAnalysis>(F); }), - AG(AG), CGSCC(CGSCC) { - if (CGSCC) - initializeModuleSlice(*CGSCC); - } + AG(AG), CGSCC(CGSCC) { + if (CGSCC) + initializeModuleSlice(*CGSCC); + } ~InformationCache() { // The FunctionInfo objects are allocated via a BumpPtrAllocator, we call @@ -781,68 +781,68 @@ struct InformationCache { It.getSecond()->~FunctionInfo(); } - /// Apply \p CB to all uses of \p F. If \p LookThroughConstantExprUses is - /// true, constant expression users are not given to \p CB but their uses are - /// traversed transitively. - template <typename CBTy> - static void foreachUse(Function &F, CBTy CB, - bool LookThroughConstantExprUses = true) { - SmallVector<Use *, 8> Worklist(make_pointer_range(F.uses())); - - for (unsigned Idx = 0; Idx < Worklist.size(); ++Idx) { - Use &U = *Worklist[Idx]; - - // Allow use in constant bitcasts and simply look through them. - if (LookThroughConstantExprUses && isa<ConstantExpr>(U.getUser())) { - for (Use &CEU : cast<ConstantExpr>(U.getUser())->uses()) - Worklist.push_back(&CEU); - continue; - } - - CB(U); - } - } - - /// Initialize the ModuleSlice member based on \p SCC. ModuleSlices contains - /// (a subset of) all functions that we can look at during this SCC traversal. - /// This includes functions (transitively) called from the SCC and the - /// (transitive) callers of SCC functions. We also can look at a function if - /// there is a "reference edge", i.a., if the function somehow uses (!=calls) - /// a function in the SCC or a caller of a function in the SCC. - void initializeModuleSlice(SetVector<Function *> &SCC) { - ModuleSlice.insert(SCC.begin(), SCC.end()); - - SmallPtrSet<Function *, 16> Seen; - SmallVector<Function *, 16> Worklist(SCC.begin(), SCC.end()); - while (!Worklist.empty()) { - Function *F = Worklist.pop_back_val(); - ModuleSlice.insert(F); - - for (Instruction &I : instructions(*F)) - if (auto *CB = dyn_cast<CallBase>(&I)) - if (Function *Callee = CB->getCalledFunction()) - if (Seen.insert(Callee).second) - Worklist.push_back(Callee); - } - - Seen.clear(); - Worklist.append(SCC.begin(), SCC.end()); - while (!Worklist.empty()) { - Function *F = Worklist.pop_back_val(); - ModuleSlice.insert(F); - - // Traverse all transitive uses. - foreachUse(*F, [&](Use &U) { - if (auto *UsrI = dyn_cast<Instruction>(U.getUser())) - if (Seen.insert(UsrI->getFunction()).second) - Worklist.push_back(UsrI->getFunction()); - }); - } - } - - /// The slice of the module we are allowed to look at. - SmallPtrSet<Function *, 8> ModuleSlice; - + /// Apply \p CB to all uses of \p F. If \p LookThroughConstantExprUses is + /// true, constant expression users are not given to \p CB but their uses are + /// traversed transitively. + template <typename CBTy> + static void foreachUse(Function &F, CBTy CB, + bool LookThroughConstantExprUses = true) { + SmallVector<Use *, 8> Worklist(make_pointer_range(F.uses())); + + for (unsigned Idx = 0; Idx < Worklist.size(); ++Idx) { + Use &U = *Worklist[Idx]; + + // Allow use in constant bitcasts and simply look through them. + if (LookThroughConstantExprUses && isa<ConstantExpr>(U.getUser())) { + for (Use &CEU : cast<ConstantExpr>(U.getUser())->uses()) + Worklist.push_back(&CEU); + continue; + } + + CB(U); + } + } + + /// Initialize the ModuleSlice member based on \p SCC. ModuleSlices contains + /// (a subset of) all functions that we can look at during this SCC traversal. + /// This includes functions (transitively) called from the SCC and the + /// (transitive) callers of SCC functions. We also can look at a function if + /// there is a "reference edge", i.a., if the function somehow uses (!=calls) + /// a function in the SCC or a caller of a function in the SCC. + void initializeModuleSlice(SetVector<Function *> &SCC) { + ModuleSlice.insert(SCC.begin(), SCC.end()); + + SmallPtrSet<Function *, 16> Seen; + SmallVector<Function *, 16> Worklist(SCC.begin(), SCC.end()); + while (!Worklist.empty()) { + Function *F = Worklist.pop_back_val(); + ModuleSlice.insert(F); + + for (Instruction &I : instructions(*F)) + if (auto *CB = dyn_cast<CallBase>(&I)) + if (Function *Callee = CB->getCalledFunction()) + if (Seen.insert(Callee).second) + Worklist.push_back(Callee); + } + + Seen.clear(); + Worklist.append(SCC.begin(), SCC.end()); + while (!Worklist.empty()) { + Function *F = Worklist.pop_back_val(); + ModuleSlice.insert(F); + + // Traverse all transitive uses. + foreachUse(*F, [&](Use &U) { + if (auto *UsrI = dyn_cast<Instruction>(U.getUser())) + if (Seen.insert(UsrI->getFunction()).second) + Worklist.push_back(UsrI->getFunction()); + }); + } + } + + /// The slice of the module we are allowed to look at. + SmallPtrSet<Function *, 8> ModuleSlice; + /// A vector type to hold instructions. using InstructionVectorTy = SmallVector<Instruction *, 8>; @@ -871,7 +871,7 @@ struct InformationCache { } /// Return AliasAnalysis Result for function \p F. - AAResults *getAAResultsForFunction(const Function &F); + AAResults *getAAResultsForFunction(const Function &F); /// Return true if \p Arg is involved in a must-tail call, thus the argument /// of the caller or callee. @@ -899,26 +899,26 @@ struct InformationCache { /// Return the map conaining all the knowledge we have from `llvm.assume`s. const RetainedKnowledgeMap &getKnowledgeMap() const { return KnowledgeMap; } - /// Return if \p To is potentially reachable form \p From or not - /// If the same query was answered, return cached result - bool getPotentiallyReachable(const Instruction &From, const Instruction &To) { - auto KeyPair = std::make_pair(&From, &To); - auto Iter = PotentiallyReachableMap.find(KeyPair); - if (Iter != PotentiallyReachableMap.end()) - return Iter->second; - const Function &F = *From.getFunction(); - bool Result = isPotentiallyReachable( - &From, &To, nullptr, AG.getAnalysis<DominatorTreeAnalysis>(F), - AG.getAnalysis<LoopAnalysis>(F)); - PotentiallyReachableMap.insert(std::make_pair(KeyPair, Result)); - return Result; - } - - /// Check whether \p F is part of module slice. - bool isInModuleSlice(const Function &F) { - return ModuleSlice.count(const_cast<Function *>(&F)); - } - + /// Return if \p To is potentially reachable form \p From or not + /// If the same query was answered, return cached result + bool getPotentiallyReachable(const Instruction &From, const Instruction &To) { + auto KeyPair = std::make_pair(&From, &To); + auto Iter = PotentiallyReachableMap.find(KeyPair); + if (Iter != PotentiallyReachableMap.end()) + return Iter->second; + const Function &F = *From.getFunction(); + bool Result = isPotentiallyReachable( + &From, &To, nullptr, AG.getAnalysis<DominatorTreeAnalysis>(F), + AG.getAnalysis<LoopAnalysis>(F)); + PotentiallyReachableMap.insert(std::make_pair(KeyPair, Result)); + return Result; + } + + /// Check whether \p F is part of module slice. + bool isInModuleSlice(const Function &F) { + return ModuleSlice.count(const_cast<Function *>(&F)); + } + private: struct FunctionInfo { ~FunctionInfo(); @@ -978,10 +978,10 @@ private: /// Set of inlineable functions SmallPtrSet<const Function *, 8> InlineableFunctions; - /// A map for caching results of queries for isPotentiallyReachable - DenseMap<std::pair<const Instruction *, const Instruction *>, bool> - PotentiallyReachableMap; - + /// A map for caching results of queries for isPotentiallyReachable + DenseMap<std::pair<const Instruction *, const Instruction *>, bool> + PotentiallyReachableMap; + /// Give the Attributor access to the members so /// Attributor::identifyDefaultAbstractAttributes(...) can initialize them. friend struct Attributor; @@ -1084,7 +1084,7 @@ struct Attributor { /// attribute. Using this after Attributor started running is restricted to /// only the Attributor itself. Initial seeding of AAs can be done via this /// function. - /// NOTE: ForceUpdate is ignored in any stage other than the update stage. + /// NOTE: ForceUpdate is ignored in any stage other than the update stage. template <typename AAType> const AAType &getOrCreateAAFor(const IRPosition &IRP, const AbstractAttribute *QueryingAA = nullptr, @@ -1092,7 +1092,7 @@ struct Attributor { DepClassTy DepClass = DepClassTy::OPTIONAL, bool ForceUpdate = false) { if (AAType *AAPtr = lookupAAFor<AAType>(IRP, QueryingAA, TrackDependence)) { - if (ForceUpdate && Phase == AttributorPhase::UPDATE) + if (ForceUpdate && Phase == AttributorPhase::UPDATE) updateAA(*AAPtr); return *AAPtr; } @@ -1102,7 +1102,7 @@ struct Attributor { auto &AA = AAType::createForPosition(IRP, *this); // If we are currenty seeding attributes, enforce seeding rules. - if (Phase == AttributorPhase::SEEDING && !shouldSeedAttribute(AA)) { + if (Phase == AttributorPhase::SEEDING && !shouldSeedAttribute(AA)) { AA.getState().indicatePessimisticFixpoint(); return AA; } @@ -1116,9 +1116,9 @@ struct Attributor { Invalidate |= FnScope->hasFnAttribute(Attribute::Naked) || FnScope->hasFnAttribute(Attribute::OptimizeNone); - // Avoid too many nested initializations to prevent a stack overflow. - Invalidate |= InitializationChainLength > MaxInitializationChainLength; - + // Avoid too many nested initializations to prevent a stack overflow. + Invalidate |= InitializationChainLength > MaxInitializationChainLength; + // Bootstrap the new attribute with an initial update to propagate // information, e.g., function -> call site. If it is not on a given // Allowed we will not perform updates at all. @@ -1127,39 +1127,39 @@ struct Attributor { return AA; } - { - TimeTraceScope TimeScope(AA.getName() + "::initialize"); - ++InitializationChainLength; - AA.initialize(*this); - --InitializationChainLength; - } - - // Initialize and update is allowed for code outside of the current function - // set, but only if it is part of module slice we are allowed to look at. - // Only exception is AAIsDeadFunction whose initialization is prevented - // directly, since we don't to compute it twice. + { + TimeTraceScope TimeScope(AA.getName() + "::initialize"); + ++InitializationChainLength; + AA.initialize(*this); + --InitializationChainLength; + } + + // Initialize and update is allowed for code outside of the current function + // set, but only if it is part of module slice we are allowed to look at. + // Only exception is AAIsDeadFunction whose initialization is prevented + // directly, since we don't to compute it twice. if (FnScope && !Functions.count(const_cast<Function *>(FnScope))) { - if (!getInfoCache().isInModuleSlice(*FnScope)) { - AA.getState().indicatePessimisticFixpoint(); - return AA; - } - } - - // If this is queried in the manifest stage, we force the AA to indicate - // pessimistic fixpoint immediately. - if (Phase == AttributorPhase::MANIFEST) { + if (!getInfoCache().isInModuleSlice(*FnScope)) { + AA.getState().indicatePessimisticFixpoint(); + return AA; + } + } + + // If this is queried in the manifest stage, we force the AA to indicate + // pessimistic fixpoint immediately. + if (Phase == AttributorPhase::MANIFEST) { AA.getState().indicatePessimisticFixpoint(); return AA; } // Allow seeded attributes to declare dependencies. // Remember the seeding state. - AttributorPhase OldPhase = Phase; - Phase = AttributorPhase::UPDATE; + AttributorPhase OldPhase = Phase; + Phase = AttributorPhase::UPDATE; updateAA(AA); - Phase = OldPhase; + Phase = OldPhase; if (TrackDependence && AA.getState().isValidState()) recordDependence(AA, const_cast<AbstractAttribute &>(*QueryingAA), @@ -1228,11 +1228,11 @@ struct Attributor { assert(!AAPtr && "Attribute already in map!"); AAPtr = &AA; - // Register AA with the synthetic root only before the manifest stage. - if (Phase == AttributorPhase::SEEDING || Phase == AttributorPhase::UPDATE) - DG.SyntheticRoot.Deps.push_back( - AADepGraphNode::DepTy(&AA, unsigned(DepClassTy::REQUIRED))); - + // Register AA with the synthetic root only before the manifest stage. + if (Phase == AttributorPhase::SEEDING || Phase == AttributorPhase::UPDATE) + DG.SyntheticRoot.Deps.push_back( + AADepGraphNode::DepTy(&AA, unsigned(DepClassTy::REQUIRED))); + return AA; } @@ -1541,22 +1541,22 @@ struct Attributor { bool checkForAllReadWriteInstructions(function_ref<bool(Instruction &)> Pred, AbstractAttribute &QueryingAA); - /// Create a shallow wrapper for \p F such that \p F has internal linkage - /// afterwards. It also sets the original \p F 's name to anonymous - /// - /// A wrapper is a function with the same type (and attributes) as \p F - /// that will only call \p F and return the result, if any. - /// - /// Assuming the declaration of looks like: - /// rty F(aty0 arg0, ..., atyN argN); - /// - /// The wrapper will then look as follows: - /// rty wrapper(aty0 arg0, ..., atyN argN) { - /// return F(arg0, ..., argN); - /// } - /// - static void createShallowWrapper(Function &F); - + /// Create a shallow wrapper for \p F such that \p F has internal linkage + /// afterwards. It also sets the original \p F 's name to anonymous + /// + /// A wrapper is a function with the same type (and attributes) as \p F + /// that will only call \p F and return the result, if any. + /// + /// Assuming the declaration of looks like: + /// rty F(aty0 arg0, ..., atyN argN); + /// + /// The wrapper will then look as follows: + /// rty wrapper(aty0 arg0, ..., atyN argN) { + /// return F(arg0, ..., argN); + /// } + /// + static void createShallowWrapper(Function &F); + /// Return the data layout associated with the anchor scope. const DataLayout &getDataLayout() const { return InfoCache.DL; } @@ -1580,10 +1580,10 @@ private: /// Rewrites function signitures and updates the call graph. ChangeStatus cleanupIR(); - /// Identify internal functions that are effectively dead, thus not reachable - /// from a live entry point. The functions are added to ToBeDeletedFunctions. - void identifyDeadInternalFunctions(); - + /// Identify internal functions that are effectively dead, thus not reachable + /// from a live entry point. The functions are added to ToBeDeletedFunctions. + void identifyDeadInternalFunctions(); + /// Run `::update` on \p AA and track the dependences queried while doing so. /// Also adjust the state if we know further updates are not necessary. ChangeStatus updateAA(AbstractAttribute &AA); @@ -1635,9 +1635,9 @@ private: /// Helper to update an underlying call graph. CallGraphUpdater &CGUpdater; - /// Abstract Attribute dependency graph - AADepGraph DG; - + /// Abstract Attribute dependency graph + AADepGraph DG; + /// Set of functions for which we modified the content such that it might /// impact the call graph. SmallPtrSet<Function *, 8> CGModifiedFunctions; @@ -1676,18 +1676,18 @@ private: /// Invoke instructions with at least a single dead successor block. SmallVector<WeakVH, 16> InvokeWithDeadSuccessor; - /// A flag that indicates which stage of the process we are in. Initially, the - /// phase is SEEDING. Phase is changed in `Attributor::run()` - enum class AttributorPhase { - SEEDING, - UPDATE, - MANIFEST, - CLEANUP, - } Phase = AttributorPhase::SEEDING; - - /// The current initialization chain length. Tracked to avoid stack overflows. - unsigned InitializationChainLength = 0; - + /// A flag that indicates which stage of the process we are in. Initially, the + /// phase is SEEDING. Phase is changed in `Attributor::run()` + enum class AttributorPhase { + SEEDING, + UPDATE, + MANIFEST, + CLEANUP, + } Phase = AttributorPhase::SEEDING; + + /// The current initialization chain length. Tracked to avoid stack overflows. + unsigned InitializationChainLength = 0; + /// Functions, blocks, and instructions we delete after manifest is done. /// ///{ @@ -1695,8 +1695,8 @@ private: SmallPtrSet<BasicBlock *, 8> ToBeDeletedBlocks; SmallDenseSet<WeakVH, 8> ToBeDeletedInsts; ///} - - friend AADepGraph; + + friend AADepGraph; }; /// An interface to query the internal state of an abstract attribute. @@ -2175,7 +2175,7 @@ struct StateWrapper : public BaseType, public StateTy { StateType &getState() override { return *this; } /// See AbstractAttribute::getState(...). - const StateType &getState() const override { return *this; } + const StateType &getState() const override { return *this; } }; /// Helper class that provides common functionality to manifest IR attributes. @@ -2269,7 +2269,7 @@ struct IRAttribute : public BaseType { /// both directions will be added in the future. /// NOTE: The mechanics of adding a new "concrete" abstract attribute are /// described in the file comment. -struct AbstractAttribute : public IRPosition, public AADepGraphNode { +struct AbstractAttribute : public IRPosition, public AADepGraphNode { using StateType = AbstractState; AbstractAttribute(const IRPosition &IRP) : IRPosition(IRP) {} @@ -2277,14 +2277,14 @@ struct AbstractAttribute : public IRPosition, public AADepGraphNode { /// Virtual destructor. virtual ~AbstractAttribute() {} - /// This function is used to identify if an \p DGN is of type - /// AbstractAttribute so that the dyn_cast and cast can use such information - /// to cast an AADepGraphNode to an AbstractAttribute. - /// - /// We eagerly return true here because all AADepGraphNodes except for the - /// Synthethis Node are of type AbstractAttribute - static bool classof(const AADepGraphNode *DGN) { return true; } - + /// This function is used to identify if an \p DGN is of type + /// AbstractAttribute so that the dyn_cast and cast can use such information + /// to cast an AADepGraphNode to an AbstractAttribute. + /// + /// We eagerly return true here because all AADepGraphNodes except for the + /// Synthethis Node are of type AbstractAttribute + static bool classof(const AADepGraphNode *DGN) { return true; } + /// Initialize the state with the information in the Attributor \p A. /// /// This function is called by the Attributor once all abstract attributes @@ -2305,8 +2305,8 @@ struct AbstractAttribute : public IRPosition, public AADepGraphNode { /// Helper functions, for debug purposes only. ///{ - void print(raw_ostream &OS) const override; - virtual void printWithDeps(raw_ostream &OS) const; + void print(raw_ostream &OS) const override; + virtual void printWithDeps(raw_ostream &OS) const; void dump() const { print(dbgs()); } /// This function should return the "summarized" assumed state as string. @@ -2635,17 +2635,17 @@ struct AAReachability : public StateWrapper<BooleanState, AbstractAttribute> { /// Returns true if 'From' instruction is assumed to reach, 'To' instruction. /// Users should provide two positions they are interested in, and the class /// determines (and caches) reachability. - bool isAssumedReachable(Attributor &A, const Instruction &From, - const Instruction &To) const { - return A.getInfoCache().getPotentiallyReachable(From, To); + bool isAssumedReachable(Attributor &A, const Instruction &From, + const Instruction &To) const { + return A.getInfoCache().getPotentiallyReachable(From, To); } /// Returns true if 'From' instruction is known to reach, 'To' instruction. /// Users should provide two positions they are interested in, and the class /// determines (and caches) reachability. - bool isKnownReachable(Attributor &A, const Instruction &From, - const Instruction &To) const { - return A.getInfoCache().getPotentiallyReachable(From, To); + bool isKnownReachable(Attributor &A, const Instruction &From, + const Instruction &To) const { + return A.getInfoCache().getPotentiallyReachable(From, To); } /// Create an abstract attribute view for the position \p IRP. @@ -2808,12 +2808,12 @@ public: return F.hasPersonalityFn() && !canSimplifyInvokeNoUnwind(&F); } - /// Return if the edge from \p From BB to \p To BB is assumed dead. - /// This is specifically useful in AAReachability. - virtual bool isEdgeDead(const BasicBlock *From, const BasicBlock *To) const { - return false; - } - + /// Return if the edge from \p From BB to \p To BB is assumed dead. + /// This is specifically useful in AAReachability. + virtual bool isEdgeDead(const BasicBlock *From, const BasicBlock *To) const { + return false; + } + /// See AbstractAttribute::getName() const std::string getName() const override { return "AAIsDead"; } @@ -3470,7 +3470,7 @@ struct AAValueConstantRange /// See AbstractAttribute::getState(...). IntegerRangeState &getState() override { return *this; } - const IntegerRangeState &getState() const override { return *this; } + const IntegerRangeState &getState() const override { return *this; } /// Create an abstract attribute view for the position \p IRP. static AAValueConstantRange &createForPosition(const IRPosition &IRP, @@ -3518,279 +3518,279 @@ struct AAValueConstantRange static const char ID; }; -/// A class for a set state. -/// The assumed boolean state indicates whether the corresponding set is full -/// set or not. If the assumed state is false, this is the worst state. The -/// worst state (invalid state) of set of potential values is when the set -/// contains every possible value (i.e. we cannot in any way limit the value -/// that the target position can take). That never happens naturally, we only -/// force it. As for the conditions under which we force it, see -/// AAPotentialValues. -template <typename MemberTy, typename KeyInfo = DenseMapInfo<MemberTy>> -struct PotentialValuesState : AbstractState { - using SetTy = DenseSet<MemberTy, KeyInfo>; - - PotentialValuesState() : IsValidState(true), UndefIsContained(false) {} - - PotentialValuesState(bool IsValid) - : IsValidState(IsValid), UndefIsContained(false) {} - - /// See AbstractState::isValidState(...) - bool isValidState() const override { return IsValidState.isValidState(); } - - /// See AbstractState::isAtFixpoint(...) - bool isAtFixpoint() const override { return IsValidState.isAtFixpoint(); } - - /// See AbstractState::indicatePessimisticFixpoint(...) - ChangeStatus indicatePessimisticFixpoint() override { - return IsValidState.indicatePessimisticFixpoint(); - } - - /// See AbstractState::indicateOptimisticFixpoint(...) - ChangeStatus indicateOptimisticFixpoint() override { - return IsValidState.indicateOptimisticFixpoint(); - } - - /// Return the assumed state - PotentialValuesState &getAssumed() { return *this; } - const PotentialValuesState &getAssumed() const { return *this; } - - /// Return this set. We should check whether this set is valid or not by - /// isValidState() before calling this function. - const SetTy &getAssumedSet() const { - assert(isValidState() && "This set shoud not be used when it is invalid!"); - return Set; - } - - /// Returns whether this state contains an undef value or not. - bool undefIsContained() const { - assert(isValidState() && "This flag shoud not be used when it is invalid!"); - return UndefIsContained; - } - - bool operator==(const PotentialValuesState &RHS) const { - if (isValidState() != RHS.isValidState()) - return false; - if (!isValidState() && !RHS.isValidState()) - return true; - if (undefIsContained() != RHS.undefIsContained()) - return false; - return Set == RHS.getAssumedSet(); - } - - /// Maximum number of potential values to be tracked. - /// This is set by -attributor-max-potential-values command line option - static unsigned MaxPotentialValues; - - /// Return empty set as the best state of potential values. - static PotentialValuesState getBestState() { - return PotentialValuesState(true); - } - - static PotentialValuesState getBestState(PotentialValuesState &PVS) { - return getBestState(); - } - - /// Return full set as the worst state of potential values. - static PotentialValuesState getWorstState() { - return PotentialValuesState(false); - } - - /// Union assumed set with the passed value. - void unionAssumed(const MemberTy &C) { insert(C); } - - /// Union assumed set with assumed set of the passed state \p PVS. - void unionAssumed(const PotentialValuesState &PVS) { unionWith(PVS); } - - /// Union assumed set with an undef value. - void unionAssumedWithUndef() { unionWithUndef(); } - - /// "Clamp" this state with \p PVS. - PotentialValuesState operator^=(const PotentialValuesState &PVS) { - IsValidState ^= PVS.IsValidState; - unionAssumed(PVS); - return *this; - } - - PotentialValuesState operator&=(const PotentialValuesState &PVS) { - IsValidState &= PVS.IsValidState; - unionAssumed(PVS); - return *this; - } - -private: - /// Check the size of this set, and invalidate when the size is no - /// less than \p MaxPotentialValues threshold. - void checkAndInvalidate() { - if (Set.size() >= MaxPotentialValues) - indicatePessimisticFixpoint(); - } - - /// If this state contains both undef and not undef, we can reduce - /// undef to the not undef value. - void reduceUndefValue() { UndefIsContained = UndefIsContained & Set.empty(); } - - /// Insert an element into this set. - void insert(const MemberTy &C) { - if (!isValidState()) - return; - Set.insert(C); - checkAndInvalidate(); - } - - /// Take union with R. - void unionWith(const PotentialValuesState &R) { - /// If this is a full set, do nothing.; - if (!isValidState()) - return; - /// If R is full set, change L to a full set. - if (!R.isValidState()) { - indicatePessimisticFixpoint(); - return; - } - for (const MemberTy &C : R.Set) - Set.insert(C); - UndefIsContained |= R.undefIsContained(); - reduceUndefValue(); - checkAndInvalidate(); - } - - /// Take union with an undef value. - void unionWithUndef() { - UndefIsContained = true; - reduceUndefValue(); - } - - /// Take intersection with R. - void intersectWith(const PotentialValuesState &R) { - /// If R is a full set, do nothing. - if (!R.isValidState()) - return; - /// If this is a full set, change this to R. - if (!isValidState()) { - *this = R; - return; - } - SetTy IntersectSet; - for (const MemberTy &C : Set) { - if (R.Set.count(C)) - IntersectSet.insert(C); - } - Set = IntersectSet; - UndefIsContained &= R.undefIsContained(); - reduceUndefValue(); - } - - /// A helper state which indicate whether this state is valid or not. - BooleanState IsValidState; - - /// Container for potential values - SetTy Set; - - /// Flag for undef value - bool UndefIsContained; -}; - -using PotentialConstantIntValuesState = PotentialValuesState<APInt>; - -raw_ostream &operator<<(raw_ostream &OS, - const PotentialConstantIntValuesState &R); - -/// An abstract interface for potential values analysis. -/// -/// This AA collects potential values for each IR position. -/// An assumed set of potential values is initialized with the empty set (the -/// best state) and it will grow monotonically as we find more potential values -/// for this position. -/// The set might be forced to the worst state, that is, to contain every -/// possible value for this position in 2 cases. -/// 1. We surpassed the \p MaxPotentialValues threshold. This includes the -/// case that this position is affected (e.g. because of an operation) by a -/// Value that is in the worst state. -/// 2. We tried to initialize on a Value that we cannot handle (e.g. an -/// operator we do not currently handle). -/// -/// TODO: Support values other than constant integers. -struct AAPotentialValues - : public StateWrapper<PotentialConstantIntValuesState, AbstractAttribute> { - using Base = StateWrapper<PotentialConstantIntValuesState, AbstractAttribute>; - AAPotentialValues(const IRPosition &IRP, Attributor &A) : Base(IRP) {} - - /// See AbstractAttribute::getState(...). - PotentialConstantIntValuesState &getState() override { return *this; } - const PotentialConstantIntValuesState &getState() const override { - return *this; - } - - /// Create an abstract attribute view for the position \p IRP. - static AAPotentialValues &createForPosition(const IRPosition &IRP, - Attributor &A); - - /// Return assumed constant for the associated value - Optional<ConstantInt *> - getAssumedConstantInt(Attributor &A, - const Instruction *CtxI = nullptr) const { - if (!isValidState()) - return nullptr; - if (getAssumedSet().size() == 1) - return cast<ConstantInt>(ConstantInt::get(getAssociatedValue().getType(), - *(getAssumedSet().begin()))); - if (getAssumedSet().size() == 0) { - if (undefIsContained()) - return cast<ConstantInt>( - ConstantInt::get(getAssociatedValue().getType(), 0)); - return llvm::None; - } - - return nullptr; - } - - /// See AbstractAttribute::getName() - const std::string getName() const override { return "AAPotentialValues"; } - - /// See AbstractAttribute::getIdAddr() - const char *getIdAddr() const override { return &ID; } - - /// This function should return true if the type of the \p AA is - /// AAPotentialValues - static bool classof(const AbstractAttribute *AA) { - return (AA->getIdAddr() == &ID); - } - - /// Unique ID (due to the unique address) - static const char ID; -}; - -/// An abstract interface for all noundef attributes. -struct AANoUndef - : public IRAttribute<Attribute::NoUndef, - StateWrapper<BooleanState, AbstractAttribute>> { - AANoUndef(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {} - - /// Return true if we assume that the underlying value is noundef. - bool isAssumedNoUndef() const { return getAssumed(); } - - /// Return true if we know that underlying value is noundef. - bool isKnownNoUndef() const { return getKnown(); } - - /// Create an abstract attribute view for the position \p IRP. - static AANoUndef &createForPosition(const IRPosition &IRP, Attributor &A); - - /// See AbstractAttribute::getName() - const std::string getName() const override { return "AANoUndef"; } - - /// See AbstractAttribute::getIdAddr() - const char *getIdAddr() const override { return &ID; } - - /// This function should return true if the type of the \p AA is AANoUndef - static bool classof(const AbstractAttribute *AA) { - return (AA->getIdAddr() == &ID); - } - - /// Unique ID (due to the unique address) - static const char ID; -}; - +/// A class for a set state. +/// The assumed boolean state indicates whether the corresponding set is full +/// set or not. If the assumed state is false, this is the worst state. The +/// worst state (invalid state) of set of potential values is when the set +/// contains every possible value (i.e. we cannot in any way limit the value +/// that the target position can take). That never happens naturally, we only +/// force it. As for the conditions under which we force it, see +/// AAPotentialValues. +template <typename MemberTy, typename KeyInfo = DenseMapInfo<MemberTy>> +struct PotentialValuesState : AbstractState { + using SetTy = DenseSet<MemberTy, KeyInfo>; + + PotentialValuesState() : IsValidState(true), UndefIsContained(false) {} + + PotentialValuesState(bool IsValid) + : IsValidState(IsValid), UndefIsContained(false) {} + + /// See AbstractState::isValidState(...) + bool isValidState() const override { return IsValidState.isValidState(); } + + /// See AbstractState::isAtFixpoint(...) + bool isAtFixpoint() const override { return IsValidState.isAtFixpoint(); } + + /// See AbstractState::indicatePessimisticFixpoint(...) + ChangeStatus indicatePessimisticFixpoint() override { + return IsValidState.indicatePessimisticFixpoint(); + } + + /// See AbstractState::indicateOptimisticFixpoint(...) + ChangeStatus indicateOptimisticFixpoint() override { + return IsValidState.indicateOptimisticFixpoint(); + } + + /// Return the assumed state + PotentialValuesState &getAssumed() { return *this; } + const PotentialValuesState &getAssumed() const { return *this; } + + /// Return this set. We should check whether this set is valid or not by + /// isValidState() before calling this function. + const SetTy &getAssumedSet() const { + assert(isValidState() && "This set shoud not be used when it is invalid!"); + return Set; + } + + /// Returns whether this state contains an undef value or not. + bool undefIsContained() const { + assert(isValidState() && "This flag shoud not be used when it is invalid!"); + return UndefIsContained; + } + + bool operator==(const PotentialValuesState &RHS) const { + if (isValidState() != RHS.isValidState()) + return false; + if (!isValidState() && !RHS.isValidState()) + return true; + if (undefIsContained() != RHS.undefIsContained()) + return false; + return Set == RHS.getAssumedSet(); + } + + /// Maximum number of potential values to be tracked. + /// This is set by -attributor-max-potential-values command line option + static unsigned MaxPotentialValues; + + /// Return empty set as the best state of potential values. + static PotentialValuesState getBestState() { + return PotentialValuesState(true); + } + + static PotentialValuesState getBestState(PotentialValuesState &PVS) { + return getBestState(); + } + + /// Return full set as the worst state of potential values. + static PotentialValuesState getWorstState() { + return PotentialValuesState(false); + } + + /// Union assumed set with the passed value. + void unionAssumed(const MemberTy &C) { insert(C); } + + /// Union assumed set with assumed set of the passed state \p PVS. + void unionAssumed(const PotentialValuesState &PVS) { unionWith(PVS); } + + /// Union assumed set with an undef value. + void unionAssumedWithUndef() { unionWithUndef(); } + + /// "Clamp" this state with \p PVS. + PotentialValuesState operator^=(const PotentialValuesState &PVS) { + IsValidState ^= PVS.IsValidState; + unionAssumed(PVS); + return *this; + } + + PotentialValuesState operator&=(const PotentialValuesState &PVS) { + IsValidState &= PVS.IsValidState; + unionAssumed(PVS); + return *this; + } + +private: + /// Check the size of this set, and invalidate when the size is no + /// less than \p MaxPotentialValues threshold. + void checkAndInvalidate() { + if (Set.size() >= MaxPotentialValues) + indicatePessimisticFixpoint(); + } + + /// If this state contains both undef and not undef, we can reduce + /// undef to the not undef value. + void reduceUndefValue() { UndefIsContained = UndefIsContained & Set.empty(); } + + /// Insert an element into this set. + void insert(const MemberTy &C) { + if (!isValidState()) + return; + Set.insert(C); + checkAndInvalidate(); + } + + /// Take union with R. + void unionWith(const PotentialValuesState &R) { + /// If this is a full set, do nothing.; + if (!isValidState()) + return; + /// If R is full set, change L to a full set. + if (!R.isValidState()) { + indicatePessimisticFixpoint(); + return; + } + for (const MemberTy &C : R.Set) + Set.insert(C); + UndefIsContained |= R.undefIsContained(); + reduceUndefValue(); + checkAndInvalidate(); + } + + /// Take union with an undef value. + void unionWithUndef() { + UndefIsContained = true; + reduceUndefValue(); + } + + /// Take intersection with R. + void intersectWith(const PotentialValuesState &R) { + /// If R is a full set, do nothing. + if (!R.isValidState()) + return; + /// If this is a full set, change this to R. + if (!isValidState()) { + *this = R; + return; + } + SetTy IntersectSet; + for (const MemberTy &C : Set) { + if (R.Set.count(C)) + IntersectSet.insert(C); + } + Set = IntersectSet; + UndefIsContained &= R.undefIsContained(); + reduceUndefValue(); + } + + /// A helper state which indicate whether this state is valid or not. + BooleanState IsValidState; + + /// Container for potential values + SetTy Set; + + /// Flag for undef value + bool UndefIsContained; +}; + +using PotentialConstantIntValuesState = PotentialValuesState<APInt>; + +raw_ostream &operator<<(raw_ostream &OS, + const PotentialConstantIntValuesState &R); + +/// An abstract interface for potential values analysis. +/// +/// This AA collects potential values for each IR position. +/// An assumed set of potential values is initialized with the empty set (the +/// best state) and it will grow monotonically as we find more potential values +/// for this position. +/// The set might be forced to the worst state, that is, to contain every +/// possible value for this position in 2 cases. +/// 1. We surpassed the \p MaxPotentialValues threshold. This includes the +/// case that this position is affected (e.g. because of an operation) by a +/// Value that is in the worst state. +/// 2. We tried to initialize on a Value that we cannot handle (e.g. an +/// operator we do not currently handle). +/// +/// TODO: Support values other than constant integers. +struct AAPotentialValues + : public StateWrapper<PotentialConstantIntValuesState, AbstractAttribute> { + using Base = StateWrapper<PotentialConstantIntValuesState, AbstractAttribute>; + AAPotentialValues(const IRPosition &IRP, Attributor &A) : Base(IRP) {} + + /// See AbstractAttribute::getState(...). + PotentialConstantIntValuesState &getState() override { return *this; } + const PotentialConstantIntValuesState &getState() const override { + return *this; + } + + /// Create an abstract attribute view for the position \p IRP. + static AAPotentialValues &createForPosition(const IRPosition &IRP, + Attributor &A); + + /// Return assumed constant for the associated value + Optional<ConstantInt *> + getAssumedConstantInt(Attributor &A, + const Instruction *CtxI = nullptr) const { + if (!isValidState()) + return nullptr; + if (getAssumedSet().size() == 1) + return cast<ConstantInt>(ConstantInt::get(getAssociatedValue().getType(), + *(getAssumedSet().begin()))); + if (getAssumedSet().size() == 0) { + if (undefIsContained()) + return cast<ConstantInt>( + ConstantInt::get(getAssociatedValue().getType(), 0)); + return llvm::None; + } + + return nullptr; + } + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AAPotentialValues"; } + + /// See AbstractAttribute::getIdAddr() + const char *getIdAddr() const override { return &ID; } + + /// This function should return true if the type of the \p AA is + /// AAPotentialValues + static bool classof(const AbstractAttribute *AA) { + return (AA->getIdAddr() == &ID); + } + + /// Unique ID (due to the unique address) + static const char ID; +}; + +/// An abstract interface for all noundef attributes. +struct AANoUndef + : public IRAttribute<Attribute::NoUndef, + StateWrapper<BooleanState, AbstractAttribute>> { + AANoUndef(const IRPosition &IRP, Attributor &A) : IRAttribute(IRP) {} + + /// Return true if we assume that the underlying value is noundef. + bool isAssumedNoUndef() const { return getAssumed(); } + + /// Return true if we know that underlying value is noundef. + bool isKnownNoUndef() const { return getKnown(); } + + /// Create an abstract attribute view for the position \p IRP. + static AANoUndef &createForPosition(const IRPosition &IRP, Attributor &A); + + /// See AbstractAttribute::getName() + const std::string getName() const override { return "AANoUndef"; } + + /// See AbstractAttribute::getIdAddr() + const char *getIdAddr() const override { return &ID; } + + /// This function should return true if the type of the \p AA is AANoUndef + static bool classof(const AbstractAttribute *AA) { + return (AA->getIdAddr() == &ID); + } + + /// Unique ID (due to the unique address) + static const char ID; +}; + /// Run options, used by the pass manager. enum AttributorRunOption { NONE = 0, |