aboutsummaryrefslogtreecommitdiff
path: root/lib/Transforms/Scalar/PredicateSimplifier.cpp
diff options
context:
space:
mode:
authorNick Lewycky <nicholas@mxc.ca>2007-01-11 02:32:38 +0000
committerNick Lewycky <nicholas@mxc.ca>2007-01-11 02:32:38 +0000
commit419c6f5ac8fff1c6fbe7954c006e0180f6a6aa05 (patch)
tree0194b7cf84a777d9f35f20d56d2ba9e685c35215 /lib/Transforms/Scalar/PredicateSimplifier.cpp
parent25919cb7802f2682b159a040ba07c5bd12b54efa (diff)
New predicate simplifier!
Please do not enable, there is still some known miscompile problem. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@33066 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Transforms/Scalar/PredicateSimplifier.cpp')
-rw-r--r--lib/Transforms/Scalar/PredicateSimplifier.cpp2129
1 files changed, 1155 insertions, 974 deletions
diff --git a/lib/Transforms/Scalar/PredicateSimplifier.cpp b/lib/Transforms/Scalar/PredicateSimplifier.cpp
index 6578bccff1..16cc20c06a 100644
--- a/lib/Transforms/Scalar/PredicateSimplifier.cpp
+++ b/lib/Transforms/Scalar/PredicateSimplifier.cpp
@@ -41,11 +41,11 @@
// %a < %b < %c < %d
//
// with four nodes representing the properties. The InequalityGraph provides
-// queries (such as "isEqual") and mutators (such as "addEqual"). To implement
-// "isLess(%a, %c)", we start with getNode(%c) and walk downwards until
-// we reach %a or the leaf node. Note that the graph is directed and acyclic,
-// but may contain joins, meaning that this walk is not a linear time
-// algorithm.
+// querying with "isRelatedBy" and mutators "addEquality" and "addInequality".
+// To find a relationship, we start with one of the nodes any binary search
+// through its list to find where the relationships with the second node start.
+// Then we iterate through those to find the first relationship that dominates
+// our context node.
//
// To create these properties, we wait until a branch or switch instruction
// implies that a particular value is true (or false). The VRPSolver is
@@ -74,13 +74,13 @@
#include "llvm/DerivedTypes.h"
#include "llvm/Instructions.h"
#include "llvm/Pass.h"
+#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/SetOperations.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/Analysis/ET-Forest.h"
-#include "llvm/Assembly/Writer.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
@@ -89,14 +89,82 @@
#include <algorithm>
#include <deque>
#include <sstream>
-#include <map>
using namespace llvm;
STATISTIC(NumVarsReplaced, "Number of argument substitutions");
STATISTIC(NumInstruction , "Number of instructions removed");
STATISTIC(NumSimple , "Number of simple replacements");
+STATISTIC(NumBlocks , "Number of blocks marked unreachable");
namespace {
+ // SLT SGT ULT UGT EQ
+ // 0 1 0 1 0 -- GT 10
+ // 0 1 0 1 1 -- GE 11
+ // 0 1 1 0 0 -- SGTULT 12
+ // 0 1 1 0 1 -- SGEULE 13
+ // 0 1 1 1 0 -- SGTUNE 14
+ // 0 1 1 1 1 -- SGEUANY 15
+ // 1 0 0 1 0 -- SLTUGT 18
+ // 1 0 0 1 1 -- SLEUGE 19
+ // 1 0 1 0 0 -- LT 20
+ // 1 0 1 0 1 -- LE 21
+ // 1 0 1 1 0 -- SLTUNE 22
+ // 1 0 1 1 1 -- SLEUANY 23
+ // 1 1 0 1 0 -- SNEUGT 26
+ // 1 1 0 1 1 -- SANYUGE 27
+ // 1 1 1 0 0 -- SNEULT 28
+ // 1 1 1 0 1 -- SANYULE 29
+ // 1 1 1 1 0 -- NE 30
+ enum LatticeBits {
+ EQ_BIT = 1, UGT_BIT = 2, ULT_BIT = 4, SGT_BIT = 8, SLT_BIT = 16
+ };
+ enum LatticeVal {
+ GT = SGT_BIT | UGT_BIT,
+ GE = GT | EQ_BIT,
+ LT = SLT_BIT | ULT_BIT,
+ LE = LT | EQ_BIT,
+ NE = SLT_BIT | SGT_BIT | ULT_BIT | UGT_BIT,
+ SGTULT = SGT_BIT | ULT_BIT,
+ SGEULE = SGTULT | EQ_BIT,
+ SLTUGT = SLT_BIT | UGT_BIT,
+ SLEUGE = SLTUGT | EQ_BIT,
+ SNEULT = SLT_BIT | SGT_BIT | ULT_BIT,
+ SNEUGT = SLT_BIT | SGT_BIT | UGT_BIT,
+ SLTUNE = SLT_BIT | ULT_BIT | UGT_BIT,
+ SGTUNE = SGT_BIT | ULT_BIT | UGT_BIT,
+ SLEUANY = SLT_BIT | ULT_BIT | UGT_BIT | EQ_BIT,
+ SGEUANY = SGT_BIT | ULT_BIT | UGT_BIT | EQ_BIT,
+ SANYULE = SLT_BIT | SGT_BIT | ULT_BIT | EQ_BIT,
+ SANYUGE = SLT_BIT | SGT_BIT | UGT_BIT | EQ_BIT
+ };
+
+ static bool validPredicate(LatticeVal LV) {
+ switch (LV) {
+ case GT: case GE: case LT: case LE: case NE:
+ case SGTULT: case SGTUNE: case SGEULE:
+ case SLTUGT: case SLTUNE: case SLEUGE:
+ case SNEULT: case SNEUGT:
+ case SLEUANY: case SGEUANY: case SANYULE: case SANYUGE:
+ return true;
+ default:
+ return false;
+ }
+ }
+
+ /// reversePredicate - reverse the direction of the inequality
+ static LatticeVal reversePredicate(LatticeVal LV) {
+ unsigned reverse = LV ^ (SLT_BIT|SGT_BIT|ULT_BIT|UGT_BIT); //preserve EQ_BIT
+ if ((reverse & (SLT_BIT|SGT_BIT)) == 0)
+ reverse |= (SLT_BIT|SGT_BIT);
+
+ if ((reverse & (ULT_BIT|UGT_BIT)) == 0)
+ reverse |= (ULT_BIT|UGT_BIT);
+
+ LatticeVal Rev = static_cast<LatticeVal>(reverse);
+ assert(validPredicate(Rev) && "Failed reversing predicate.");
+ return Rev;
+ }
+
/// The InequalityGraph stores the relationships between values.
/// Each Value in the graph is assigned to a Node. Nodes are pointer
/// comparable for equality. The caller is expected to maintain the logical
@@ -105,38 +173,51 @@ namespace {
/// The InequalityGraph class may invalidate Node*s after any mutator call.
/// @brief The InequalityGraph stores the relationships between values.
class VISIBILITY_HIDDEN InequalityGraph {
+ ETNode *TreeRoot;
+
+ InequalityGraph(); // DO NOT IMPLEMENT
+ InequalityGraph(InequalityGraph &); // DO NOT IMPLEMENT
public:
+ explicit InequalityGraph(ETNode *TreeRoot) : TreeRoot(TreeRoot) {}
+
class Node;
- // LT GT EQ
- // 0 0 0 -- invalid (false)
- // 0 0 1 -- invalid (EQ)
- // 0 1 0 -- GT
- // 0 1 1 -- GE
- // 1 0 0 -- LT
- // 1 0 1 -- LE
- // 1 1 0 -- NE
- // 1 1 1 -- invalid (true)
- enum LatticeBits {
- EQ_BIT = 1, GT_BIT = 2, LT_BIT = 4
- };
- enum LatticeVal {
- GT = GT_BIT, GE = GT_BIT | EQ_BIT,
- LT = LT_BIT, LE = LT_BIT | EQ_BIT,
- NE = GT_BIT | LT_BIT
+ /// This is a StrictWeakOrdering predicate that sorts ETNodes by how many
+ /// children they have. With this, you can iterate through a list sorted by
+ /// this operation and the first matching entry is the most specific match
+ /// for your basic block. The order provided is total; ETNodes with the
+ /// same number of children are sorted by pointer address.
+ struct VISIBILITY_HIDDEN OrderByDominance {
+ bool operator()(const ETNode *LHS, const ETNode *RHS) const {
+ unsigned LHS_spread = LHS->getDFSNumOut() - LHS->getDFSNumIn();
+ unsigned RHS_spread = RHS->getDFSNumOut() - RHS->getDFSNumIn();
+ if (LHS_spread != RHS_spread) return LHS_spread < RHS_spread;
+ else return LHS < RHS;
+ }
};
- static bool validPredicate(LatticeVal LV) {
- return LV > 1 && LV < 7;
- }
+ /// An Edge is contained inside a Node making one end of the edge implicit
+ /// and contains a pointer to the other end. The edge contains a lattice
+ /// value specifying the relationship between the two nodes. Further, there
+ /// is an ETNode specifying which subtree of the dominator the edge applies.
+ class VISIBILITY_HIDDEN Edge {
+ public:
+ Edge(unsigned T, LatticeVal V, ETNode *ST)
+ : To(T), LV(V), Subtree(ST) {}
- private:
- typedef std::map<Value *, Node *> NodeMapType;
- NodeMapType Nodes;
+ unsigned To;
+ LatticeVal LV;
+ ETNode *Subtree;
- const InequalityGraph *ConcreteIG;
+ bool operator<(const Edge &edge) const {
+ if (To != edge.To) return To < edge.To;
+ else return OrderByDominance()(Subtree, edge.Subtree);
+ }
+ bool operator<(unsigned to) const {
+ return To < to;
+ }
+ };
- public:
/// A single node in the InequalityGraph. This stores the canonical Value
/// for the node, as well as the relationships with the neighbours.
///
@@ -148,367 +229,488 @@ namespace {
class VISIBILITY_HIDDEN Node {
friend class InequalityGraph;
+ typedef SmallVector<Edge, 4> RelationsType;
+ RelationsType Relations;
+
Value *Canonical;
- typedef SmallVector<std::pair<Node *, LatticeVal>, 4> RelationsType;
- RelationsType Relations;
+ // TODO: can this idea improve performance?
+ //friend class std::vector<Node>;
+ //Node(Node &N) { RelationsType.swap(N.RelationsType); }
+
public:
typedef RelationsType::iterator iterator;
typedef RelationsType::const_iterator const_iterator;
+ Node(Value *V) : Canonical(V) {}
+
private:
+#ifndef NDEBUG
+ public:
+ virtual void dump() const {
+ dump(*cerr.stream());
+ }
+ private:
+ void dump(std::ostream &os) const {
+ os << *getValue() << ":\n";
+ for (Node::const_iterator NI = begin(), NE = end(); NI != NE; ++NI) {
+ static const std::string names[32] =
+ { "000000", "000001", "000002", "000003", "000004", "000005",
+ "000006", "000007", "000008", "000009", " >", " >=",
+ " s>u<", "s>=u<=", " s>", " s>=", "000016", "000017",
+ " s<u>", "s<=u>=", " <", " <=", " s<", " s<=",
+ "000024", "000025", " u>", " u>=", " u<", " u<=",
+ " !=", "000031" };
+ os << " " << names[NI->LV] << " " << NI->To
+ << "(" << NI->Subtree << ")\n";
+ }
+ }
+#endif
+
+ public:
+ iterator begin() { return Relations.begin(); }
+ iterator end() { return Relations.end(); }
+ const_iterator begin() const { return Relations.begin(); }
+ const_iterator end() const { return Relations.end(); }
+
+ iterator find(unsigned n, ETNode *Subtree) {
+ iterator E = end();
+ for (iterator I = std::lower_bound(begin(), E, n);
+ I != E && I->To == n; ++I) {
+ if (Subtree->DominatedBy(I->Subtree))
+ return I;
+ }
+ return E;
+ }
+
+ const_iterator find(unsigned n, ETNode *Subtree) const {
+ const_iterator E = end();
+ for (const_iterator I = std::lower_bound(begin(), E, n);
+ I != E && I->To == n; ++I) {
+ if (Subtree->DominatedBy(I->Subtree))
+ return I;
+ }
+ return E;
+ }
+
+ Value *getValue() const
+ {
+ return Canonical;
+ }
+
/// Updates the lattice value for a given node. Create a new entry if
/// one doesn't exist, otherwise it merges the values. The new lattice
/// value must not be inconsistent with any previously existing value.
- void update(Node *N, LatticeVal R) {
- iterator I = find(N);
+ void update(unsigned n, LatticeVal R, ETNode *Subtree) {
+ assert(validPredicate(R) && "Invalid predicate.");
+ iterator I = find(n, Subtree);
if (I == end()) {
- Relations.push_back(std::make_pair(N, R));
+ Edge edge(n, R, Subtree);
+ iterator Insert = std::lower_bound(begin(), end(), edge);
+ Relations.insert(Insert, edge);
} else {
- I->second = static_cast<LatticeVal>(I->second & R);
- assert(validPredicate(I->second) &&
- "Invalid union of lattice values.");
+ LatticeVal LV = static_cast<LatticeVal>(I->LV & R);
+ assert(validPredicate(LV) && "Invalid union of lattice values.");
+ if (LV != I->LV) {
+ if (Subtree == I->Subtree)
+ I->LV = LV;
+ else {
+ assert(Subtree->DominatedBy(I->Subtree) &&
+ "Find returned subtree that doesn't apply.");
+
+ Edge edge(n, R, Subtree);
+ iterator Insert = std::lower_bound(begin(), end(), edge);
+ Relations.insert(Insert, edge);
+ }
+ }
}
}
+ };
- void assign(Node *N, LatticeVal R) {
- iterator I = find(N);
- if (I != end()) I->second = R;
+ private:
+ struct VISIBILITY_HIDDEN NodeMapEdge {
+ Value *V;
+ unsigned index;
+ ETNode *Subtree;
- Relations.push_back(std::make_pair(N, R));
- }
+ NodeMapEdge(Value *V, unsigned index, ETNode *Subtree)
+ : V(V), index(index), Subtree(Subtree) {}
- public:
- iterator begin() { return Relations.begin(); }
- iterator end() { return Relations.end(); }
- iterator find(Node *N) {
- iterator I = begin();
- for (iterator E = end(); I != E; ++I)
- if (I->first == N) break;
- return I;
+ bool operator==(const NodeMapEdge &RHS) const {
+ return V == RHS.V &&
+ Subtree == RHS.Subtree;
}
- const_iterator begin() const { return Relations.begin(); }
- const_iterator end() const { return Relations.end(); }
- const_iterator find(Node *N) const {
- const_iterator I = begin();
- for (const_iterator E = end(); I != E; ++I)
- if (I->first == N) break;
- return I;
+ bool operator<(const NodeMapEdge &RHS) const {
+ if (V != RHS.V) return V < RHS.V;
+ return OrderByDominance()(Subtree, RHS.Subtree);
}
- unsigned findIndex(Node *N) {
- unsigned i = 0;
- iterator I = begin();
- for (iterator E = end(); I != E; ++I, ++i)
- if (I->first == N) return i;
- return (unsigned)-1;
+ bool operator<(Value *RHS) const {
+ return V < RHS;
}
-
- void erase(iterator i) { Relations.erase(i); }
-
- Value *getValue() const { return Canonical; }
- void setValue(Value *V) { Canonical = V; }
-
- void addNotEqual(Node *N) { update(N, NE); }
- void addLess(Node *N) { update(N, LT); }
- void addLessEqual(Node *N) { update(N, LE); }
- void addGreater(Node *N) { update(N, GT); }
- void addGreaterEqual(Node *N) { update(N, GE); }
};
- InequalityGraph() : ConcreteIG(NULL) {}
-
- InequalityGraph(const InequalityGraph &_IG) {
-#if 0 // disable COW
- if (_IG.ConcreteIG) ConcreteIG = _IG.ConcreteIG;
- else ConcreteIG = &_IG;
-#else
- ConcreteIG = &_IG;
- materialize();
-#endif
+ typedef std::vector<NodeMapEdge> NodeMapType;
+ NodeMapType NodeMap;
+
+ std::vector<Node> Nodes;
+
+ std::vector<std::pair<ConstantIntegral *, unsigned> > Constants;
+ void initializeConstant(Constant *C, unsigned index) {
+ ConstantIntegral *CI = dyn_cast<ConstantIntegral>(C);
+ if (!CI) return;
+
+ // XXX: instead of O(n) calls to addInequality, just find the 2, 3 or 4
+ // nodes that are nearest less than or greater than (signed or unsigned).
+ for (std::vector<std::pair<ConstantIntegral *, unsigned> >::iterator
+ I = Constants.begin(), E = Constants.end(); I != E; ++I) {
+ ConstantIntegral *Other = I->first;
+ if (CI->getType() == Other->getType()) {
+ unsigned lv = 0;
+
+ if (CI->getZExtValue() < Other->getZExtValue())
+ lv |= ULT_BIT;
+ else
+ lv |= UGT_BIT;
+
+ if (CI->getSExtValue() < Other->getSExtValue())
+ lv |= SLT_BIT;
+ else
+ lv |= SGT_BIT;
+
+ LatticeVal LV = static_cast<LatticeVal>(lv);
+ assert(validPredicate(LV) && "Not a valid predicate.");
+ if (!isRelatedBy(index, I->second, TreeRoot, LV))
+ addInequality(index, I->second, TreeRoot, LV);
+ }
+ }
+ Constants.push_back(std::make_pair(CI, index));
}
- ~InequalityGraph();
-
- private:
- void materialize();
-
public:
- /// If the Value is in the graph, return the canonical form. Otherwise,
- /// return the original Value.
- Value *canonicalize(Value *V) const {
- if (const Node *N = getNode(V))
- return N->getValue();
- else
- return V;
+ /// node - returns the node object at a given index retrieved from getNode.
+ /// Index zero is reserved and may not be passed in here. The pointer
+ /// returned is valid until the next call to newNode or getOrInsertNode.
+ Node *node(unsigned index) {
+ assert(index != 0 && "Zero index is reserved for not found.");
+ assert(index <= Nodes.size() && "Index out of range.");
+ return &Nodes[index-1];
}
- /// Returns the node currently representing Value V, or null if no such
+ /// Returns the node currently representing Value V, or zero if no such
/// node exists.
- Node *getNode(Value *V) {
- materialize();
-
- NodeMapType::const_iterator I = Nodes.find(V);
- return (I != Nodes.end()) ? I->second : 0;
- }
-
- const Node *getNode(Value *V) const {
- if (ConcreteIG) return ConcreteIG->getNode(V);
-
- NodeMapType::const_iterator I = Nodes.find(V);
- return (I != Nodes.end()) ? I->second : 0;
+ unsigned getNode(Value *V, ETNode *Subtree) {
+ NodeMapType::iterator E = NodeMap.end();
+ NodeMapEdge Edge(V, 0, Subtree);
+ NodeMapType::iterator I = std::lower_bound(NodeMap.begin(), E, Edge);
+ while (I != E && I->V == V) {
+ if (Subtree->DominatedBy(I->Subtree))
+ return I->index;
+ ++I;
+ }
+ return 0;
}
- Node *getOrInsertNode(Value *V) {
- if (Node *N = getNode(V))
- return N;
+ /// getOrInsertNode - always returns a valid node index, creating a node
+ /// to match the Value if needed.
+ unsigned getOrInsertNode(Value *V, ETNode *Subtree) {
+ if (unsigned n = getNode(V, Subtree))
+ return n;
else
return newNode(V);
}
- Node *newNode(Value *V) {
- //DOUT << "new node: " << *V << "\n";
- materialize();
- Node *&N = Nodes[V];
- assert(N == 0 && "Node already exists for value.");
- N = new Node();
- N->setValue(V);
- return N;
- }
+ /// newNode - creates a new node for a given Value and returns the index.
+ unsigned newNode(Value *V) {
+ Nodes.push_back(Node(V));
- /// Returns true iff the nodes are provably inequal.
- bool isNotEqual(const Node *N1, const Node *N2) const {
- if (N1 == N2) return false;
- for (Node::const_iterator I = N1->begin(), E = N1->end(); I != E; ++I) {
- if (I->first == N2)
- return (I->second & EQ_BIT) == 0;
- }
- return isLess(N1, N2) || isGreater(N1, N2);
- }
+ NodeMapEdge MapEntry = NodeMapEdge(V, Nodes.size(), TreeRoot);
+ assert(!std::binary_search(NodeMap.begin(), NodeMap.end(), MapEntry) &&
+ "Attempt to create a duplicate Node.");
+ NodeMap.insert(std::lower_bound(NodeMap.begin(), NodeMap.end(),
+ MapEntry), MapEntry);
- /// Returns true iff N1 is provably less than N2.
- bool isLess(const Node *N1, const Node *N2) const {
- if (N1 == N2) return false;
- for (Node::const_iterator I = N2->begin(), E = N2->end(); I != E; ++I) {
- if (I->first == N1)
- return I->second == LT;
- }
- for (Node::const_iterator I = N2->begin(), E = N2->end(); I != E; ++I) {
- if ((I->second & (LT_BIT | GT_BIT)) == LT_BIT)
- if (isLess(N1, I->first)) return true;
- }
- return false;
- }
+#if 1
+ // This is the missing piece to turn on VRP.
+ if (Constant *C = dyn_cast<Constant>(V))
+ initializeConstant(C, MapEntry.index);
+#endif
- /// Returns true iff N1 is provably less than or equal to N2.
- bool isLessEqual(const Node *N1, const Node *N2) const {
- if (N1 == N2) return true;
- for (Node::const_iterator I = N2->begin(), E = N2->end(); I != E; ++I) {
- if (I->first == N1)
- return (I->second & (LT_BIT | GT_BIT)) == LT_BIT;
- }
- for (Node::const_iterator I = N2->begin(), E = N2->end(); I != E; ++I) {
- if ((I->second & (LT_BIT | GT_BIT)) == LT_BIT)
- if (isLessEqual(N1, I->first)) return true;
- }
- return false;
+ return MapEntry.index;
}
- /// Returns true iff N1 is provably greater than N2.
- bool isGreater(const Node *N1, const Node *N2) const {
- return isLess(N2, N1);
+ /// If the Value is in the graph, return the canonical form. Otherwise,
+ /// return the original Value.
+ Value *canonicalize(Value *V, ETNode *Subtree) {
+ if (isa<Constant>(V)) return V;
+
+ if (unsigned n = getNode(V, Subtree))
+ return node(n)->getValue();
+ else
+ return V;
}
- /// Returns true iff N1 is provably greater than or equal to N2.
- bool isGreaterEqual(const Node *N1, const Node *N2) const {
- return isLessEqual(N2, N1);
+ /// isRelatedBy - true iff n1 op n2
+ bool isRelatedBy(unsigned n1, unsigned n2, ETNode *Subtree, LatticeVal LV) {
+ if (n1 == n2) return LV & EQ_BIT;
+
+ Node *N1 = node(n1);
+ Node::iterator I = N1->find(n2, Subtree), E = N1->end();
+ if (I != E) return (I->LV & LV) == I->LV;
+
+ return false;
}
// The add* methods assume that your input is logically valid and may
// assertion-fail or infinitely loop if you attempt a contradiction.
- void addEqual(Node *N, Value *V) {
- materialize();
- Nodes[V] = N;
- }
+ void addEquality(unsigned n, Value *V, ETNode *Subtree) {
+ assert(canonicalize(node(n)->getValue(), Subtree) == node(n)->getValue()
+ && "Node's 'canonical' choice isn't best within this subtree.");
- void addNotEqual(Node *N1, Node *N2) {
- assert(N1 != N2 && "A node can't be inequal to itself.");
- materialize();
- N1->addNotEqual(N2);
- N2->addNotEqual(N1);
- }
+ // Suppose that we are given "%x -> node #1 (%y)". The problem is that
+ // we may already have "%z -> node #2 (%x)" somewhere above us in the
+ // graph. We need to find those edges and add "%z -> node #1 (%y)"
+ // to keep the lookups canonical.
- /// N1 is less than N2.
- void addLess(Node *N1, Node *N2) {
- assert(N1 != N2 && !isLess(N2, N1) && "Attempt to create < cycle.");
- materialize();
- N2->addLess(N1);
- N1->addGreater(N2);
- }
+ std::vector<Value *> ToRepoint;
+ ToRepoint.push_back(V);
- /// N1 is less than or equal to N2.
- void addLessEqual(Node *N1, Node *N2) {
- assert(N1 != N2 && "Nodes are equal. Use mergeNodes instead.");
- assert(!isGreater(N1, N2) && "Impossible: Adding x <= y when x > y.");
- materialize();
- N2->addLessEqual(N1);
- N1->addGreaterEqual(N2);
- }
+ if (unsigned Conflict = getNode(V, Subtree)) {
+ // XXX: NodeMap.size() exceeds 68000 entries compiling kimwitu++!
+ // This adds 57 seconds to the otherwise 3 second build. Unacceptable.
+ //
+ // IDEA: could we iterate 1..Nodes.size() calling getNode? It's
+ // O(n log n) but kimwitu++ only has about 300 nodes.
+ for (NodeMapType::iterator I = NodeMap.begin(), E = NodeMap.end();
+ I != E; ++I) {
+ if (I->index == Conflict && Subtree->DominatedBy(I->Subtree))
+ ToRepoint.push_back(I->V);
+ }
+ }
+
+ for (std::vector<Value *>::iterator VI = ToRepoint.begin(),
+ VE = ToRepoint.end(); VI != VE; ++VI) {
+ Value *V = *VI;
+
+ // XXX: review this code. This may be doing too many insertions.
+ NodeMapEdge Edge(V, n, Subtree);
+ NodeMapType::iterator E = NodeMap.end();
+ NodeMapType::iterator I = std::lower_bound(NodeMap.begin(), E, Edge);
+ if (I == E || I->V != V || I->Subtree != Subtree) {
+ // New Value
+ NodeMap.insert(I, Edge);
+ } else if (I != E && I->V == V && I->Subtree == Subtree) {
+ // Update best choice
+ I->index = n;
+ }
- /// Find the transitive closure starting at a node walking down the edges
- /// of type Val. Type Inserter must be an inserter that accepts Node *.
- template <typename Inserter>
- void transitiveClosure(Node *N, LatticeVal Val, Inserter insert) {
- for (Node::iterator I = N->begin(), E = N->end(); I != E; ++I) {
- if (I->second == Val) {
- *insert = I->first;
- transitiveClosure(I->first, Val, insert);
+#ifndef NDEBUG
+ Node *N = node(n);
+ if (isa<Constant>(V)) {
+ if (isa<Constant>(N->getValue())) {
+ assert(V == N->getValue() && "Constant equals different constant?");
+ }
}
+#endif
}
}
- /// Kills off all the nodes in Kill by replicating their properties into
- /// node N. The elements of Kill must be unique. After merging, N's new
- /// canonical value is NewCanonical. Type C must be a container of Node *.
- template <typename C>
- void mergeNodes(Node *N, C &Kill, Value *NewCanonical);
+ /// addInequality - Sets n1 op n2.
+ /// It is also an error to call this on an inequality that is already true.
+ void addInequality(unsigned n1, unsigned n2, ETNode *Subtree,
+ LatticeVal LV1) {
+ assert(n1 != n2 && "A node can't be inequal to itself.");
+
+ if (LV1 != NE)
+ assert(!isRelatedBy(n1, n2, Subtree, reversePredicate(LV1)) &&
+ "Contradictory inequality.");
+
+ Node *N1 = node(n1);
+ Node *N2 = node(n2);
+
+ // Suppose we're adding %n1 < %n2. Find all the %a < %n1 and
+ // add %a < %n2 too. This keeps the graph fully connected.
+ if (LV1 != NE) {
+ // Someone with a head for this sort of logic, please review this.
+ // Given that %x SLTUGT %y and %a SLEUANY %x, what is the relationship
+ // between %a and %y? I believe the below code is correct, but I don't
+ // think it's the most efficient solution.
+
+ unsigned LV1_s = LV1 & (SLT_BIT|SGT_BIT);
+ unsigned LV1_u = LV1 & (ULT_BIT|UGT_BIT);
+ for (Node::iterator I = N1->begin(), E = N1->end(); I != E; ++I) {
+ if (I->LV != NE && I->To != n2) {
+ ETNode *Local_Subtree = NULL;
+ if (Subtree->DominatedBy(I->Subtree))
+ Local_Subtree = Subtree;
+ else if (I->Subtree->DominatedBy(Subtree))
+ Local_Subtree = I->Subtree;
+
+ if (Local_Subtree) {
+ unsigned new_relationship = 0;
+ LatticeVal ILV = reversePredicate(I->LV);
+ unsigned ILV_s = ILV & (SLT_BIT|SGT_BIT);
+ unsigned ILV_u = ILV & (ULT_BIT|UGT_BIT);
+
+ if (LV1_s != (SLT_BIT|SGT_BIT) && ILV_s == LV1_s)
+ new_relationship |= ILV_s;
+
+ if (LV1_u != (ULT_BIT|UGT_BIT) && ILV_u == LV1_u)
+ new_relationship |= ILV_u;
+
+ if (new_relationship) {
+ if ((new_relationship & (SLT_BIT|SGT_BIT)) == 0)
+ new_relationship |= (SLT_BIT|SGT_BIT);
+ if ((new_relationship & (ULT_BIT|UGT_BIT)) == 0)
+ new_relationship |= (ULT_BIT|UGT_BIT);
+ if ((LV1 & EQ_BIT) && (ILV & EQ_BIT))
+ new_relationship |= EQ_BIT;
+
+ LatticeVal NewLV = static_cast<LatticeVal>(new_relationship);
+
+ node(I->To)->update(n2, NewLV, Local_Subtree);
+ N2->update(I->To, reversePredicate(NewLV), Local_Subtree);
+ }
+ }
+ }
+ }
+
+ for (Node::iterator I = N2->begin(), E = N2->end(); I != E; ++I) {
+ if (I->LV != NE && I->To != n1) {
+ ETNode *Local_Subtree = NULL;
+ if (Subtree->DominatedBy(I->Subtree))
+ Local_Subtree = Subtree;
+ else if (I->Subtree->DominatedBy(Subtree))
+ Local_Subtree = I->Subtree;
+
+ if (Local_Subtree) {
+ unsigned new_relationship = 0;
+ unsigned ILV_s = I->LV & (SLT_BIT|SGT_BIT);
+ unsigned ILV_u = I->LV & (ULT_BIT|UGT_BIT);
+
+ if (LV1_s != (SLT_BIT|SGT_BIT) && ILV_s == LV1_s)
+ new_relationship |= ILV_s;
+
+ if (LV1_u != (ULT_BIT|UGT_BIT) && ILV_u == LV1_u)
+ new_relationship |= ILV_u;
+
+ if (new_relationship) {
+ if ((new_relationship & (SLT_BIT|SGT_BIT)) == 0)
+ new_relationship |= (SLT_BIT|SGT_BIT);
+ if ((new_relationship & (ULT_BIT|UGT_BIT)) == 0)
+ new_relationship |= (ULT_BIT|UGT_BIT);
+ if ((LV1 & EQ_BIT) && (I->LV & EQ_BIT))
+ new_relationship |= EQ_BIT;
+
+ LatticeVal NewLV = static_cast<LatticeVal>(new_relationship);
+
+ N1->update(I->To, NewLV, Local_Subtree);
+ node(I->To)->update(n1, reversePredicate(NewLV), Local_Subtree);
+ }
+ }
+ }
+ }
+ }
+
+ N1->update(n2, LV1, Subtree);
+ N2->update(n1, reversePredicate(LV1), Subtree);
+ }
/// Removes a Value from the graph, but does not delete any nodes. As this
/// method does not delete Nodes, V may not be the canonical choice for
- /// any node.
+ /// a node with any relationships. It is invalid to call newNode on a Value
+ /// that has been removed.
void remove(Value *V) {
- materialize();
-
- for (NodeMapType::iterator I = Nodes.begin(), E = Nodes.end(); I != E;) {
- NodeMapType::iterator J = I++;
- assert(J->second->getValue() != V && "Can't delete canonical choice.");
- if (J->first == V) Nodes.erase(J);
+ for (unsigned i = 0; i < NodeMap.size();) {
+ NodeMapType::iterator I = NodeMap.begin()+i;
+ assert((node(I->index)->getValue() != V || node(I->index)->begin() ==
+ node(I->index)->end()) && "Tried to delete in-use node.");
+ if (I->V == V) {
+#ifndef NDEBUG
+ if (node(I->index)->getValue() == V)
+ node(I->index)->Canonical = NULL;
+#endif
+ NodeMap.erase(I);
+ } else ++i;
}
}
#ifndef NDEBUG
- void debug(std::ostream &os) const {
+ virtual void dump() {
+ dump(*cerr.stream());
+ }
+
+ void dump(std::ostream &os) {
std::set<Node *> VisitedNodes;
- for (NodeMapType::const_iterator I = Nodes.begin(), E = Nodes.end();
+ for (NodeMapType::const_iterator I = NodeMap.begin(), E = NodeMap.end();
I != E; ++I) {
- Node *N = I->second;
- os << *I->first << " == " << *N->getValue() << "\n";
+ Node *N = node(I->index);
+ os << *I->V << " == " << I->index << "(" << I->Subtree << ")\n";
if (VisitedNodes.insert(N).second) {
- os << *N->getValue() << ":\n";
- for (Node::const_iterator NI = N->begin(), NE = N->end();
- NI != NE; ++NI) {
- static const std::string names[8] =
- { "00", "01", " <", "<=", " >", ">=", "!=", "07" };
- os << " " << names[NI->second] << " "
- << *NI->first->getValue() << "\n";
- }
+ os << I->index << ". ";
+ if (!N->getValue()) os << "(deleted node)\n";
+ else N->dump(os);
}
}
}
#endif
};
- InequalityGraph::~InequalityGraph() {
- if (ConcreteIG) return;
-
- std::vector<Node *> Remove;
- for (NodeMapType::iterator I = Nodes.begin(), E = Nodes.end();
- I != E; ++I) {
- if (I->first == I->second->getValue())
- Remove.push_back(I->second);
- }
- for (std::vector<Node *>::iterator I = Remove.begin(), E = Remove.end();
- I != E; ++I) {
- delete *I;
- }
- }
-
- template <typename C>
- void InequalityGraph::mergeNodes(Node *N, C &Kill, Value *NewCanonical) {
- materialize();
-
- // Merge the relationships from the members of Kill into N.
- for (typename C::iterator KI = Kill.begin(), KE = Kill.end();
- KI != KE; ++KI) {
-
- for (Node::iterator I = (*KI)->begin(), E = (*KI)->end(); I != E; ++I) {
- if (I->first == N) continue;
-
- Node::iterator NI = N->find(I->first);
- if (NI == N->end()) {
- N->Relations.push_back(std::make_pair(I->first, I->second));
- } else {
- unsigned char LV = NI->second & I->second;
- if (LV == EQ_BIT) {
-
- assert(std::find(Kill.begin(), Kill.end(), I->first) != Kill.end()
- && "Lost EQ property.");
- N->erase(NI);
- } else {
- NI->second = static_cast<LatticeVal>(LV);
- assert(InequalityGraph::validPredicate(NI->second) &&
- "Invalid union of lattice values.");
- }
- }
+ /// UnreachableBlocks keeps tracks of blocks that are for one reason or
+ /// another discovered to be unreachable. This is used to cull the graph when
+ /// analyzing instructions, and to mark blocks with the "unreachable"
+ /// terminator instruction after the function has executed.
+ class VISIBILITY_HIDDEN UnreachableBlocks {
+ private:
+ std::vector<BasicBlock *> DeadBlocks;
- // All edges are reciprocal; every Node that Kill points to also
- // contains a pointer to Kill. Replace those with pointers with N.
- unsigned iter = I->first->findIndex(*KI);
- assert(iter != (unsigned)-1 && "Edge not reciprocal.");
- I->first->assign(N, (I->first->begin()+iter)->second);
- I->first->erase(I->first->begin()+iter);
- }
+ public:
+ /// mark - mark a block as dead
+ void mark(BasicBlock *BB) {
+ std::vector<BasicBlock *>::iterator E = DeadBlocks.end();
+ std::vector<BasicBlock *>::iterator I =
+ std::lower_bound(DeadBlocks.begin(), E, BB);
- // Removing references from N to Kill.
- Node::iterator NI = N->find(*KI);
- if (NI != N->end()) {
- N->erase(NI); // breaks reciprocity until Kill is deleted.
- }
+ if (I == E || *I != BB) DeadBlocks.insert(I, BB);
}
- N->setValue(NewCanonical);
+ /// isDead - returns whether a block is known to be dead already
+ bool isDead(BasicBlock *BB) {
+ std::vector<BasicBlock *>::iterator E = DeadBlocks.end();
+ std::vector<BasicBlock *>::iterator I =
+ std::lower_bound(DeadBlocks.begin(), E, BB);
- // Update value mapping to point to the merged node.
- for (NodeMapType::iterator I = Nodes.begin(), E = Nodes.end();
- I != E; ++I) {
- if (std::find(Kill.begin(), Kill.end(), I->second) != Kill.end())
- I->second = N;
+ return I != E && *I == BB;
}
- for (typename C::iterator KI = Kill.begin(), KE = Kill.end();
- KI != KE; ++KI) {
- delete *KI;
- }
- }
+ /// kill - replace the dead blocks' terminator with an UnreachableInst.
+ bool kill() {
+ bool modified = false;
+ for (std::vector<BasicBlock *>::iterator I = DeadBlocks.begin(),
+ E = DeadBlocks.end(); I != E; ++I) {
+ BasicBlock *BB = *I;
- void InequalityGraph::materialize() {
- if (!ConcreteIG) return;
- const InequalityGraph *IG = ConcreteIG;
- ConcreteIG = NULL;