mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2024-12-26 21:32:10 +00:00
514ab348fd
The meaning of getTypeSize was not clear - clarifying it is important now that we have x86 long double and arbitrary precision integers. The issue with long double is that it requires 80 bits, and this is not a multiple of its alignment. This gives a primitive type for which getTypeSize differed from getABITypeSize. For arbitrary precision integers it is even worse: there is the minimum number of bits needed to hold the type (eg: 36 for an i36), the maximum number of bits that will be overwriten when storing the type (40 bits for i36) and the ABI size (i.e. the storage size rounded up to a multiple of the alignment; 64 bits for i36). This patch removes getTypeSize (not really - it is still there but deprecated to allow for a gradual transition). Instead there is: (1) getTypeSizeInBits - a number of bits that suffices to hold all values of the type. For a primitive type, this is the minimum number of bits. For an i36 this is 36 bits. For x86 long double it is 80. This corresponds to gcc's TYPE_PRECISION. (2) getTypeStoreSizeInBits - the maximum number of bits that is written when storing the type (or read when reading it). For an i36 this is 40 bits, for an x86 long double it is 80 bits. This is the size alias analysis is interested in (getTypeStoreSize returns the number of bytes). There doesn't seem to be anything corresponding to this in gcc. (3) getABITypeSizeInBits - this is getTypeStoreSizeInBits rounded up to a multiple of the alignment. For an i36 this is 64, for an x86 long double this is 96 or 128 depending on the OS. This is the spacing between consecutive elements when you form an array out of this type (getABITypeSize returns the number of bytes). This is TYPE_SIZE in gcc. Since successive elements in a SequentialType (arrays, pointers and vectors) need to be aligned, the spacing between them will be given by getABITypeSize. This means that the size of an array is the length times the getABITypeSize. It also means that GEP computations need to use getABITypeSize when computing offsets. Furthermore, if an alloca allocates several elements at once then these too need to be aligned, so the size of the alloca has to be the number of elements multiplied by getABITypeSize. Logically speaking this doesn't have to be the case when allocating just one element, but it is simpler to also use getABITypeSize in this case. So alloca's and mallocs should use getABITypeSize. Finally, since gcc's only notion of size is that given by getABITypeSize, if you want to output assembler etc the same as gcc then getABITypeSize is the size you want. Since a store will overwrite no more than getTypeStoreSize bytes, and a read will read no more than that many bytes, this is the notion of size appropriate for alias analysis calculations. In this patch I have corrected all type size uses except some of those in ScalarReplAggregates, lib/Codegen, lib/Target (the hard cases). I will get around to auditing these too at some point, but I could do with some help. Finally, I made one change which I think wise but others might consider pointless and suboptimal: in an unpacked struct the amount of space allocated for a field is now given by the ABI size rather than getTypeStoreSize. I did this because every other place that reserves memory for a type (eg: alloca) now uses getABITypeSize, and I didn't want to make an exception for unpacked structs, i.e. I did it to make things more uniform. This only effects structs containing long doubles and arbitrary precision integers. If someone wants to pack these types more tightly they can always use a packed struct. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@43620 91177308-0d34-0410-b5e6-96231b3b80d8
2657 lines
92 KiB
C++
2657 lines
92 KiB
C++
//===-- PredicateSimplifier.cpp - Path Sensitive Simplifier ---------------===//
|
|
//
|
|
// The LLVM Compiler Infrastructure
|
|
//
|
|
// This file was developed by Nick Lewycky and is distributed under the
|
|
// University of Illinois Open Source License. See LICENSE.TXT for details.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Path-sensitive optimizer. In a branch where x == y, replace uses of
|
|
// x with y. Permits further optimization, such as the elimination of
|
|
// the unreachable call:
|
|
//
|
|
// void test(int *p, int *q)
|
|
// {
|
|
// if (p != q)
|
|
// return;
|
|
//
|
|
// if (*p != *q)
|
|
// foo(); // unreachable
|
|
// }
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The InequalityGraph focusses on four properties; equals, not equals,
|
|
// less-than and less-than-or-equals-to. The greater-than forms are also held
|
|
// just to allow walking from a lesser node to a greater one. These properties
|
|
// are stored in a lattice; LE can become LT or EQ, NE can become LT or GT.
|
|
//
|
|
// These relationships define a graph between values of the same type. Each
|
|
// Value is stored in a map table that retrieves the associated Node. This
|
|
// is how EQ relationships are stored; the map contains pointers from equal
|
|
// Value to the same node. The node contains a most canonical Value* form
|
|
// and the list of known relationships with other nodes.
|
|
//
|
|
// If two nodes are known to be inequal, then they will contain pointers to
|
|
// each other with an "NE" relationship. If node getNode(%x) is less than
|
|
// getNode(%y), then the %x node will contain <%y, GT> and %y will contain
|
|
// <%x, LT>. This allows us to tie nodes together into a graph like this:
|
|
//
|
|
// %a < %b < %c < %d
|
|
//
|
|
// with four nodes representing the properties. The InequalityGraph provides
|
|
// 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
|
|
// responsible for analyzing the variable and seeing what new inferences
|
|
// can be made from each property. For example:
|
|
//
|
|
// %P = icmp ne i32* %ptr, null
|
|
// %a = and i1 %P, %Q
|
|
// br i1 %a label %cond_true, label %cond_false
|
|
//
|
|
// For the true branch, the VRPSolver will start with %a EQ true and look at
|
|
// the definition of %a and find that it can infer that %P and %Q are both
|
|
// true. From %P being true, it can infer that %ptr NE null. For the false
|
|
// branch it can't infer anything from the "and" instruction.
|
|
//
|
|
// Besides branches, we can also infer properties from instruction that may
|
|
// have undefined behaviour in certain cases. For example, the dividend of
|
|
// a division may never be zero. After the division instruction, we may assume
|
|
// that the dividend is not equal to zero.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// The ValueRanges class stores the known integer bounds of a Value. When we
|
|
// encounter i8 %a u< %b, the ValueRanges stores that %a = [1, 255] and
|
|
// %b = [0, 254].
|
|
//
|
|
// It never stores an empty range, because that means that the code is
|
|
// unreachable. It never stores a single-element range since that's an equality
|
|
// relationship and better stored in the InequalityGraph, nor an empty range
|
|
// since that is better stored in UnreachableBlocks.
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#define DEBUG_TYPE "predsimplify"
|
|
#include "llvm/Transforms/Scalar.h"
|
|
#include "llvm/Constants.h"
|
|
#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/SetVector.h"
|
|
#include "llvm/ADT/Statistic.h"
|
|
#include "llvm/ADT/STLExtras.h"
|
|
#include "llvm/Analysis/Dominators.h"
|
|
#include "llvm/Assembly/Writer.h"
|
|
#include "llvm/Support/CFG.h"
|
|
#include "llvm/Support/Compiler.h"
|
|
#include "llvm/Support/ConstantRange.h"
|
|
#include "llvm/Support/Debug.h"
|
|
#include "llvm/Support/InstVisitor.h"
|
|
#include "llvm/Target/TargetData.h"
|
|
#include "llvm/Transforms/Utils/Local.h"
|
|
#include <algorithm>
|
|
#include <deque>
|
|
#include <sstream>
|
|
#include <stack>
|
|
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");
|
|
STATISTIC(NumSnuggle , "Number of comparisons snuggled");
|
|
|
|
namespace {
|
|
class DomTreeDFS {
|
|
public:
|
|
class Node {
|
|
friend class DomTreeDFS;
|
|
public:
|
|
typedef std::vector<Node *>::iterator iterator;
|
|
typedef std::vector<Node *>::const_iterator const_iterator;
|
|
|
|
unsigned getDFSNumIn() const { return DFSin; }
|
|
unsigned getDFSNumOut() const { return DFSout; }
|
|
|
|
BasicBlock *getBlock() const { return BB; }
|
|
|
|
iterator begin() { return Children.begin(); }
|
|
iterator end() { return Children.end(); }
|
|
|
|
const_iterator begin() const { return Children.begin(); }
|
|
const_iterator end() const { return Children.end(); }
|
|
|
|
bool dominates(const Node *N) const {
|
|
return DFSin <= N->DFSin && DFSout >= N->DFSout;
|
|
}
|
|
|
|
bool DominatedBy(const Node *N) const {
|
|
return N->dominates(this);
|
|
}
|
|
|
|
/// Sorts by the number of descendants. With this, you can iterate
|
|
/// through a sorted list and the first matching entry is the most
|
|
/// specific match for your basic block. The order provided is stable;
|
|
/// DomTreeDFS::Nodes with the same number of descendants are sorted by
|
|
/// DFS in number.
|
|
bool operator<(const Node &N) const {
|
|
unsigned spread = DFSout - DFSin;
|
|
unsigned N_spread = N.DFSout - N.DFSin;
|
|
if (spread == N_spread) return DFSin < N.DFSin;
|
|
return spread < N_spread;
|
|
}
|
|
bool operator>(const Node &N) const { return N < *this; }
|
|
|
|
private:
|
|
unsigned DFSin, DFSout;
|
|
BasicBlock *BB;
|
|
|
|
std::vector<Node *> Children;
|
|
};
|
|
|
|
// XXX: this may be slow. Instead of using "new" for each node, consider
|
|
// putting them in a vector to keep them contiguous.
|
|
explicit DomTreeDFS(DominatorTree *DT) {
|
|
std::stack<std::pair<Node *, DomTreeNode *> > S;
|
|
|
|
Entry = new Node;
|
|
Entry->BB = DT->getRootNode()->getBlock();
|
|
S.push(std::make_pair(Entry, DT->getRootNode()));
|
|
|
|
NodeMap[Entry->BB] = Entry;
|
|
|
|
while (!S.empty()) {
|
|
std::pair<Node *, DomTreeNode *> &Pair = S.top();
|
|
Node *N = Pair.first;
|
|
DomTreeNode *DTNode = Pair.second;
|
|
S.pop();
|
|
|
|
for (DomTreeNode::iterator I = DTNode->begin(), E = DTNode->end();
|
|
I != E; ++I) {
|
|
Node *NewNode = new Node;
|
|
NewNode->BB = (*I)->getBlock();
|
|
N->Children.push_back(NewNode);
|
|
S.push(std::make_pair(NewNode, *I));
|
|
|
|
NodeMap[NewNode->BB] = NewNode;
|
|
}
|
|
}
|
|
|
|
renumber();
|
|
|
|
#ifndef NDEBUG
|
|
DEBUG(dump());
|
|
#endif
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
virtual
|
|
#endif
|
|
~DomTreeDFS() {
|
|
std::stack<Node *> S;
|
|
|
|
S.push(Entry);
|
|
while (!S.empty()) {
|
|
Node *N = S.top(); S.pop();
|
|
|
|
for (Node::iterator I = N->begin(), E = N->end(); I != E; ++I)
|
|
S.push(*I);
|
|
|
|
delete N;
|
|
}
|
|
}
|
|
|
|
/// getRootNode - This returns the entry node for the CFG of the function.
|
|
Node *getRootNode() const { return Entry; }
|
|
|
|
/// getNodeForBlock - return the node for the specified basic block.
|
|
Node *getNodeForBlock(BasicBlock *BB) const {
|
|
if (!NodeMap.count(BB)) return 0;
|
|
return const_cast<DomTreeDFS*>(this)->NodeMap[BB];
|
|
}
|
|
|
|
/// dominates - returns true if the basic block for I1 dominates that of
|
|
/// the basic block for I2. If the instructions belong to the same basic
|
|
/// block, the instruction first instruction sequentially in the block is
|
|
/// considered dominating.
|
|
bool dominates(Instruction *I1, Instruction *I2) {
|
|
BasicBlock *BB1 = I1->getParent(),
|
|
*BB2 = I2->getParent();
|
|
if (BB1 == BB2) {
|
|
if (isa<TerminatorInst>(I1)) return false;
|
|
if (isa<TerminatorInst>(I2)) return true;
|
|
if ( isa<PHINode>(I1) && !isa<PHINode>(I2)) return true;
|
|
if (!isa<PHINode>(I1) && isa<PHINode>(I2)) return false;
|
|
|
|
for (BasicBlock::const_iterator I = BB2->begin(), E = BB2->end();
|
|
I != E; ++I) {
|
|
if (&*I == I1) return true;
|
|
else if (&*I == I2) return false;
|
|
}
|
|
assert(!"Instructions not found in parent BasicBlock?");
|
|
} else {
|
|
Node *Node1 = getNodeForBlock(BB1),
|
|
*Node2 = getNodeForBlock(BB2);
|
|
return Node1 && Node2 && Node1->dominates(Node2);
|
|
}
|
|
}
|
|
|
|
private:
|
|
/// renumber - calculates the depth first search numberings and applies
|
|
/// them onto the nodes.
|
|
void renumber() {
|
|
std::stack<std::pair<Node *, Node::iterator> > S;
|
|
unsigned n = 0;
|
|
|
|
Entry->DFSin = ++n;
|
|
S.push(std::make_pair(Entry, Entry->begin()));
|
|
|
|
while (!S.empty()) {
|
|
std::pair<Node *, Node::iterator> &Pair = S.top();
|
|
Node *N = Pair.first;
|
|
Node::iterator &I = Pair.second;
|
|
|
|
if (I == N->end()) {
|
|
N->DFSout = ++n;
|
|
S.pop();
|
|
} else {
|
|
Node *Next = *I++;
|
|
Next->DFSin = ++n;
|
|
S.push(std::make_pair(Next, Next->begin()));
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
virtual void dump() const {
|
|
dump(*cerr.stream());
|
|
}
|
|
|
|
void dump(std::ostream &os) const {
|
|
os << "Predicate simplifier DomTreeDFS: \n";
|
|
dump(Entry, 0, os);
|
|
os << "\n\n";
|
|
}
|
|
|
|
void dump(Node *N, int depth, std::ostream &os) const {
|
|
++depth;
|
|
for (int i = 0; i < depth; ++i) { os << " "; }
|
|
os << "[" << depth << "] ";
|
|
|
|
os << N->getBlock()->getName() << " (" << N->getDFSNumIn()
|
|
<< ", " << N->getDFSNumOut() << ")\n";
|
|
|
|
for (Node::iterator I = N->begin(), E = N->end(); I != E; ++I)
|
|
dump(*I, depth, os);
|
|
}
|
|
#endif
|
|
|
|
Node *Entry;
|
|
std::map<BasicBlock *, Node *> NodeMap;
|
|
};
|
|
|
|
// 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 -- SGT 14
|
|
// 0 1 1 1 1 -- SGE 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 -- SLT 22
|
|
// 1 0 1 1 1 -- SLE 23
|
|
// 1 1 0 1 0 -- UGT 26
|
|
// 1 1 0 1 1 -- UGE 27
|
|
// 1 1 1 0 0 -- ULT 28
|
|
// 1 1 1 0 1 -- ULE 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,
|
|
ULT = SLT_BIT | SGT_BIT | ULT_BIT,
|
|
UGT = SLT_BIT | SGT_BIT | UGT_BIT,
|
|
SLT = SLT_BIT | ULT_BIT | UGT_BIT,
|
|
SGT = SGT_BIT | ULT_BIT | UGT_BIT,
|
|
SLE = SLT | EQ_BIT,
|
|
SGE = SGT | EQ_BIT,
|
|
ULE = ULT | EQ_BIT,
|
|
UGE = UGT | EQ_BIT
|
|
};
|
|
|
|
/// validPredicate - determines whether a given value is actually a lattice
|
|
/// value. Only used in assertions or debugging.
|
|
static bool validPredicate(LatticeVal LV) {
|
|
switch (LV) {
|
|
case GT: case GE: case LT: case LE: case NE:
|
|
case SGTULT: case SGT: case SGEULE:
|
|
case SLTUGT: case SLT: case SLEUGE:
|
|
case ULT: case UGT:
|
|
case SLE: case SGE: case ULE: case UGE:
|
|
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;
|
|
}
|
|
|
|
/// ValueNumbering stores the scope-specific value numbers for a given Value.
|
|
class VISIBILITY_HIDDEN ValueNumbering {
|
|
|
|
/// VNPair is a tuple of {Value, index number, DomTreeDFS::Node}. It
|
|
/// includes the comparison operators necessary to allow you to store it
|
|
/// in a sorted vector.
|
|
class VISIBILITY_HIDDEN VNPair {
|
|
public:
|
|
Value *V;
|
|
unsigned index;
|
|
DomTreeDFS::Node *Subtree;
|
|
|
|
VNPair(Value *V, unsigned index, DomTreeDFS::Node *Subtree)
|
|
: V(V), index(index), Subtree(Subtree) {}
|
|
|
|
bool operator==(const VNPair &RHS) const {
|
|
return V == RHS.V && Subtree == RHS.Subtree;
|
|
}
|
|
|
|
bool operator<(const VNPair &RHS) const {
|
|
if (V != RHS.V) return V < RHS.V;
|
|
return *Subtree < *RHS.Subtree;
|
|
}
|
|
|
|
bool operator<(Value *RHS) const {
|
|
return V < RHS;
|
|
}
|
|
|
|
bool operator>(Value *RHS) const {
|
|
return V > RHS;
|
|
}
|
|
|
|
friend bool operator<(Value *RHS, const VNPair &pair) {
|
|
return pair.operator>(RHS);
|
|
}
|
|
};
|
|
|
|
typedef std::vector<VNPair> VNMapType;
|
|
VNMapType VNMap;
|
|
|
|
/// The canonical choice for value number at index.
|
|
std::vector<Value *> Values;
|
|
|
|
DomTreeDFS *DTDFS;
|
|
|
|
public:
|
|
#ifndef NDEBUG
|
|
virtual ~ValueNumbering() {}
|
|
virtual void dump() {
|
|
dump(*cerr.stream());
|
|
}
|
|
|
|
void dump(std::ostream &os) {
|
|
for (unsigned i = 1; i <= Values.size(); ++i) {
|
|
os << i << " = ";
|
|
WriteAsOperand(os, Values[i-1]);
|
|
os << " {";
|
|
for (unsigned j = 0; j < VNMap.size(); ++j) {
|
|
if (VNMap[j].index == i) {
|
|
WriteAsOperand(os, VNMap[j].V);
|
|
os << " (" << VNMap[j].Subtree->getDFSNumIn() << ") ";
|
|
}
|
|
}
|
|
os << "}\n";
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// compare - returns true if V1 is a better canonical value than V2.
|
|
bool compare(Value *V1, Value *V2) const {
|
|
if (isa<Constant>(V1))
|
|
return !isa<Constant>(V2);
|
|
else if (isa<Constant>(V2))
|
|
return false;
|
|
else if (isa<Argument>(V1))
|
|
return !isa<Argument>(V2);
|
|
else if (isa<Argument>(V2))
|
|
return false;
|
|
|
|
Instruction *I1 = dyn_cast<Instruction>(V1);
|
|
Instruction *I2 = dyn_cast<Instruction>(V2);
|
|
|
|
if (!I1 || !I2)
|
|
return V1->getNumUses() < V2->getNumUses();
|
|
|
|
return DTDFS->dominates(I1, I2);
|
|
}
|
|
|
|
ValueNumbering(DomTreeDFS *DTDFS) : DTDFS(DTDFS) {}
|
|
|
|
/// valueNumber - finds the value number for V under the Subtree. If
|
|
/// there is no value number, returns zero.
|
|
unsigned valueNumber(Value *V, DomTreeDFS::Node *Subtree) {
|
|
if (!(isa<Constant>(V) || isa<Argument>(V) || isa<Instruction>(V))
|
|
|| V->getType() == Type::VoidTy) return 0;
|
|
|
|
VNMapType::iterator E = VNMap.end();
|
|
VNPair pair(V, 0, Subtree);
|
|
VNMapType::iterator I = std::lower_bound(VNMap.begin(), E, pair);
|
|
while (I != E && I->V == V) {
|
|
if (I->Subtree->dominates(Subtree))
|
|
return I->index;
|
|
++I;
|
|
}
|
|
return 0;
|
|
}
|
|
|
|
/// getOrInsertVN - always returns a value number, creating it if necessary.
|
|
unsigned getOrInsertVN(Value *V, DomTreeDFS::Node *Subtree) {
|
|
if (unsigned n = valueNumber(V, Subtree))
|
|
return n;
|
|
else
|
|
return newVN(V);
|
|
}
|
|
|
|
/// newVN - creates a new value number. Value V must not already have a
|
|
/// value number assigned.
|
|
unsigned newVN(Value *V) {
|
|
assert((isa<Constant>(V) || isa<Argument>(V) || isa<Instruction>(V)) &&
|
|
"Bad Value for value numbering.");
|
|
assert(V->getType() != Type::VoidTy && "Won't value number a void value");
|
|
|
|
Values.push_back(V);
|
|
|
|
VNPair pair = VNPair(V, Values.size(), DTDFS->getRootNode());
|
|
VNMapType::iterator I = std::lower_bound(VNMap.begin(), VNMap.end(), pair);
|
|
assert((I == VNMap.end() || value(I->index) != V) &&
|
|
"Attempt to create a duplicate value number.");
|
|
VNMap.insert(I, pair);
|
|
|
|
return Values.size();
|
|
}
|
|
|
|
/// value - returns the Value associated with a value number.
|
|
Value *value(unsigned index) const {
|
|
assert(index != 0 && "Zero index is reserved for not found.");
|
|
assert(index <= Values.size() && "Index out of range.");
|
|
return Values[index-1];
|
|
}
|
|
|
|
/// canonicalize - return a Value that is equal to V under Subtree.
|
|
Value *canonicalize(Value *V, DomTreeDFS::Node *Subtree) {
|
|
if (isa<Constant>(V)) return V;
|
|
|
|
if (unsigned n = valueNumber(V, Subtree))
|
|
return value(n);
|
|
else
|
|
return V;
|
|
}
|
|
|
|
/// addEquality - adds that value V belongs to the set of equivalent
|
|
/// values defined by value number n under Subtree.
|
|
void addEquality(unsigned n, Value *V, DomTreeDFS::Node *Subtree) {
|
|
assert(canonicalize(value(n), Subtree) == value(n) &&
|
|
"Node's 'canonical' choice isn't best within this subtree.");
|
|
|
|
// 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.
|
|
|
|
std::vector<Value *> ToRepoint(1, V);
|
|
|
|
if (unsigned Conflict = valueNumber(V, Subtree)) {
|
|
for (VNMapType::iterator I = VNMap.begin(), E = VNMap.end();
|
|
I != E; ++I) {
|
|
if (I->index == Conflict && I->Subtree->dominates(Subtree))
|
|
ToRepoint.push_back(I->V);
|
|
}
|
|
}
|
|
|
|
for (std::vector<Value *>::iterator VI = ToRepoint.begin(),
|
|
VE = ToRepoint.end(); VI != VE; ++VI) {
|
|
Value *V = *VI;
|
|
|
|
VNPair pair(V, n, Subtree);
|
|
VNMapType::iterator B = VNMap.begin(), E = VNMap.end();
|
|
VNMapType::iterator I = std::lower_bound(B, E, pair);
|
|
if (I != E && I->V == V && I->Subtree == Subtree)
|
|
I->index = n; // Update best choice
|
|
else
|
|
VNMap.insert(I, pair); // New Value
|
|
|
|
// XXX: we currently don't have to worry about updating values with
|
|
// more specific Subtrees, but we will need to for PHI node support.
|
|
|
|
#ifndef NDEBUG
|
|
Value *V_n = value(n);
|
|
if (isa<Constant>(V) && isa<Constant>(V_n)) {
|
|
assert(V == V_n && "Constant equals different constant?");
|
|
}
|
|
#endif
|
|
}
|
|
}
|
|
|
|
/// remove - removes all references to value V.
|
|
void remove(Value *V) {
|
|
VNMapType::iterator B = VNMap.begin(), E = VNMap.end();
|
|
VNPair pair(V, 0, DTDFS->getRootNode());
|
|
VNMapType::iterator J = std::upper_bound(B, E, pair);
|
|
VNMapType::iterator I = J;
|
|
|
|
while (I != B && (I == E || I->V == V)) --I;
|
|
|
|
VNMap.erase(I, J);
|
|
}
|
|
};
|
|
|
|
/// 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
|
|
/// consistency of the system.
|
|
///
|
|
/// The InequalityGraph class may invalidate Node*s after any mutator call.
|
|
/// @brief The InequalityGraph stores the relationships between values.
|
|
class VISIBILITY_HIDDEN InequalityGraph {
|
|
ValueNumbering &VN;
|
|
DomTreeDFS::Node *TreeRoot;
|
|
|
|
InequalityGraph(); // DO NOT IMPLEMENT
|
|
InequalityGraph(InequalityGraph &); // DO NOT IMPLEMENT
|
|
public:
|
|
InequalityGraph(ValueNumbering &VN, DomTreeDFS::Node *TreeRoot)
|
|
: VN(VN), TreeRoot(TreeRoot) {}
|
|
|
|
class Node;
|
|
|
|
/// 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 and an DomTreeDFS::Node specifying
|
|
/// the root in the dominator tree to which this edge applies.
|
|
class VISIBILITY_HIDDEN Edge {
|
|
public:
|
|
Edge(unsigned T, LatticeVal V, DomTreeDFS::Node *ST)
|
|
: To(T), LV(V), Subtree(ST) {}
|
|
|
|
unsigned To;
|
|
LatticeVal LV;
|
|
DomTreeDFS::Node *Subtree;
|
|
|
|
bool operator<(const Edge &edge) const {
|
|
if (To != edge.To) return To < edge.To;
|
|
return *Subtree < *edge.Subtree;
|
|
}
|
|
|
|
bool operator<(unsigned to) const {
|
|
return To < to;
|
|
}
|
|
|
|
bool operator>(unsigned to) const {
|
|
return To > to;
|
|
}
|
|
|
|
friend bool operator<(unsigned to, const Edge &edge) {
|
|
return edge.operator>(to);
|
|
}
|
|
};
|
|
|
|
/// A single node in the InequalityGraph. This stores the canonical Value
|
|
/// for the node, as well as the relationships with the neighbours.
|
|
///
|
|
/// @brief A single node in the InequalityGraph.
|
|
class VISIBILITY_HIDDEN Node {
|
|
friend class InequalityGraph;
|
|
|
|
typedef SmallVector<Edge, 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;
|
|
|
|
#ifndef NDEBUG
|
|
virtual ~Node() {}
|
|
virtual void dump() const {
|
|
dump(*cerr.stream());
|
|
}
|
|
private:
|
|
void dump(std::ostream &os) const {
|
|
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" };
|
|
for (Node::const_iterator NI = begin(), NE = end(); NI != NE; ++NI) {
|
|
os << names[NI->LV] << " " << NI->To
|
|
<< " (" << NI->Subtree->getDFSNumIn() << "), ";
|
|
}
|
|
}
|
|
public:
|
|
#endif
|
|
|
|
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, DomTreeDFS::Node *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, DomTreeDFS::Node *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;
|
|
}
|
|
|
|
/// update - updates the lattice value for a given node, creating a new
|
|
/// entry if one doesn't exist. The new lattice value must not be
|
|
/// inconsistent with any previously existing value.
|
|
void update(unsigned n, LatticeVal R, DomTreeDFS::Node *Subtree) {
|
|
assert(validPredicate(R) && "Invalid predicate.");
|
|
|
|
Edge edge(n, R, Subtree);
|
|
iterator B = begin(), E = end();
|
|
iterator I = std::lower_bound(B, E, edge);
|
|
|
|
iterator J = I;
|
|
while (J != E && J->To == n) {
|
|
if (Subtree->DominatedBy(J->Subtree))
|
|
break;
|
|
++J;
|
|
}
|
|
|
|
if (J != E && J->To == n) {
|
|
edge.LV = static_cast<LatticeVal>(J->LV & R);
|
|
assert(validPredicate(edge.LV) && "Invalid union of lattice values.");
|
|
|
|
if (edge.LV == J->LV)
|
|
return; // This update adds nothing new.
|
|
}
|
|
|
|
if (I != B) {
|
|
// We also have to tighten any edge beneath our update.
|
|
for (iterator K = I - 1; K->To == n; --K) {
|
|
if (K->Subtree->DominatedBy(Subtree)) {
|
|
LatticeVal LV = static_cast<LatticeVal>(K->LV & edge.LV);
|
|
assert(validPredicate(LV) && "Invalid union of lattice values");
|
|
K->LV = LV;
|
|
}
|
|
if (K == B) break;
|
|
}
|
|
}
|
|
|
|
// Insert new edge at Subtree if it isn't already there.
|
|
if (I == E || I->To != n || Subtree != I->Subtree)
|
|
Relations.insert(I, edge);
|
|
}
|
|
};
|
|
|
|
private:
|
|
|
|
std::vector<Node> Nodes;
|
|
|
|
public:
|
|
/// node - returns the node object at a given value number. The pointer
|
|
/// returned may be invalidated on the next call to node().
|
|
Node *node(unsigned index) {
|
|
assert(VN.value(index)); // This triggers the necessary checks.
|
|
if (Nodes.size() < index) Nodes.resize(index);
|
|
return &Nodes[index-1];
|
|
}
|
|
|
|
/// isRelatedBy - true iff n1 op n2
|
|
bool isRelatedBy(unsigned n1, unsigned n2, DomTreeDFS::Node *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.
|
|
|
|
/// 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, DomTreeDFS::Node *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.");
|
|
|
|
// 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) {
|
|
// Break up the relationship into signed and unsigned comparison parts.
|
|
// If the signed parts of %a op1 %n1 match that of %n1 op2 %n2, and
|
|
// op1 and op2 aren't NE, then add %a op3 %n2. The new relationship
|
|
// should have the EQ_BIT iff it's set for both op1 and op2.
|
|
|
|
unsigned LV1_s = LV1 & (SLT_BIT|SGT_BIT);
|
|
unsigned LV1_u = LV1 & (ULT_BIT|UGT_BIT);
|
|
|
|
for (Node::iterator I = node(n1)->begin(), E = node(n1)->end(); I != E; ++I) {
|
|
if (I->LV != NE && I->To != n2) {
|
|
|
|
DomTreeDFS::Node *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);
|
|
node(n2)->update(I->To, reversePredicate(NewLV), Local_Subtree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
for (Node::iterator I = node(n2)->begin(), E = node(n2)->end(); I != E; ++I) {
|
|
if (I->LV != NE && I->To != n1) {
|
|
DomTreeDFS::Node *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);
|
|
|
|
node(n1)->update(I->To, NewLV, Local_Subtree);
|
|
node(I->To)->update(n1, reversePredicate(NewLV), Local_Subtree);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
node(n1)->update(n2, LV1, Subtree);
|
|
node(n2)->update(n1, reversePredicate(LV1), Subtree);
|
|
}
|
|
|
|
/// remove - removes a node from the graph by removing all references to
|
|
/// and from it.
|
|
void remove(unsigned n) {
|
|
Node *N = node(n);
|
|
for (Node::iterator NI = N->begin(), NE = N->end(); NI != NE; ++NI) {
|
|
Node::iterator Iter = node(NI->To)->find(n, TreeRoot);
|
|
do {
|
|
node(NI->To)->Relations.erase(Iter);
|
|
Iter = node(NI->To)->find(n, TreeRoot);
|
|
} while (Iter != node(NI->To)->end());
|
|
}
|
|
N->Relations.clear();
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
virtual ~InequalityGraph() {}
|
|
virtual void dump() {
|
|
dump(*cerr.stream());
|
|
}
|
|
|
|
void dump(std::ostream &os) {
|
|
for (unsigned i = 1; i <= Nodes.size(); ++i) {
|
|
os << i << " = {";
|
|
node(i)->dump(os);
|
|
os << "}\n";
|
|
}
|
|
}
|
|
#endif
|
|
};
|
|
|
|
class VRPSolver;
|
|
|
|
/// ValueRanges tracks the known integer ranges and anti-ranges of the nodes
|
|
/// in the InequalityGraph.
|
|
class VISIBILITY_HIDDEN ValueRanges {
|
|
ValueNumbering &VN;
|
|
TargetData *TD;
|
|
|
|
class VISIBILITY_HIDDEN ScopedRange {
|
|
typedef std::vector<std::pair<DomTreeDFS::Node *, ConstantRange> >
|
|
RangeListType;
|
|
RangeListType RangeList;
|
|
|
|
static bool swo(const std::pair<DomTreeDFS::Node *, ConstantRange> &LHS,
|
|
const std::pair<DomTreeDFS::Node *, ConstantRange> &RHS) {
|
|
return *LHS.first < *RHS.first;
|
|
}
|
|
|
|
public:
|
|
#ifndef NDEBUG
|
|
virtual ~ScopedRange() {}
|
|
virtual void dump() const {
|
|
dump(*cerr.stream());
|
|
}
|
|
|
|
void dump(std::ostream &os) const {
|
|
os << "{";
|
|
for (const_iterator I = begin(), E = end(); I != E; ++I) {
|
|
os << I->second << " (" << I->first->getDFSNumIn() << "), ";
|
|
}
|
|
os << "}";
|
|
}
|
|
#endif
|
|
|
|
typedef RangeListType::iterator iterator;
|
|
typedef RangeListType::const_iterator const_iterator;
|
|
|
|
iterator begin() { return RangeList.begin(); }
|
|
iterator end() { return RangeList.end(); }
|
|
const_iterator begin() const { return RangeList.begin(); }
|
|
const_iterator end() const { return RangeList.end(); }
|
|
|
|
iterator find(DomTreeDFS::Node *Subtree) {
|
|
static ConstantRange empty(1, false);
|
|
iterator E = end();
|
|
iterator I = std::lower_bound(begin(), E,
|
|
std::make_pair(Subtree, empty), swo);
|
|
|
|
while (I != E && !I->first->dominates(Subtree)) ++I;
|
|
return I;
|
|
}
|
|
|
|
const_iterator find(DomTreeDFS::Node *Subtree) const {
|
|
static const ConstantRange empty(1, false);
|
|
const_iterator E = end();
|
|
const_iterator I = std::lower_bound(begin(), E,
|
|
std::make_pair(Subtree, empty), swo);
|
|
|
|
while (I != E && !I->first->dominates(Subtree)) ++I;
|
|
return I;
|
|
}
|
|
|
|
void update(const ConstantRange &CR, DomTreeDFS::Node *Subtree) {
|
|
assert(!CR.isEmptySet() && "Empty ConstantRange.");
|
|
assert(!CR.isSingleElement() && "Refusing to store single element.");
|
|
|
|
static ConstantRange empty(1, false);
|
|
iterator E = end();
|
|
iterator I =
|
|
std::lower_bound(begin(), E, std::make_pair(Subtree, empty), swo);
|
|
|
|
if (I != end() && I->first == Subtree) {
|
|
ConstantRange CR2 = I->second.maximalIntersectWith(CR);
|
|
assert(!CR2.isEmptySet() && !CR2.isSingleElement() &&
|
|
"Invalid union of ranges.");
|
|
I->second = CR2;
|
|
} else
|
|
RangeList.insert(I, std::make_pair(Subtree, CR));
|
|
}
|
|
};
|
|
|
|
std::vector<ScopedRange> Ranges;
|
|
|
|
void update(unsigned n, const ConstantRange &CR, DomTreeDFS::Node *Subtree){
|
|
if (CR.isFullSet()) return;
|
|
if (Ranges.size() < n) Ranges.resize(n);
|
|
Ranges[n-1].update(CR, Subtree);
|
|
}
|
|
|
|
/// create - Creates a ConstantRange that matches the given LatticeVal
|
|
/// relation with a given integer.
|
|
ConstantRange create(LatticeVal LV, const ConstantRange &CR) {
|
|
assert(!CR.isEmptySet() && "Can't deal with empty set.");
|
|
|
|
if (LV == NE)
|
|
return makeConstantRange(ICmpInst::ICMP_NE, CR);
|
|
|
|
unsigned LV_s = LV & (SGT_BIT|SLT_BIT);
|
|
unsigned LV_u = LV & (UGT_BIT|ULT_BIT);
|
|
bool hasEQ = LV & EQ_BIT;
|
|
|
|
ConstantRange Range(CR.getBitWidth());
|
|
|
|
if (LV_s == SGT_BIT) {
|
|
Range = Range.maximalIntersectWith(makeConstantRange(
|
|
hasEQ ? ICmpInst::ICMP_SGE : ICmpInst::ICMP_SGT, CR));
|
|
} else if (LV_s == SLT_BIT) {
|
|
Range = Range.maximalIntersectWith(makeConstantRange(
|
|
hasEQ ? ICmpInst::ICMP_SLE : ICmpInst::ICMP_SLT, CR));
|
|
}
|
|
|
|
if (LV_u == UGT_BIT) {
|
|
Range = Range.maximalIntersectWith(makeConstantRange(
|
|
hasEQ ? ICmpInst::ICMP_UGE : ICmpInst::ICMP_UGT, CR));
|
|
} else if (LV_u == ULT_BIT) {
|
|
Range = Range.maximalIntersectWith(makeConstantRange(
|
|
hasEQ ? ICmpInst::ICMP_ULE : ICmpInst::ICMP_ULT, CR));
|
|
}
|
|
|
|
return Range;
|
|
}
|
|
|
|
/// makeConstantRange - Creates a ConstantRange representing the set of all
|
|
/// value that match the ICmpInst::Predicate with any of the values in CR.
|
|
ConstantRange makeConstantRange(ICmpInst::Predicate ICmpOpcode,
|
|
const ConstantRange &CR) {
|
|
uint32_t W = CR.getBitWidth();
|
|
switch (ICmpOpcode) {
|
|
default: assert(!"Invalid ICmp opcode to makeConstantRange()");
|
|
case ICmpInst::ICMP_EQ:
|
|
return ConstantRange(CR.getLower(), CR.getUpper());
|
|
case ICmpInst::ICMP_NE:
|
|
if (CR.isSingleElement())
|
|
return ConstantRange(CR.getUpper(), CR.getLower());
|
|
return ConstantRange(W);
|
|
case ICmpInst::ICMP_ULT:
|
|
return ConstantRange(APInt::getMinValue(W), CR.getUnsignedMax());
|
|
case ICmpInst::ICMP_SLT:
|
|
return ConstantRange(APInt::getSignedMinValue(W), CR.getSignedMax());
|
|
case ICmpInst::ICMP_ULE: {
|
|
APInt UMax(CR.getUnsignedMax());
|
|
if (UMax.isMaxValue())
|
|
return ConstantRange(W);
|
|
return ConstantRange(APInt::getMinValue(W), UMax + 1);
|
|
}
|
|
case ICmpInst::ICMP_SLE: {
|
|
APInt SMax(CR.getSignedMax());
|
|
if (SMax.isMaxSignedValue() || (SMax+1).isMaxSignedValue())
|
|
return ConstantRange(W);
|
|
return ConstantRange(APInt::getSignedMinValue(W), SMax + 1);
|
|
}
|
|
case ICmpInst::ICMP_UGT:
|
|
return ConstantRange(CR.getUnsignedMin() + 1, APInt::getNullValue(W));
|
|
case ICmpInst::ICMP_SGT:
|
|
return ConstantRange(CR.getSignedMin() + 1,
|
|
APInt::getSignedMinValue(W));
|
|
case ICmpInst::ICMP_UGE: {
|
|
APInt UMin(CR.getUnsignedMin());
|
|
if (UMin.isMinValue())
|
|
return ConstantRange(W);
|
|
return ConstantRange(UMin, APInt::getNullValue(W));
|
|
}
|
|
case ICmpInst::ICMP_SGE: {
|
|
APInt SMin(CR.getSignedMin());
|
|
if (SMin.isMinSignedValue())
|
|
return ConstantRange(W);
|
|
return ConstantRange(SMin, APInt::getSignedMinValue(W));
|
|
}
|
|
}
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
bool isCanonical(Value *V, DomTreeDFS::Node *Subtree) {
|
|
return V == VN.canonicalize(V, Subtree);
|
|
}
|
|
#endif
|
|
|
|
public:
|
|
|
|
ValueRanges(ValueNumbering &VN, TargetData *TD) : VN(VN), TD(TD) {}
|
|
|
|
#ifndef NDEBUG
|
|
virtual ~ValueRanges() {}
|
|
|
|
virtual void dump() const {
|
|
dump(*cerr.stream());
|
|
}
|
|
|
|
void dump(std::ostream &os) const {
|
|
for (unsigned i = 0, e = Ranges.size(); i != e; ++i) {
|
|
os << (i+1) << " = ";
|
|
Ranges[i].dump(os);
|
|
os << "\n";
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/// range - looks up the ConstantRange associated with a value number.
|
|
ConstantRange range(unsigned n, DomTreeDFS::Node *Subtree) {
|
|
assert(VN.value(n)); // performs range checks
|
|
|
|
if (n <= Ranges.size()) {
|
|
ScopedRange::iterator I = Ranges[n-1].find(Subtree);
|
|
if (I != Ranges[n-1].end()) return I->second;
|
|
}
|
|
|
|
Value *V = VN.value(n);
|
|
ConstantRange CR = range(V);
|
|
return CR;
|
|
}
|
|
|
|
/// range - determine a range from a Value without performing any lookups.
|
|
ConstantRange range(Value *V) const {
|
|
if (ConstantInt *C = dyn_cast<ConstantInt>(V))
|
|
return ConstantRange(C->getValue());
|
|
else if (isa<ConstantPointerNull>(V))
|
|
return ConstantRange(APInt::getNullValue(typeToWidth(V->getType())));
|
|
else
|
|
return typeToWidth(V->getType());
|
|
}
|
|
|
|
// typeToWidth - returns the number of bits necessary to store a value of
|
|
// this type, or zero if unknown.
|
|
uint32_t typeToWidth(const Type *Ty) const {
|
|
if (TD)
|
|
return TD->getTypeSizeInBits(Ty);
|
|
else
|
|
return Ty->getPrimitiveSizeInBits();
|
|
}
|
|
|
|
static bool isRelatedBy(const ConstantRange &CR1, const ConstantRange &CR2,
|
|
LatticeVal LV) {
|
|
switch (LV) {
|
|
default: assert(!"Impossible lattice value!");
|
|
case NE:
|
|
return CR1.maximalIntersectWith(CR2).isEmptySet();
|
|
case ULT:
|
|
return CR1.getUnsignedMax().ult(CR2.getUnsignedMin());
|
|
case ULE:
|
|
return CR1.getUnsignedMax().ule(CR2.getUnsignedMin());
|
|
case UGT:
|
|
return CR1.getUnsignedMin().ugt(CR2.getUnsignedMax());
|
|
case UGE:
|
|
return CR1.getUnsignedMin().uge(CR2.getUnsignedMax());
|
|
case SLT:
|
|
return CR1.getSignedMax().slt(CR2.getSignedMin());
|
|
case SLE:
|
|
return CR1.getSignedMax().sle(CR2.getSignedMin());
|
|
case SGT:
|
|
return CR1.getSignedMin().sgt(CR2.getSignedMax());
|
|
case SGE:
|
|
return CR1.getSignedMin().sge(CR2.getSignedMax());
|
|
case LT:
|
|
return CR1.getUnsignedMax().ult(CR2.getUnsignedMin()) &&
|
|
CR1.getSignedMax().slt(CR2.getUnsignedMin());
|
|
case LE:
|
|
return CR1.getUnsignedMax().ule(CR2.getUnsignedMin()) &&
|
|
CR1.getSignedMax().sle(CR2.getUnsignedMin());
|
|
case GT:
|
|
return CR1.getUnsignedMin().ugt(CR2.getUnsignedMax()) &&
|
|
CR1.getSignedMin().sgt(CR2.getSignedMax());
|
|
case GE:
|
|
return CR1.getUnsignedMin().uge(CR2.getUnsignedMax()) &&
|
|
CR1.getSignedMin().sge(CR2.getSignedMax());
|
|
case SLTUGT:
|
|
return CR1.getSignedMax().slt(CR2.getSignedMin()) &&
|
|
CR1.getUnsignedMin().ugt(CR2.getUnsignedMax());
|
|
case SLEUGE:
|
|
return CR1.getSignedMax().sle(CR2.getSignedMin()) &&
|
|
CR1.getUnsignedMin().uge(CR2.getUnsignedMax());
|
|
case SGTULT:
|
|
return CR1.getSignedMin().sgt(CR2.getSignedMax()) &&
|
|
CR1.getUnsignedMax().ult(CR2.getUnsignedMin());
|
|
case SGEULE:
|
|
return CR1.getSignedMin().sge(CR2.getSignedMax()) &&
|
|
CR1.getUnsignedMax().ule(CR2.getUnsignedMin());
|
|
}
|
|
}
|
|
|
|
bool isRelatedBy(unsigned n1, unsigned n2, DomTreeDFS::Node *Subtree,
|
|
LatticeVal LV) {
|
|
ConstantRange CR1 = range(n1, Subtree);
|
|
ConstantRange CR2 = range(n2, Subtree);
|
|
|
|
// True iff all values in CR1 are LV to all values in CR2.
|
|
return isRelatedBy(CR1, CR2, LV);
|
|
}
|
|
|
|
void addToWorklist(Value *V, Constant *C, ICmpInst::Predicate Pred,
|
|
VRPSolver *VRP);
|
|
void markBlock(VRPSolver *VRP);
|
|
|
|
void mergeInto(Value **I, unsigned n, unsigned New,
|
|
DomTreeDFS::Node *Subtree, VRPSolver *VRP) {
|
|
ConstantRange CR_New = range(New, Subtree);
|
|
ConstantRange Merged = CR_New;
|
|
|
|
for (; n != 0; ++I, --n) {
|
|
unsigned i = VN.valueNumber(*I, Subtree);
|
|
ConstantRange CR_Kill = i ? range(i, Subtree) : range(*I);
|
|
if (CR_Kill.isFullSet()) continue;
|
|
Merged = Merged.maximalIntersectWith(CR_Kill);
|
|
}
|
|
|
|
if (Merged.isFullSet() || Merged == CR_New) return;
|
|
|
|
applyRange(New, Merged, Subtree, VRP);
|
|
}
|
|
|
|
void applyRange(unsigned n, const ConstantRange &CR,
|
|
DomTreeDFS::Node *Subtree, VRPSolver *VRP) {
|
|
ConstantRange Merged = CR.maximalIntersectWith(range(n, Subtree));
|
|
if (Merged.isEmptySet()) {
|
|
markBlock(VRP);
|
|
return;
|
|
}
|
|
|
|
if (const APInt *I = Merged.getSingleElement()) {
|
|
Value *V = VN.value(n); // XXX: redesign worklist.
|
|
const Type *Ty = V->getType();
|
|
if (Ty->isInteger()) {
|
|
addToWorklist(V, ConstantInt::get(*I), ICmpInst::ICMP_EQ, VRP);
|
|
return;
|
|
} else if (const PointerType *PTy = dyn_cast<PointerType>(Ty)) {
|
|
assert(*I == 0 && "Pointer is null but not zero?");
|
|
addToWorklist(V, ConstantPointerNull::get(PTy),
|
|
ICmpInst::ICMP_EQ, VRP);
|
|
return;
|
|
}
|
|
}
|
|
|
|
update(n, Merged, Subtree);
|
|
}
|
|
|
|
void addNotEquals(unsigned n1, unsigned n2, DomTreeDFS::Node *Subtree,
|
|
VRPSolver *VRP) {
|
|
ConstantRange CR1 = range(n1, Subtree);
|
|
ConstantRange CR2 = range(n2, Subtree);
|
|
|
|
uint32_t W = CR1.getBitWidth();
|
|
|
|
if (const APInt *I = CR1.getSingleElement()) {
|
|
if (CR2.isFullSet()) {
|
|
ConstantRange NewCR2(CR1.getUpper(), CR1.getLower());
|
|
applyRange(n2, NewCR2, Subtree, VRP);
|
|
} else if (*I == CR2.getLower()) {
|
|
APInt NewLower(CR2.getLower() + 1),
|
|
NewUpper(CR2.getUpper());
|
|
if (NewLower == NewUpper)
|
|
NewLower = NewUpper = APInt::getMinValue(W);
|
|
|
|
ConstantRange NewCR2(NewLower, NewUpper);
|
|
applyRange(n2, NewCR2, Subtree, VRP);
|
|
} else if (*I == CR2.getUpper() - 1) {
|
|
APInt NewLower(CR2.getLower()),
|
|
NewUpper(CR2.getUpper() - 1);
|
|
if (NewLower == NewUpper)
|
|
NewLower = NewUpper = APInt::getMinValue(W);
|
|
|
|
ConstantRange NewCR2(NewLower, NewUpper);
|
|
applyRange(n2, NewCR2, Subtree, VRP);
|
|
}
|
|
}
|
|
|
|
if (const APInt *I = CR2.getSingleElement()) {
|
|
if (CR1.isFullSet()) {
|
|
ConstantRange NewCR1(CR2.getUpper(), CR2.getLower());
|
|
applyRange(n1, NewCR1, Subtree, VRP);
|
|
} else if (*I == CR1.getLower()) {
|
|
APInt NewLower(CR1.getLower() + 1),
|
|
NewUpper(CR1.getUpper());
|
|
if (NewLower == NewUpper)
|
|
NewLower = NewUpper = APInt::getMinValue(W);
|
|
|
|
ConstantRange NewCR1(NewLower, NewUpper);
|
|
applyRange(n1, NewCR1, Subtree, VRP);
|
|
} else if (*I == CR1.getUpper() - 1) {
|
|
APInt NewLower(CR1.getLower()),
|
|
NewUpper(CR1.getUpper() - 1);
|
|
if (NewLower == NewUpper)
|
|
NewLower = NewUpper = APInt::getMinValue(W);
|
|
|
|
ConstantRange NewCR1(NewLower, NewUpper);
|
|
applyRange(n1, NewCR1, Subtree, VRP);
|
|
}
|
|
}
|
|
}
|
|
|
|
void addInequality(unsigned n1, unsigned n2, DomTreeDFS::Node *Subtree,
|
|
LatticeVal LV, VRPSolver *VRP) {
|
|
assert(!isRelatedBy(n1, n2, Subtree, LV) && "Asked to do useless work.");
|
|
|
|
if (LV == NE) {
|
|
addNotEquals(n1, n2, Subtree, VRP);
|
|
return;
|
|
}
|
|
|
|
ConstantRange CR1 = range(n1, Subtree);
|
|
ConstantRange CR2 = range(n2, Subtree);
|
|
|
|
if (!CR1.isSingleElement()) {
|
|
ConstantRange NewCR1 = CR1.maximalIntersectWith(create(LV, CR2));
|
|
if (NewCR1 != CR1)
|
|
applyRange(n1, NewCR1, Subtree, VRP);
|
|
}
|
|
|
|
if (!CR2.isSingleElement()) {
|
|
ConstantRange NewCR2 = CR2.maximalIntersectWith(
|
|
create(reversePredicate(LV), CR1));
|
|
if (NewCR2 != CR2)
|
|
applyRange(n2, NewCR2, Subtree, VRP);
|
|
}
|
|
}
|
|
};
|
|
|
|
/// 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;
|
|
|
|
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);
|
|
|
|
if (I == E || *I != BB) DeadBlocks.insert(I, BB);
|
|
}
|
|
|
|
/// 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);
|
|
|
|
return I != E && *I == BB;
|
|
}
|
|
|
|
/// 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;
|
|
|
|
DOUT << "unreachable block: " << BB->getName() << "\n";
|
|
|
|
for (succ_iterator SI = succ_begin(BB), SE = succ_end(BB);
|
|
SI != SE; ++SI) {
|
|
BasicBlock *Succ = *SI;
|
|
Succ->removePredecessor(BB);
|
|
}
|
|
|
|
TerminatorInst *TI = BB->getTerminator();
|
|
TI->replaceAllUsesWith(UndefValue::get(TI->getType()));
|
|
TI->eraseFromParent();
|
|
new UnreachableInst(BB);
|
|
++NumBlocks;
|
|
modified = true;
|
|
}
|
|
DeadBlocks.clear();
|
|
return modified;
|
|
}
|
|
};
|
|
|
|
/// VRPSolver keeps track of how changes to one variable affect other
|
|
/// variables, and forwards changes along to the InequalityGraph. It
|
|
/// also maintains the correct choice for "canonical" in the IG.
|
|
/// @brief VRPSolver calculates inferences from a new relationship.
|
|
class VISIBILITY_HIDDEN VRPSolver {
|
|
private:
|
|
friend class ValueRanges;
|
|
|
|
struct Operation {
|
|
Value *LHS, *RHS;
|
|
ICmpInst::Predicate Op;
|
|
|
|
BasicBlock *ContextBB; // XXX use a DomTreeDFS::Node instead
|
|
Instruction *ContextInst;
|
|
};
|
|
std::deque<Operation> WorkList;
|
|
|
|
ValueNumbering &VN;
|
|
InequalityGraph &IG;
|
|
UnreachableBlocks &UB;
|
|
ValueRanges &VR;
|
|
DomTreeDFS *DTDFS;
|
|
DomTreeDFS::Node *Top;
|
|
BasicBlock *TopBB;
|
|
Instruction *TopInst;
|
|
bool &modified;
|
|
|
|
typedef InequalityGraph::Node Node;
|
|
|
|
// below - true if the Instruction is dominated by the current context
|
|
// block or instruction
|
|
bool below(Instruction *I) {
|
|
BasicBlock *BB = I->getParent();
|
|
if (TopInst && TopInst->getParent() == BB) {
|
|
if (isa<TerminatorInst>(TopInst)) return false;
|
|
if (isa<TerminatorInst>(I)) return true;
|
|
if ( isa<PHINode>(TopInst) && !isa<PHINode>(I)) return true;
|
|
if (!isa<PHINode>(TopInst) && isa<PHINode>(I)) return false;
|
|
|
|
for (BasicBlock::const_iterator Iter = BB->begin(), E = BB->end();
|
|
Iter != E; ++Iter) {
|
|
if (&*Iter == TopInst) return true;
|
|
else if (&*Iter == I) return false;
|
|
}
|
|
assert(!"Instructions not found in parent BasicBlock?");
|
|
} else {
|
|
DomTreeDFS::Node *Node = DTDFS->getNodeForBlock(BB);
|
|
if (!Node) return false;
|
|
return Top->dominates(Node);
|
|
}
|
|
}
|
|
|
|
// aboveOrBelow - true if the Instruction either dominates or is dominated
|
|
// by the current context block or instruction
|
|
bool aboveOrBelow(Instruction *I) {
|
|
BasicBlock *BB = I->getParent();
|
|
DomTreeDFS::Node *Node = DTDFS->getNodeForBlock(BB);
|
|
if (!Node) return false;
|
|
|
|
return Top == Node || Top->dominates(Node) || Node->dominates(Top);
|
|
}
|
|
|
|
bool makeEqual(Value *V1, Value *V2) {
|
|
DOUT << "makeEqual(" << *V1 << ", " << *V2 << ")\n";
|
|
DOUT << "context is ";
|
|
if (TopInst) DOUT << "I: " << *TopInst << "\n";
|
|
else DOUT << "BB: " << TopBB->getName()
|
|
<< "(" << Top->getDFSNumIn() << ")\n";
|
|
|
|
assert(V1->getType() == V2->getType() &&
|
|
"Can't make two values with different types equal.");
|
|
|
|
if (V1 == V2) return true;
|
|
|
|
if (isa<Constant>(V1) && isa<Constant>(V2))
|
|
return false;
|
|
|
|
unsigned n1 = VN.valueNumber(V1, Top), n2 = VN.valueNumber(V2, Top);
|
|
|
|
if (n1 && n2) {
|
|
if (n1 == n2) return true;
|
|
if (IG.isRelatedBy(n1, n2, Top, NE)) return false;
|
|
}
|
|
|
|
if (n1) assert(V1 == VN.value(n1) && "Value isn't canonical.");
|
|
if (n2) assert(V2 == VN.value(n2) && "Value isn't canonical.");
|
|
|
|
assert(!VN.compare(V2, V1) && "Please order parameters to makeEqual.");
|
|
|
|
assert(!isa<Constant>(V2) && "Tried to remove a constant.");
|
|
|
|
SetVector<unsigned> Remove;
|
|
if (n2) Remove.insert(n2);
|
|
|
|
if (n1 && n2) {
|
|
// Suppose we're being told that %x == %y, and %x <= %z and %y >= %z.
|
|
// We can't just merge %x and %y because the relationship with %z would
|
|
// be EQ and that's invalid. What we're doing is looking for any nodes
|
|
// %z such that %x <= %z and %y >= %z, and vice versa.
|
|
|
|
Node::iterator end = IG.node(n2)->end();
|
|
|
|
// Find the intersection between N1 and N2 which is dominated by
|
|
// Top. If we find %x where N1 <= %x <= N2 (or >=) then add %x to
|
|
// Remove.
|
|
for (Node::iterator I = IG.node(n1)->begin(), E = IG.node(n1)->end();
|
|
I != E; ++I) {
|
|
if (!(I->LV & EQ_BIT) || !Top->DominatedBy(I->Subtree)) continue;
|
|
|
|
unsigned ILV_s = I->LV & (SLT_BIT|SGT_BIT);
|
|
unsigned ILV_u = I->LV & (ULT_BIT|UGT_BIT);
|
|
Node::iterator NI = IG.node(n2)->find(I->To, Top);
|
|
if (NI != end) {
|
|
LatticeVal NILV = reversePredicate(NI->LV);
|
|
unsigned NILV_s = NILV & (SLT_BIT|SGT_BIT);
|
|
unsigned NILV_u = NILV & (ULT_BIT|UGT_BIT);
|
|
|
|
if ((ILV_s != (SLT_BIT|SGT_BIT) && ILV_s == NILV_s) ||
|
|
(ILV_u != (ULT_BIT|UGT_BIT) && ILV_u == NILV_u))
|
|
Remove.insert(I->To);
|
|
}
|
|
}
|
|
|
|
// See if one of the nodes about to be removed is actually a better
|
|
// canonical choice than n1.
|
|
unsigned orig_n1 = n1;
|
|
SetVector<unsigned>::iterator DontRemove = Remove.end();
|
|
for (SetVector<unsigned>::iterator I = Remove.begin()+1 /* skip n2 */,
|
|
E = Remove.end(); I != E; ++I) {
|
|
unsigned n = *I;
|
|
Value *V = VN.value(n);
|
|
if (VN.compare(V, V1)) {
|
|
V1 = V;
|
|
n1 = n;
|
|
DontRemove = I;
|
|
}
|
|
}
|
|
if (DontRemove != Remove.end()) {
|
|
unsigned n = *DontRemove;
|
|
Remove.remove(n);
|
|
Remove.insert(orig_n1);
|
|
}
|
|
}
|
|
|
|
// We'd like to allow makeEqual on two values to perform a simple
|
|
// substitution without every creating nodes in the IG whenever possible.
|
|
//
|
|
// The first iteration through this loop operates on V2 before going
|
|
// through the Remove list and operating on those too. If all of the
|
|
// iterations performed simple replacements then we exit early.
|
|
bool mergeIGNode = false;
|
|
unsigned i = 0;
|
|
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
|
if (i) R = VN.value(Remove[i]); // skip n2.
|
|
|
|
// Try to replace the whole instruction. If we can, we're done.
|
|
Instruction *I2 = dyn_cast<Instruction>(R);
|
|
if (I2 && below(I2)) {
|
|
std::vector<Instruction *> ToNotify;
|
|
for (Value::use_iterator UI = R->use_begin(), UE = R->use_end();
|
|
UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser()))
|
|
ToNotify.push_back(I);
|
|
}
|
|
|
|
DOUT << "Simply removing " << *I2
|
|
<< ", replacing with " << *V1 << "\n";
|
|
I2->replaceAllUsesWith(V1);
|
|
// leave it dead; it'll get erased later.
|
|
++NumInstruction;
|
|
modified = true;
|
|
|
|
for (std::vector<Instruction *>::iterator II = ToNotify.begin(),
|
|
IE = ToNotify.end(); II != IE; ++II) {
|
|
opsToDef(*II);
|
|
}
|
|
|
|
continue;
|
|
}
|
|
|
|
// Otherwise, replace all dominated uses.
|
|
for (Value::use_iterator UI = R->use_begin(), UE = R->use_end();
|
|
UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
|
if (below(I)) {
|
|
TheUse.set(V1);
|
|
modified = true;
|
|
++NumVarsReplaced;
|
|
opsToDef(I);
|
|
}
|
|
}
|
|
}
|
|
|
|
// If that killed the instruction, stop here.
|
|
if (I2 && isInstructionTriviallyDead(I2)) {
|
|
DOUT << "Killed all uses of " << *I2
|
|
<< ", replacing with " << *V1 << "\n";
|
|
continue;
|
|
}
|
|
|
|
// If we make it to here, then we will need to create a node for N1.
|
|
// Otherwise, we can skip out early!
|
|
mergeIGNode = true;
|
|
}
|
|
|
|
if (!isa<Constant>(V1)) {
|
|
if (Remove.empty()) {
|
|
VR.mergeInto(&V2, 1, VN.getOrInsertVN(V1, Top), Top, this);
|
|
} else {
|
|
std::vector<Value*> RemoveVals;
|
|
RemoveVals.reserve(Remove.size());
|
|
|
|
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
|
E = Remove.end(); I != E; ++I) {
|
|
Value *V = VN.value(*I);
|
|
if (!V->use_empty())
|
|
RemoveVals.push_back(V);
|
|
}
|
|
VR.mergeInto(&RemoveVals[0], RemoveVals.size(),
|
|
VN.getOrInsertVN(V1, Top), Top, this);
|
|
}
|
|
}
|
|
|
|
if (mergeIGNode) {
|
|
// Create N1.
|
|
if (!n1) n1 = VN.getOrInsertVN(V1, Top);
|
|
|
|
// Migrate relationships from removed nodes to N1.
|
|
for (SetVector<unsigned>::iterator I = Remove.begin(), E = Remove.end();
|
|
I != E; ++I) {
|
|
unsigned n = *I;
|
|
for (Node::iterator NI = IG.node(n)->begin(), NE = IG.node(n)->end();
|
|
NI != NE; ++NI) {
|
|
if (NI->Subtree->DominatedBy(Top)) {
|
|
if (NI->To == n1) {
|
|
assert((NI->LV & EQ_BIT) && "Node inequal to itself.");
|
|
continue;
|
|
}
|
|
if (Remove.count(NI->To))
|
|
continue;
|
|
|
|
IG.node(NI->To)->update(n1, reversePredicate(NI->LV), Top);
|
|
IG.node(n1)->update(NI->To, NI->LV, Top);
|
|
}
|
|
}
|
|
}
|
|
|
|
// Point V2 (and all items in Remove) to N1.
|
|
if (!n2)
|
|
VN.addEquality(n1, V2, Top);
|
|
else {
|
|
for (SetVector<unsigned>::iterator I = Remove.begin(),
|
|
E = Remove.end(); I != E; ++I) {
|
|
VN.addEquality(n1, VN.value(*I), Top);
|
|
}
|
|
}
|
|
|
|
// If !Remove.empty() then V2 = Remove[0]->getValue().
|
|
// Even when Remove is empty, we still want to process V2.
|
|
i = 0;
|
|
for (Value *R = V2; i == 0 || i < Remove.size(); ++i) {
|
|
if (i) R = VN.value(Remove[i]); // skip n2.
|
|
|
|
if (Instruction *I2 = dyn_cast<Instruction>(R)) {
|
|
if (aboveOrBelow(I2))
|
|
defToOps(I2);
|
|
}
|
|
for (Value::use_iterator UI = V2->use_begin(), UE = V2->use_end();
|
|
UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
|
if (aboveOrBelow(I))
|
|
opsToDef(I);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// re-opsToDef all dominated users of V1.
|
|
if (Instruction *I = dyn_cast<Instruction>(V1)) {
|
|
for (Value::use_iterator UI = I->use_begin(), UE = I->use_end();
|
|
UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
Value *V = TheUse.getUser();
|
|
if (!V->use_empty()) {
|
|
if (Instruction *Inst = dyn_cast<Instruction>(V)) {
|
|
if (aboveOrBelow(Inst))
|
|
opsToDef(Inst);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return true;
|
|
}
|
|
|
|
/// cmpInstToLattice - converts an CmpInst::Predicate to lattice value
|
|
/// Requires that the lattice value be valid; does not accept ICMP_EQ.
|
|
static LatticeVal cmpInstToLattice(ICmpInst::Predicate Pred) {
|
|
switch (Pred) {
|
|
case ICmpInst::ICMP_EQ:
|
|
assert(!"No matching lattice value.");
|
|
return static_cast<LatticeVal>(EQ_BIT);
|
|
default:
|
|
assert(!"Invalid 'icmp' predicate.");
|
|
case ICmpInst::ICMP_NE:
|
|
return NE;
|
|
case ICmpInst::ICMP_UGT:
|
|
return UGT;
|
|
case ICmpInst::ICMP_UGE:
|
|
return UGE;
|
|
case ICmpInst::ICMP_ULT:
|
|
return ULT;
|
|
case ICmpInst::ICMP_ULE:
|
|
return ULE;
|
|
case ICmpInst::ICMP_SGT:
|
|
return SGT;
|
|
case ICmpInst::ICMP_SGE:
|
|
return SGE;
|
|
case ICmpInst::ICMP_SLT:
|
|
return SLT;
|
|
case ICmpInst::ICMP_SLE:
|
|
return SLE;
|
|
}
|
|
}
|
|
|
|
public:
|
|
VRPSolver(ValueNumbering &VN, InequalityGraph &IG, UnreachableBlocks &UB,
|
|
ValueRanges &VR, DomTreeDFS *DTDFS, bool &modified,
|
|
BasicBlock *TopBB)
|
|
: VN(VN),
|
|
IG(IG),
|
|
UB(UB),
|
|
VR(VR),
|
|
DTDFS(DTDFS),
|
|
Top(DTDFS->getNodeForBlock(TopBB)),
|
|
TopBB(TopBB),
|
|
TopInst(NULL),
|
|
modified(modified)
|
|
{
|
|
assert(Top && "VRPSolver created for unreachable basic block.");
|
|
}
|
|
|
|
VRPSolver(ValueNumbering &VN, InequalityGraph &IG, UnreachableBlocks &UB,
|
|
ValueRanges &VR, DomTreeDFS *DTDFS, bool &modified,
|
|
Instruction *TopInst)
|
|
: VN(VN),
|
|
IG(IG),
|
|
UB(UB),
|
|
VR(VR),
|
|
DTDFS(DTDFS),
|
|
Top(DTDFS->getNodeForBlock(TopInst->getParent())),
|
|
TopBB(TopInst->getParent()),
|
|
TopInst(TopInst),
|
|
modified(modified)
|
|
{
|
|
assert(Top && "VRPSolver created for unreachable basic block.");
|
|
assert(Top->getBlock() == TopInst->getParent() && "Context mismatch.");
|
|
}
|
|
|
|
bool isRelatedBy(Value *V1, Value *V2, ICmpInst::Predicate Pred) const {
|
|
if (Constant *C1 = dyn_cast<Constant>(V1))
|
|
if (Constant *C2 = dyn_cast<Constant>(V2))
|
|
return ConstantExpr::getCompare(Pred, C1, C2) ==
|
|
ConstantInt::getTrue();
|
|
|
|
unsigned n1 = VN.valueNumber(V1, Top);
|
|
unsigned n2 = VN.valueNumber(V2, Top);
|
|
|
|
if (n1 && n2) {
|
|
if (n1 == n2) return Pred == ICmpInst::ICMP_EQ ||
|
|
Pred == ICmpInst::ICMP_ULE ||
|
|
Pred == ICmpInst::ICMP_UGE ||
|
|
Pred == ICmpInst::ICMP_SLE ||
|
|
Pred == ICmpInst::ICMP_SGE;
|
|
if (Pred == ICmpInst::ICMP_EQ) return false;
|
|
if (IG.isRelatedBy(n1, n2, Top, cmpInstToLattice(Pred))) return true;
|
|
if (VR.isRelatedBy(n1, n2, Top, cmpInstToLattice(Pred))) return true;
|
|
}
|
|
|
|
if ((n1 && !n2 && isa<Constant>(V2)) ||
|
|
(n2 && !n1 && isa<Constant>(V1))) {
|
|
ConstantRange CR1 = n1 ? VR.range(n1, Top) : VR.range(V1);
|
|
ConstantRange CR2 = n2 ? VR.range(n2, Top) : VR.range(V2);
|
|
|
|
if (Pred == ICmpInst::ICMP_EQ)
|
|
return CR1.isSingleElement() &&
|
|
CR1.getSingleElement() == CR2.getSingleElement();
|
|
|
|
return VR.isRelatedBy(CR1, CR2, cmpInstToLattice(Pred));
|
|
}
|
|
if (Pred == ICmpInst::ICMP_EQ) return V1 == V2;
|
|
return false;
|
|
}
|
|
|
|
/// add - adds a new property to the work queue
|
|
void add(Value *V1, Value *V2, ICmpInst::Predicate Pred,
|
|
Instruction *I = NULL) {
|
|
DOUT << "adding " << *V1 << " " << Pred << " " << *V2;
|
|
if (I) DOUT << " context: " << *I;
|
|
else DOUT << " default context (" << Top->getDFSNumIn() << ")";
|
|
DOUT << "\n";
|
|
|
|
assert(V1->getType() == V2->getType() &&
|
|
"Can't relate two values with different types.");
|
|
|
|
WorkList.push_back(Operation());
|
|
Operation &O = WorkList.back();
|
|
O.LHS = V1, O.RHS = V2, O.Op = Pred, O.ContextInst = I;
|
|
O.ContextBB = I ? I->getParent() : TopBB;
|
|
}
|
|
|
|
/// defToOps - Given an instruction definition that we've learned something
|
|
/// new about, find any new relationships between its operands.
|
|
void defToOps(Instruction *I) {
|
|
Instruction *NewContext = below(I) ? I : TopInst;
|
|
Value *Canonical = VN.canonicalize(I, Top);
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(I)) {
|
|
const Type *Ty = BO->getType();
|
|
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
|
|
|
Value *Op0 = VN.canonicalize(BO->getOperand(0), Top);
|
|
Value *Op1 = VN.canonicalize(BO->getOperand(1), Top);
|
|
|
|
// TODO: "and i32 -1, %x" EQ %y then %x EQ %y.
|
|
|
|
switch (BO->getOpcode()) {
|
|
case Instruction::And: {
|
|
// "and i32 %a, %b" EQ -1 then %a EQ -1 and %b EQ -1
|
|
ConstantInt *CI = ConstantInt::getAllOnesValue(Ty);
|
|
if (Canonical == CI) {
|
|
add(CI, Op0, ICmpInst::ICMP_EQ, NewContext);
|
|
add(CI, Op1, ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
} break;
|
|
case Instruction::Or: {
|
|
// "or i32 %a, %b" EQ 0 then %a EQ 0 and %b EQ 0
|
|
Constant *Zero = Constant::getNullValue(Ty);
|
|
if (Canonical == Zero) {
|
|
add(Zero, Op0, ICmpInst::ICMP_EQ, NewContext);
|
|
add(Zero, Op1, ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
} break;
|
|
case Instruction::Xor: {
|
|
// "xor i32 %c, %a" EQ %b then %a EQ %c ^ %b
|
|
// "xor i32 %c, %a" EQ %c then %a EQ 0
|
|
// "xor i32 %c, %a" NE %c then %a NE 0
|
|
// Repeat the above, with order of operands reversed.
|
|
Value *LHS = Op0;
|
|
Value *RHS = Op1;
|
|
if (!isa<Constant>(LHS)) std::swap(LHS, RHS);
|
|
|
|
if (ConstantInt *CI = dyn_cast<ConstantInt>(Canonical)) {
|
|
if (ConstantInt *Arg = dyn_cast<ConstantInt>(LHS)) {
|
|
add(RHS, ConstantInt::get(CI->getValue() ^ Arg->getValue()),
|
|
ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
}
|
|
if (Canonical == LHS) {
|
|
if (isa<ConstantInt>(Canonical))
|
|
add(RHS, Constant::getNullValue(Ty), ICmpInst::ICMP_EQ,
|
|
NewContext);
|
|
} else if (isRelatedBy(LHS, Canonical, ICmpInst::ICMP_NE)) {
|
|
add(RHS, Constant::getNullValue(Ty), ICmpInst::ICMP_NE,
|
|
NewContext);
|
|
}
|
|
} break;
|
|
default:
|
|
break;
|
|
}
|
|
} else if (ICmpInst *IC = dyn_cast<ICmpInst>(I)) {
|
|
// "icmp ult i32 %a, %y" EQ true then %a u< y
|
|
// etc.
|
|
|
|
if (Canonical == ConstantInt::getTrue()) {
|
|
add(IC->getOperand(0), IC->getOperand(1), IC->getPredicate(),
|
|
NewContext);
|
|
} else if (Canonical == ConstantInt::getFalse()) {
|
|
add(IC->getOperand(0), IC->getOperand(1),
|
|
ICmpInst::getInversePredicate(IC->getPredicate()), NewContext);
|
|
}
|
|
} else if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
|
|
if (I->getType()->isFPOrFPVector()) return;
|
|
|
|
// Given: "%a = select i1 %x, i32 %b, i32 %c"
|
|
// %a EQ %b and %b NE %c then %x EQ true
|
|
// %a EQ %c and %b NE %c then %x EQ false
|
|
|
|
Value *True = SI->getTrueValue();
|
|
Value *False = SI->getFalseValue();
|
|
if (isRelatedBy(True, False, ICmpInst::ICMP_NE)) {
|
|
if (Canonical == VN.canonicalize(True, Top) ||
|
|
isRelatedBy(Canonical, False, ICmpInst::ICMP_NE))
|
|
add(SI->getCondition(), ConstantInt::getTrue(),
|
|
ICmpInst::ICMP_EQ, NewContext);
|
|
else if (Canonical == VN.canonicalize(False, Top) ||
|
|
isRelatedBy(Canonical, True, ICmpInst::ICMP_NE))
|
|
add(SI->getCondition(), ConstantInt::getFalse(),
|
|
ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
|
|
for (GetElementPtrInst::op_iterator OI = GEPI->idx_begin(),
|
|
OE = GEPI->idx_end(); OI != OE; ++OI) {
|
|
ConstantInt *Op = dyn_cast<ConstantInt>(VN.canonicalize(*OI, Top));
|
|
if (!Op || !Op->isZero()) return;
|
|
}
|
|
// TODO: The GEPI indices are all zero. Copy from definition to operand,
|
|
// jumping the type plane as needed.
|
|
if (isRelatedBy(GEPI, Constant::getNullValue(GEPI->getType()),
|
|
ICmpInst::ICMP_NE)) {
|
|
Value *Ptr = GEPI->getPointerOperand();
|
|
add(Ptr, Constant::getNullValue(Ptr->getType()), ICmpInst::ICMP_NE,
|
|
NewContext);
|
|
}
|
|
} else if (CastInst *CI = dyn_cast<CastInst>(I)) {
|
|
const Type *SrcTy = CI->getSrcTy();
|
|
|
|
unsigned ci = VN.getOrInsertVN(CI, Top);
|
|
uint32_t W = VR.typeToWidth(SrcTy);
|
|
if (!W) return;
|
|
ConstantRange CR = VR.range(ci, Top);
|
|
|
|
if (CR.isFullSet()) return;
|
|
|
|
switch (CI->getOpcode()) {
|
|
default: break;
|
|
case Instruction::ZExt:
|
|
case Instruction::SExt:
|
|
VR.applyRange(VN.getOrInsertVN(CI->getOperand(0), Top),
|
|
CR.truncate(W), Top, this);
|
|
break;
|
|
case Instruction::BitCast:
|
|
VR.applyRange(VN.getOrInsertVN(CI->getOperand(0), Top),
|
|
CR, Top, this);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
/// opsToDef - A new relationship was discovered involving one of this
|
|
/// instruction's operands. Find any new relationship involving the
|
|
/// definition, or another operand.
|
|
void opsToDef(Instruction *I) {
|
|
Instruction *NewContext = below(I) ? I : TopInst;
|
|
|
|
if (BinaryOperator *BO = dyn_cast<BinaryOperator>(I)) {
|
|
Value *Op0 = VN.canonicalize(BO->getOperand(0), Top);
|
|
Value *Op1 = VN.canonicalize(BO->getOperand(1), Top);
|
|
|
|
if (ConstantInt *CI0 = dyn_cast<ConstantInt>(Op0))
|
|
if (ConstantInt *CI1 = dyn_cast<ConstantInt>(Op1)) {
|
|
add(BO, ConstantExpr::get(BO->getOpcode(), CI0, CI1),
|
|
ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
}
|
|
|
|
// "%y = and i1 true, %x" then %x EQ %y
|
|
// "%y = or i1 false, %x" then %x EQ %y
|
|
// "%x = add i32 %y, 0" then %x EQ %y
|
|
// "%x = mul i32 %y, 0" then %x EQ 0
|
|
|
|
Instruction::BinaryOps Opcode = BO->getOpcode();
|
|
const Type *Ty = BO->getType();
|
|
assert(!Ty->isFPOrFPVector() && "Float in work queue!");
|
|
|
|
Constant *Zero = Constant::getNullValue(Ty);
|
|
ConstantInt *AllOnes = ConstantInt::getAllOnesValue(Ty);
|
|
|
|
switch (Opcode) {
|
|
default: break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr:
|
|
case Instruction::Shl:
|
|
case Instruction::Sub:
|
|
if (Op1 == Zero) {
|
|
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
}
|
|
break;
|
|
case Instruction::Or:
|
|
if (Op0 == AllOnes || Op1 == AllOnes) {
|
|
add(BO, AllOnes, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
} // fall-through
|
|
case Instruction::Xor:
|
|
case Instruction::Add:
|
|
if (Op0 == Zero) {
|
|
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
} else if (Op1 == Zero) {
|
|
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
}
|
|
break;
|
|
case Instruction::And:
|
|
if (Op0 == AllOnes) {
|
|
add(BO, Op1, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
} else if (Op1 == AllOnes) {
|
|
add(BO, Op0, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
}
|
|
// fall-through
|
|
case Instruction::Mul:
|
|
if (Op0 == Zero || Op1 == Zero) {
|
|
add(BO, Zero, ICmpInst::ICMP_EQ, NewContext);
|
|
return;
|
|
}
|
|
break;
|
|
}
|
|
|
|
// "%x = add i32 %y, %z" and %x EQ %y then %z EQ 0
|
|
// "%x = add i32 %y, %z" and %x EQ %z then %y EQ 0
|
|
// "%x = shl i32 %y, %z" and %x EQ %y and %y NE 0 then %z EQ 0
|
|
// "%x = udiv i32 %y, %z" and %x EQ %y then %z EQ 1
|
|
|
|
Value *Known = Op0, *Unknown = Op1,
|
|
*TheBO = VN.canonicalize(BO, Top);
|
|
if (Known != TheBO) std::swap(Known, Unknown);
|
|
if (Known == TheBO) {
|
|
switch (Opcode) {
|
|
default: break;
|
|
case Instruction::LShr:
|
|
case Instruction::AShr:
|
|
case Instruction::Shl:
|
|
if (!isRelatedBy(Known, Zero, ICmpInst::ICMP_NE)) break;
|
|
// otherwise, fall-through.
|
|
case Instruction::Sub:
|
|
if (Unknown == Op0) break;
|
|
// otherwise, fall-through.
|
|
case Instruction::Xor:
|
|
case Instruction::Add:
|
|
add(Unknown, Zero, ICmpInst::ICMP_EQ, NewContext);
|
|
break;
|
|
case Instruction::UDiv:
|
|
case Instruction::SDiv:
|
|
if (Unknown == Op1) break;
|
|
if (isRelatedBy(Known, Zero, ICmpInst::ICMP_NE)) {
|
|
Constant *One = ConstantInt::get(Ty, 1);
|
|
add(Unknown, One, ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
// TODO: "%a = add i32 %b, 1" and %b > %z then %a >= %z.
|
|
|
|
} else if (ICmpInst *IC = dyn_cast<ICmpInst>(I)) {
|
|
// "%a = icmp ult i32 %b, %c" and %b u< %c then %a EQ true
|
|
// "%a = icmp ult i32 %b, %c" and %b u>= %c then %a EQ false
|
|
// etc.
|
|
|
|
Value *Op0 = VN.canonicalize(IC->getOperand(0), Top);
|
|
Value *Op1 = VN.canonicalize(IC->getOperand(1), Top);
|
|
|
|
ICmpInst::Predicate Pred = IC->getPredicate();
|
|
if (isRelatedBy(Op0, Op1, Pred))
|
|
add(IC, ConstantInt::getTrue(), ICmpInst::ICMP_EQ, NewContext);
|
|
else if (isRelatedBy(Op0, Op1, ICmpInst::getInversePredicate(Pred)))
|
|
add(IC, ConstantInt::getFalse(), ICmpInst::ICMP_EQ, NewContext);
|
|
|
|
} else if (SelectInst *SI = dyn_cast<SelectInst>(I)) {
|
|
if (I->getType()->isFPOrFPVector()) return;
|
|
|
|
// Given: "%a = select i1 %x, i32 %b, i32 %c"
|
|
// %x EQ true then %a EQ %b
|
|
// %x EQ false then %a EQ %c
|
|
// %b EQ %c then %a EQ %b
|
|
|
|
Value *Canonical = VN.canonicalize(SI->getCondition(), Top);
|
|
if (Canonical == ConstantInt::getTrue()) {
|
|
add(SI, SI->getTrueValue(), ICmpInst::ICMP_EQ, NewContext);
|
|
} else if (Canonical == ConstantInt::getFalse()) {
|
|
add(SI, SI->getFalseValue(), ICmpInst::ICMP_EQ, NewContext);
|
|
} else if (VN.canonicalize(SI->getTrueValue(), Top) ==
|
|
VN.canonicalize(SI->getFalseValue(), Top)) {
|
|
add(SI, SI->getTrueValue(), ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
} else if (CastInst *CI = dyn_cast<CastInst>(I)) {
|
|
const Type *DestTy = CI->getDestTy();
|
|
if (DestTy->isFPOrFPVector()) return;
|
|
|
|
Value *Op = VN.canonicalize(CI->getOperand(0), Top);
|
|
Instruction::CastOps Opcode = CI->getOpcode();
|
|
|
|
if (Constant *C = dyn_cast<Constant>(Op)) {
|
|
add(CI, ConstantExpr::getCast(Opcode, C, DestTy),
|
|
ICmpInst::ICMP_EQ, NewContext);
|
|
}
|
|
|
|
uint32_t W = VR.typeToWidth(DestTy);
|
|
unsigned ci = VN.getOrInsertVN(CI, Top);
|
|
ConstantRange CR = VR.range(VN.getOrInsertVN(Op, Top), Top);
|
|
|
|
if (!CR.isFullSet()) {
|
|
switch (Opcode) {
|
|
default: break;
|
|
case Instruction::ZExt:
|
|
VR.applyRange(ci, CR.zeroExtend(W), Top, this);
|
|
break;
|
|
case Instruction::SExt:
|
|
VR.applyRange(ci, CR.signExtend(W), Top, this);
|
|
break;
|
|
case Instruction::Trunc: {
|
|
ConstantRange Result = CR.truncate(W);
|
|
if (!Result.isFullSet())
|
|
VR.applyRange(ci, Result, Top, this);
|
|
} break;
|
|
case Instruction::BitCast:
|
|
VR.applyRange(ci, CR, Top, this);
|
|
break;
|
|
// TODO: other casts?
|
|
}
|
|
}
|
|
} else if (GetElementPtrInst *GEPI = dyn_cast<GetElementPtrInst>(I)) {
|
|
for (GetElementPtrInst::op_iterator OI = GEPI->idx_begin(),
|
|
OE = GEPI->idx_end(); OI != OE; ++OI) {
|
|
ConstantInt *Op = dyn_cast<ConstantInt>(VN.canonicalize(*OI, Top));
|
|
if (!Op || !Op->isZero()) return;
|
|
}
|
|
// TODO: The GEPI indices are all zero. Copy from operand to definition,
|
|
// jumping the type plane as needed.
|
|
Value *Ptr = GEPI->getPointerOperand();
|
|
if (isRelatedBy(Ptr, Constant::getNullValue(Ptr->getType()),
|
|
ICmpInst::ICMP_NE)) {
|
|
add(GEPI, Constant::getNullValue(GEPI->getType()), ICmpInst::ICMP_NE,
|
|
NewContext);
|
|
}
|
|
}
|
|
}
|
|
|
|
/// solve - process the work queue
|
|
void solve() {
|
|
//DOUT << "WorkList entry, size: " << WorkList.size() << "\n";
|
|
while (!WorkList.empty()) {
|
|
//DOUT << "WorkList size: " << WorkList.size() << "\n";
|
|
|
|
Operation &O = WorkList.front();
|
|
TopInst = O.ContextInst;
|
|
TopBB = O.ContextBB;
|
|
Top = DTDFS->getNodeForBlock(TopBB); // XXX move this into Context
|
|
|
|
O.LHS = VN.canonicalize(O.LHS, Top);
|
|
O.RHS = VN.canonicalize(O.RHS, Top);
|
|
|
|
assert(O.LHS == VN.canonicalize(O.LHS, Top) && "Canonicalize isn't.");
|
|
assert(O.RHS == VN.canonicalize(O.RHS, Top) && "Canonicalize isn't.");
|
|
|
|
DOUT << "solving " << *O.LHS << " " << O.Op << " " << *O.RHS;
|
|
if (O.ContextInst) DOUT << " context inst: " << *O.ContextInst;
|
|
else DOUT << " context block: " << O.ContextBB->getName();
|
|
DOUT << "\n";
|
|
|
|
DEBUG(VN.dump());
|
|
DEBUG(IG.dump());
|
|
DEBUG(VR.dump());
|
|
|
|
// If they're both Constant, skip it. Check for contradiction and mark
|
|
// the BB as unreachable if so.
|
|
if (Constant *CI_L = dyn_cast<Constant>(O.LHS)) {
|
|
if (Constant *CI_R = dyn_cast<Constant>(O.RHS)) {
|
|
if (ConstantExpr::getCompare(O.Op, CI_L, CI_R) ==
|
|
ConstantInt::getFalse())
|
|
UB.mark(TopBB);
|
|
|
|
WorkList.pop_front();
|
|
continue;
|
|
}
|
|
}
|
|
|
|
if (VN.compare(O.LHS, O.RHS)) {
|
|
std::swap(O.LHS, O.RHS);
|
|
O.Op = ICmpInst::getSwappedPredicate(O.Op);
|
|
}
|
|
|
|
if (O.Op == ICmpInst::ICMP_EQ) {
|
|
if (!makeEqual(O.RHS, O.LHS))
|
|
UB.mark(TopBB);
|
|
} else {
|
|
LatticeVal LV = cmpInstToLattice(O.Op);
|
|
|
|
if ((LV & EQ_BIT) &&
|
|
isRelatedBy(O.LHS, O.RHS, ICmpInst::getSwappedPredicate(O.Op))) {
|
|
if (!makeEqual(O.RHS, O.LHS))
|
|
UB.mark(TopBB);
|
|
} else {
|
|
if (isRelatedBy(O.LHS, O.RHS, ICmpInst::getInversePredicate(O.Op))){
|
|
UB.mark(TopBB);
|
|
WorkList.pop_front();
|
|
continue;
|
|
}
|
|
|
|
unsigned n1 = VN.getOrInsertVN(O.LHS, Top);
|
|
unsigned n2 = VN.getOrInsertVN(O.RHS, Top);
|
|
|
|
if (n1 == n2) {
|
|
if (O.Op != ICmpInst::ICMP_UGE && O.Op != ICmpInst::ICMP_ULE &&
|
|
O.Op != ICmpInst::ICMP_SGE && O.Op != ICmpInst::ICMP_SLE)
|
|
UB.mark(TopBB);
|
|
|
|
WorkList.pop_front();
|
|
continue;
|
|
}
|
|
|
|
if (VR.isRelatedBy(n1, n2, Top, LV) ||
|
|
IG.isRelatedBy(n1, n2, Top, LV)) {
|
|
WorkList.pop_front();
|
|
continue;
|
|
}
|
|
|
|
VR.addInequality(n1, n2, Top, LV, this);
|
|
if ((!isa<ConstantInt>(O.RHS) && !isa<ConstantInt>(O.LHS)) ||
|
|
LV == NE)
|
|
IG.addInequality(n1, n2, Top, LV);
|
|
|
|
if (Instruction *I1 = dyn_cast<Instruction>(O.LHS)) {
|
|
if (aboveOrBelow(I1))
|
|
defToOps(I1);
|
|
}
|
|
if (isa<Instruction>(O.LHS) || isa<Argument>(O.LHS)) {
|
|
for (Value::use_iterator UI = O.LHS->use_begin(),
|
|
UE = O.LHS->use_end(); UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
|
if (aboveOrBelow(I))
|
|
opsToDef(I);
|
|
}
|
|
}
|
|
}
|
|
if (Instruction *I2 = dyn_cast<Instruction>(O.RHS)) {
|
|
if (aboveOrBelow(I2))
|
|
defToOps(I2);
|
|
}
|
|
if (isa<Instruction>(O.RHS) || isa<Argument>(O.RHS)) {
|
|
for (Value::use_iterator UI = O.RHS->use_begin(),
|
|
UE = O.RHS->use_end(); UI != UE;) {
|
|
Use &TheUse = UI.getUse();
|
|
++UI;
|
|
if (Instruction *I = dyn_cast<Instruction>(TheUse.getUser())) {
|
|
if (aboveOrBelow(I))
|
|
opsToDef(I);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
WorkList.pop_front();
|
|
}
|
|
}
|
|
};
|
|
|
|
void ValueRanges::addToWorklist(Value *V, Constant *C,
|
|
ICmpInst::Predicate Pred, VRPSolver *VRP) {
|
|
VRP->add(V, C, Pred, VRP->TopInst);
|
|
}
|
|
|
|
void ValueRanges::markBlock(VRPSolver *VRP) {
|
|
VRP->UB.mark(VRP->TopBB);
|
|
}
|
|
|
|
/// PredicateSimplifier - This class is a simplifier that replaces
|
|
/// one equivalent variable with another. It also tracks what
|
|
/// can't be equal and will solve setcc instructions when possible.
|
|
/// @brief Root of the predicate simplifier optimization.
|
|
class VISIBILITY_HIDDEN PredicateSimplifier : public FunctionPass {
|
|
DomTreeDFS *DTDFS;
|
|
bool modified;
|
|
ValueNumbering *VN;
|
|
InequalityGraph *IG;
|
|
UnreachableBlocks UB;
|
|
ValueRanges *VR;
|
|
|
|
std::vector<DomTreeDFS::Node *> WorkList;
|
|
|
|
public:
|
|
static char ID; // Pass identification, replacement for typeid
|
|
PredicateSimplifier() : FunctionPass((intptr_t)&ID) {}
|
|
|
|
bool runOnFunction(Function &F);
|
|
|
|
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
|
|
AU.addRequiredID(BreakCriticalEdgesID);
|
|
AU.addRequired<DominatorTree>();
|
|
AU.addRequired<TargetData>();
|
|
AU.addPreserved<TargetData>();
|
|
}
|
|
|
|
private:
|
|
/// Forwards - Adds new properties to VRPSolver and uses them to
|
|
/// simplify instructions. Because new properties sometimes apply to
|
|
/// a transition from one BasicBlock to another, this will use the
|
|
/// PredicateSimplifier::proceedToSuccessor(s) interface to enter the
|
|
/// basic block.
|
|
/// @brief Performs abstract execution of the program.
|
|
class VISIBILITY_HIDDEN Forwards : public InstVisitor<Forwards> {
|
|
friend class InstVisitor<Forwards>;
|
|
PredicateSimplifier *PS;
|
|
DomTreeDFS::Node *DTNode;
|
|
|
|
public:
|
|
ValueNumbering &VN;
|
|
InequalityGraph &IG;
|
|
UnreachableBlocks &UB;
|
|
ValueRanges &VR;
|
|
|
|
Forwards(PredicateSimplifier *PS, DomTreeDFS::Node *DTNode)
|
|
: PS(PS), DTNode(DTNode), VN(*PS->VN), IG(*PS->IG), UB(PS->UB),
|
|
VR(*PS->VR) {}
|
|
|
|
void visitTerminatorInst(TerminatorInst &TI);
|
|
void visitBranchInst(BranchInst &BI);
|
|
void visitSwitchInst(SwitchInst &SI);
|
|
|
|
void visitAllocaInst(AllocaInst &AI);
|
|
void visitLoadInst(LoadInst &LI);
|
|
void visitStoreInst(StoreInst &SI);
|
|
|
|
void visitSExtInst(SExtInst &SI);
|
|
void visitZExtInst(ZExtInst &ZI);
|
|
|
|
void visitBinaryOperator(BinaryOperator &BO);
|
|
void visitICmpInst(ICmpInst &IC);
|
|
};
|
|
|
|
// Used by terminator instructions to proceed from the current basic
|
|
// block to the next. Verifies that "current" dominates "next",
|
|
// then calls visitBasicBlock.
|
|
void proceedToSuccessors(DomTreeDFS::Node *Current) {
|
|
for (DomTreeDFS::Node::iterator I = Current->begin(),
|
|
E = Current->end(); I != E; ++I) {
|
|
WorkList.push_back(*I);
|
|
}
|
|
}
|
|
|
|
void proceedToSuccessor(DomTreeDFS::Node *Next) {
|
|
WorkList.push_back(Next);
|
|
}
|
|
|
|
// Visits each instruction in the basic block.
|
|
void visitBasicBlock(DomTreeDFS::Node *Node) {
|
|
BasicBlock *BB = Node->getBlock();
|
|
DOUT << "Entering Basic Block: " << BB->getName()
|
|
<< " (" << Node->getDFSNumIn() << ")\n";
|
|
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E;) {
|
|
visitInstruction(I++, Node);
|
|
}
|
|
}
|
|
|
|
// Tries to simplify each Instruction and add new properties.
|
|
void visitInstruction(Instruction *I, DomTreeDFS::Node *DT) {
|
|
DOUT << "Considering instruction " << *I << "\n";
|
|
DEBUG(VN->dump());
|
|
DEBUG(IG->dump());
|
|
DEBUG(VR->dump());
|
|
|
|
// Sometimes instructions are killed in earlier analysis.
|
|
if (isInstructionTriviallyDead(I)) {
|
|
++NumSimple;
|
|
modified = true;
|
|
if (unsigned n = VN->valueNumber(I, DTDFS->getRootNode()))
|
|
if (VN->value(n) == I) IG->remove(n);
|
|
VN->remove(I);
|
|
I->eraseFromParent();
|
|
return;
|
|
}
|
|
|
|
#ifndef NDEBUG
|
|
// Try to replace the whole instruction.
|
|
Value *V = VN->canonicalize(I, DT);
|
|
assert(V == I && "Late instruction canonicalization.");
|
|
if (V != I) {
|
|
modified = true;
|
|
++NumInstruction;
|
|
DOUT << "Removing " << *I << ", replacing with " << *V << "\n";
|
|
if (unsigned n = VN->valueNumber(I, DTDFS->getRootNode()))
|
|
if (VN->value(n) == I) IG->remove(n);
|
|
VN->remove(I);
|
|
I->replaceAllUsesWith(V);
|
|
I->eraseFromParent();
|
|
return;
|
|
}
|
|
|
|
// Try to substitute operands.
|
|
for (unsigned i = 0, e = I->getNumOperands(); i != e; ++i) {
|
|
Value *Oper = I->getOperand(i);
|
|
Value *V = VN->canonicalize(Oper, DT);
|
|
assert(V == Oper && "Late operand canonicalization.");
|
|
if (V != Oper) {
|
|
modified = true;
|
|
++NumVarsReplaced;
|
|
DOUT << "Resolving " << *I;
|
|
I->setOperand(i, V);
|
|
DOUT << " into " << *I;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
std::string name = I->getParent()->getName();
|
|
DOUT << "push (%" << name << ")\n";
|
|
Forwards visit(this, DT);
|
|
visit.visit(*I);
|
|
DOUT << "pop (%" << name << ")\n";
|
|
}
|
|
};
|
|
|
|
bool PredicateSimplifier::runOnFunction(Function &F) {
|
|
DominatorTree *DT = &getAnalysis<DominatorTree>();
|
|
DTDFS = new DomTreeDFS(DT);
|
|
TargetData *TD = &getAnalysis<TargetData>();
|
|
|
|
DOUT << "Entering Function: " << F.getName() << "\n";
|
|
|
|
modified = false;
|
|
DomTreeDFS::Node *Root = DTDFS->getRootNode();
|
|
VN = new ValueNumbering(DTDFS);
|
|
IG = new InequalityGraph(*VN, Root);
|
|
VR = new ValueRanges(*VN, TD);
|
|
WorkList.push_back(Root);
|
|
|
|
do {
|
|
DomTreeDFS::Node *DTNode = WorkList.back();
|
|
WorkList.pop_back();
|
|
if (!UB.isDead(DTNode->getBlock())) visitBasicBlock(DTNode);
|
|
} while (!WorkList.empty());
|
|
|
|
delete DTDFS;
|
|
delete VR;
|
|
delete IG;
|
|
|
|
modified |= UB.kill();
|
|
|
|
return modified;
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitTerminatorInst(TerminatorInst &TI) {
|
|
PS->proceedToSuccessors(DTNode);
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitBranchInst(BranchInst &BI) {
|
|
if (BI.isUnconditional()) {
|
|
PS->proceedToSuccessors(DTNode);
|
|
return;
|
|
}
|
|
|
|
Value *Condition = BI.getCondition();
|
|
BasicBlock *TrueDest = BI.getSuccessor(0);
|
|
BasicBlock *FalseDest = BI.getSuccessor(1);
|
|
|
|
if (isa<Constant>(Condition) || TrueDest == FalseDest) {
|
|
PS->proceedToSuccessors(DTNode);
|
|
return;
|
|
}
|
|
|
|
for (DomTreeDFS::Node::iterator I = DTNode->begin(), E = DTNode->end();
|
|
I != E; ++I) {
|
|
BasicBlock *Dest = (*I)->getBlock();
|
|
DOUT << "Branch thinking about %" << Dest->getName()
|
|
<< "(" << PS->DTDFS->getNodeForBlock(Dest)->getDFSNumIn() << ")\n";
|
|
|
|
if (Dest == TrueDest) {
|
|
DOUT << "(" << DTNode->getBlock()->getName() << ") true set:\n";
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, Dest);
|
|
VRP.add(ConstantInt::getTrue(), Condition, ICmpInst::ICMP_EQ);
|
|
VRP.solve();
|
|
DEBUG(VN.dump());
|
|
DEBUG(IG.dump());
|
|
DEBUG(VR.dump());
|
|
} else if (Dest == FalseDest) {
|
|
DOUT << "(" << DTNode->getBlock()->getName() << ") false set:\n";
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, Dest);
|
|
VRP.add(ConstantInt::getFalse(), Condition, ICmpInst::ICMP_EQ);
|
|
VRP.solve();
|
|
DEBUG(VN.dump());
|
|
DEBUG(IG.dump());
|
|
DEBUG(VR.dump());
|
|
}
|
|
|
|
PS->proceedToSuccessor(*I);
|
|
}
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitSwitchInst(SwitchInst &SI) {
|
|
Value *Condition = SI.getCondition();
|
|
|
|
// Set the EQProperty in each of the cases BBs, and the NEProperties
|
|
// in the default BB.
|
|
|
|
for (DomTreeDFS::Node::iterator I = DTNode->begin(), E = DTNode->end();
|
|
I != E; ++I) {
|
|
BasicBlock *BB = (*I)->getBlock();
|
|
DOUT << "Switch thinking about BB %" << BB->getName()
|
|
<< "(" << PS->DTDFS->getNodeForBlock(BB)->getDFSNumIn() << ")\n";
|
|
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, BB);
|
|
if (BB == SI.getDefaultDest()) {
|
|
for (unsigned i = 1, e = SI.getNumCases(); i < e; ++i)
|
|
if (SI.getSuccessor(i) != BB)
|
|
VRP.add(Condition, SI.getCaseValue(i), ICmpInst::ICMP_NE);
|
|
VRP.solve();
|
|
} else if (ConstantInt *CI = SI.findCaseDest(BB)) {
|
|
VRP.add(Condition, CI, ICmpInst::ICMP_EQ);
|
|
VRP.solve();
|
|
}
|
|
PS->proceedToSuccessor(*I);
|
|
}
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitAllocaInst(AllocaInst &AI) {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &AI);
|
|
VRP.add(Constant::getNullValue(AI.getType()), &AI, ICmpInst::ICMP_NE);
|
|
VRP.solve();
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitLoadInst(LoadInst &LI) {
|
|
Value *Ptr = LI.getPointerOperand();
|
|
// avoid "load uint* null" -> null NE null.
|
|
if (isa<Constant>(Ptr)) return;
|
|
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &LI);
|
|
VRP.add(Constant::getNullValue(Ptr->getType()), Ptr, ICmpInst::ICMP_NE);
|
|
VRP.solve();
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitStoreInst(StoreInst &SI) {
|
|
Value *Ptr = SI.getPointerOperand();
|
|
if (isa<Constant>(Ptr)) return;
|
|
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &SI);
|
|
VRP.add(Constant::getNullValue(Ptr->getType()), Ptr, ICmpInst::ICMP_NE);
|
|
VRP.solve();
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitSExtInst(SExtInst &SI) {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &SI);
|
|
uint32_t SrcBitWidth = cast<IntegerType>(SI.getSrcTy())->getBitWidth();
|
|
uint32_t DstBitWidth = cast<IntegerType>(SI.getDestTy())->getBitWidth();
|
|
APInt Min(APInt::getHighBitsSet(DstBitWidth, DstBitWidth-SrcBitWidth+1));
|
|
APInt Max(APInt::getLowBitsSet(DstBitWidth, SrcBitWidth-1));
|
|
VRP.add(ConstantInt::get(Min), &SI, ICmpInst::ICMP_SLE);
|
|
VRP.add(ConstantInt::get(Max), &SI, ICmpInst::ICMP_SGE);
|
|
VRP.solve();
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitZExtInst(ZExtInst &ZI) {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &ZI);
|
|
uint32_t SrcBitWidth = cast<IntegerType>(ZI.getSrcTy())->getBitWidth();
|
|
uint32_t DstBitWidth = cast<IntegerType>(ZI.getDestTy())->getBitWidth();
|
|
APInt Max(APInt::getLowBitsSet(DstBitWidth, SrcBitWidth));
|
|
VRP.add(ConstantInt::get(Max), &ZI, ICmpInst::ICMP_UGE);
|
|
VRP.solve();
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitBinaryOperator(BinaryOperator &BO) {
|
|
Instruction::BinaryOps ops = BO.getOpcode();
|
|
|
|
switch (ops) {
|
|
default: break;
|
|
case Instruction::URem:
|
|
case Instruction::SRem:
|
|
case Instruction::UDiv:
|
|
case Instruction::SDiv: {
|
|
Value *Divisor = BO.getOperand(1);
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(Constant::getNullValue(Divisor->getType()), Divisor,
|
|
ICmpInst::ICMP_NE);
|
|
VRP.solve();
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (ops) {
|
|
default: break;
|
|
case Instruction::Shl: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_UGE);
|
|
VRP.solve();
|
|
} break;
|
|
case Instruction::AShr: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_SLE);
|
|
VRP.solve();
|
|
} break;
|
|
case Instruction::LShr:
|
|
case Instruction::UDiv: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_ULE);
|
|
VRP.solve();
|
|
} break;
|
|
case Instruction::URem: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_ULE);
|
|
VRP.solve();
|
|
} break;
|
|
case Instruction::And: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_ULE);
|
|
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_ULE);
|
|
VRP.solve();
|
|
} break;
|
|
case Instruction::Or: {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &BO);
|
|
VRP.add(&BO, BO.getOperand(0), ICmpInst::ICMP_UGE);
|
|
VRP.add(&BO, BO.getOperand(1), ICmpInst::ICMP_UGE);
|
|
VRP.solve();
|
|
} break;
|
|
}
|
|
}
|
|
|
|
void PredicateSimplifier::Forwards::visitICmpInst(ICmpInst &IC) {
|
|
// If possible, squeeze the ICmp predicate into something simpler.
|
|
// Eg., if x = [0, 4) and we're being asked icmp uge %x, 3 then change
|
|
// the predicate to eq.
|
|
|
|
// XXX: once we do full PHI handling, modifying the instruction in the
|
|
// Forwards visitor will cause missed optimizations.
|
|
|
|
ICmpInst::Predicate Pred = IC.getPredicate();
|
|
|
|
switch (Pred) {
|
|
default: break;
|
|
case ICmpInst::ICMP_ULE: Pred = ICmpInst::ICMP_ULT; break;
|
|
case ICmpInst::ICMP_UGE: Pred = ICmpInst::ICMP_UGT; break;
|
|
case ICmpInst::ICMP_SLE: Pred = ICmpInst::ICMP_SLT; break;
|
|
case ICmpInst::ICMP_SGE: Pred = ICmpInst::ICMP_SGT; break;
|
|
}
|
|
if (Pred != IC.getPredicate()) {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &IC);
|
|
if (VRP.isRelatedBy(IC.getOperand(1), IC.getOperand(0),
|
|
ICmpInst::ICMP_NE)) {
|
|
++NumSnuggle;
|
|
PS->modified = true;
|
|
IC.setPredicate(Pred);
|
|
}
|
|
}
|
|
|
|
Pred = IC.getPredicate();
|
|
|
|
if (ConstantInt *Op1 = dyn_cast<ConstantInt>(IC.getOperand(1))) {
|
|
ConstantInt *NextVal = 0;
|
|
switch (Pred) {
|
|
default: break;
|
|
case ICmpInst::ICMP_SLT:
|
|
case ICmpInst::ICMP_ULT:
|
|
if (Op1->getValue() != 0)
|
|
NextVal = ConstantInt::get(Op1->getValue()-1);
|
|
break;
|
|
case ICmpInst::ICMP_SGT:
|
|
case ICmpInst::ICMP_UGT:
|
|
if (!Op1->getValue().isAllOnesValue())
|
|
NextVal = ConstantInt::get(Op1->getValue()+1);
|
|
break;
|
|
|
|
}
|
|
if (NextVal) {
|
|
VRPSolver VRP(VN, IG, UB, VR, PS->DTDFS, PS->modified, &IC);
|
|
if (VRP.isRelatedBy(IC.getOperand(0), NextVal,
|
|
ICmpInst::getInversePredicate(Pred))) {
|
|
ICmpInst *NewIC = new ICmpInst(ICmpInst::ICMP_EQ, IC.getOperand(0),
|
|
NextVal, "", &IC);
|
|
NewIC->takeName(&IC);
|
|
IC.replaceAllUsesWith(NewIC);
|
|
|
|
// XXX: prove this isn't necessary
|
|
if (unsigned n = VN.valueNumber(&IC, PS->DTDFS->getRootNode()))
|
|
if (VN.value(n) == &IC) IG.remove(n);
|
|
VN.remove(&IC);
|
|
|
|
IC.eraseFromParent();
|
|
++NumSnuggle;
|
|
PS->modified = true;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
char PredicateSimplifier::ID = 0;
|
|
RegisterPass<PredicateSimplifier> X("predsimplify",
|
|
"Predicate Simplifier");
|
|
}
|
|
|
|
FunctionPass *llvm::createPredicateSimplifierPass() {
|
|
return new PredicateSimplifier();
|
|
}
|