aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h
diff options
context:
space:
mode:
authorshadchin <shadchin@yandex-team.ru>2022-02-10 16:44:30 +0300
committerDaniil Cherednik <dcherednik@yandex-team.ru>2022-02-10 16:44:30 +0300
commit2598ef1d0aee359b4b6d5fdd1758916d5907d04f (patch)
tree012bb94d777798f1f56ac1cec429509766d05181 /contrib/libs/llvm12/include/llvm/Transforms/IPO/Attributor.h
parent6751af0b0c1b952fede40b19b71da8025b5d8bcf (diff)
downloadydb-2598ef1d0aee359b4b6d5fdd1758916d5907d04f.tar.gz
Restoring authorship annotation for <shadchin@yandex-team.ru>. Commit 1 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.h1200
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 96681071db..fd82945466 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,