llvm-6502/lib/Transforms/Scalar/GVNPRE.cpp
Dan Gohman ae3a0be92e Split the Add, Sub, and Mul instruction opcodes into separate
integer and floating-point opcodes, introducing
FAdd, FSub, and FMul.

For now, the AsmParser, BitcodeReader, and IRBuilder all preserve
backwards compatability, and the Core LLVM APIs preserve backwards
compatibility for IR producers. Most front-ends won't need to change
immediately.

This implements the first step of the plan outlined here:
http://nondot.org/sabre/LLVMNotes/IntegerOverflow.txt


git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@72897 91177308-0d34-0410-b5e6-96231b3b80d8
2009-06-04 22:49:04 +00:00

1893 lines
60 KiB
C++

//===- GVNPRE.cpp - Eliminate redundant values and expressions ------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This pass performs a hybrid of global value numbering and partial redundancy
// elimination, known as GVN-PRE. It performs partial redundancy elimination on
// values, rather than lexical expressions, allowing a more comprehensive view
// the optimization. It replaces redundant values with uses of earlier
// occurences of the same value. While this is beneficial in that it eliminates
// unneeded computation, it also increases register pressure by creating large
// live ranges, and should be used with caution on platforms that are very
// sensitive to register pressure.
//
// Note that this pass does the value numbering itself, it does not use the
// ValueNumbering analysis passes.
//
//===----------------------------------------------------------------------===//
#define DEBUG_TYPE "gvnpre"
#include "llvm/Value.h"
#include "llvm/Transforms/Scalar.h"
#include "llvm/Instructions.h"
#include "llvm/Function.h"
#include "llvm/DerivedTypes.h"
#include "llvm/Analysis/Dominators.h"
#include "llvm/ADT/BitVector.h"
#include "llvm/ADT/DenseMap.h"
#include "llvm/ADT/DepthFirstIterator.h"
#include "llvm/ADT/PostOrderIterator.h"
#include "llvm/ADT/SmallPtrSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/Statistic.h"
#include "llvm/Transforms/Utils/UnifyFunctionExitNodes.h"
#include "llvm/Support/CFG.h"
#include "llvm/Support/Compiler.h"
#include "llvm/Support/Debug.h"
#include <algorithm>
#include <deque>
#include <map>
using namespace llvm;
//===----------------------------------------------------------------------===//
// ValueTable Class
//===----------------------------------------------------------------------===//
namespace {
/// This class holds the mapping between values and value numbers. It is used
/// as an efficient mechanism to determine the expression-wise equivalence of
/// two values.
struct Expression {
enum ExpressionOpcode { ADD, FADD, SUB, FSUB, MUL, FMUL,
UDIV, SDIV, FDIV, UREM, SREM,
FREM, SHL, LSHR, ASHR, AND, OR, XOR, ICMPEQ,
ICMPNE, ICMPUGT, ICMPUGE, ICMPULT, ICMPULE,
ICMPSGT, ICMPSGE, ICMPSLT, ICMPSLE, FCMPOEQ,
FCMPOGT, FCMPOGE, FCMPOLT, FCMPOLE, FCMPONE,
FCMPORD, FCMPUNO, FCMPUEQ, FCMPUGT, FCMPUGE,
FCMPULT, FCMPULE, FCMPUNE, EXTRACT, INSERT,
SHUFFLE, SELECT, TRUNC, ZEXT, SEXT, FPTOUI,
FPTOSI, UITOFP, SITOFP, FPTRUNC, FPEXT,
PTRTOINT, INTTOPTR, BITCAST, GEP, EMPTY,
TOMBSTONE };
ExpressionOpcode opcode;
const Type* type;
uint32_t firstVN;
uint32_t secondVN;
uint32_t thirdVN;
SmallVector<uint32_t, 4> varargs;
Expression() { }
explicit Expression(ExpressionOpcode o) : opcode(o) { }
bool operator==(const Expression &other) const {
if (opcode != other.opcode)
return false;
else if (opcode == EMPTY || opcode == TOMBSTONE)
return true;
else if (type != other.type)
return false;
else if (firstVN != other.firstVN)
return false;
else if (secondVN != other.secondVN)
return false;
else if (thirdVN != other.thirdVN)
return false;
else {
if (varargs.size() != other.varargs.size())
return false;
for (size_t i = 0; i < varargs.size(); ++i)
if (varargs[i] != other.varargs[i])
return false;
return true;
}
}
bool operator!=(const Expression &other) const {
if (opcode != other.opcode)
return true;
else if (opcode == EMPTY || opcode == TOMBSTONE)
return false;
else if (type != other.type)
return true;
else if (firstVN != other.firstVN)
return true;
else if (secondVN != other.secondVN)
return true;
else if (thirdVN != other.thirdVN)
return true;
else {
if (varargs.size() != other.varargs.size())
return true;
for (size_t i = 0; i < varargs.size(); ++i)
if (varargs[i] != other.varargs[i])
return true;
return false;
}
}
};
}
namespace {
class VISIBILITY_HIDDEN ValueTable {
private:
DenseMap<Value*, uint32_t> valueNumbering;
DenseMap<Expression, uint32_t> expressionNumbering;
uint32_t nextValueNumber;
Expression::ExpressionOpcode getOpcode(BinaryOperator* BO);
Expression::ExpressionOpcode getOpcode(CmpInst* C);
Expression::ExpressionOpcode getOpcode(CastInst* C);
Expression create_expression(BinaryOperator* BO);
Expression create_expression(CmpInst* C);
Expression create_expression(ShuffleVectorInst* V);
Expression create_expression(ExtractElementInst* C);
Expression create_expression(InsertElementInst* V);
Expression create_expression(SelectInst* V);
Expression create_expression(CastInst* C);
Expression create_expression(GetElementPtrInst* G);
public:
ValueTable() { nextValueNumber = 1; }
uint32_t lookup_or_add(Value* V);
uint32_t lookup(Value* V) const;
void add(Value* V, uint32_t num);
void clear();
void erase(Value* v);
unsigned size();
};
}
namespace llvm {
template <> struct DenseMapInfo<Expression> {
static inline Expression getEmptyKey() {
return Expression(Expression::EMPTY);
}
static inline Expression getTombstoneKey() {
return Expression(Expression::TOMBSTONE);
}
static unsigned getHashValue(const Expression e) {
unsigned hash = e.opcode;
hash = e.firstVN + hash * 37;
hash = e.secondVN + hash * 37;
hash = e.thirdVN + hash * 37;
hash = ((unsigned)((uintptr_t)e.type >> 4) ^
(unsigned)((uintptr_t)e.type >> 9)) +
hash * 37;
for (SmallVector<uint32_t, 4>::const_iterator I = e.varargs.begin(),
E = e.varargs.end(); I != E; ++I)
hash = *I + hash * 37;
return hash;
}
static bool isEqual(const Expression &LHS, const Expression &RHS) {
return LHS == RHS;
}
static bool isPod() { return true; }
};
}
//===----------------------------------------------------------------------===//
// ValueTable Internal Functions
//===----------------------------------------------------------------------===//
Expression::ExpressionOpcode
ValueTable::getOpcode(BinaryOperator* BO) {
switch(BO->getOpcode()) {
case Instruction::Add:
return Expression::ADD;
case Instruction::FAdd:
return Expression::FADD;
case Instruction::Sub:
return Expression::SUB;
case Instruction::FSub:
return Expression::FSUB;
case Instruction::Mul:
return Expression::MUL;
case Instruction::FMul:
return Expression::FMUL;
case Instruction::UDiv:
return Expression::UDIV;
case Instruction::SDiv:
return Expression::SDIV;
case Instruction::FDiv:
return Expression::FDIV;
case Instruction::URem:
return Expression::UREM;
case Instruction::SRem:
return Expression::SREM;
case Instruction::FRem:
return Expression::FREM;
case Instruction::Shl:
return Expression::SHL;
case Instruction::LShr:
return Expression::LSHR;
case Instruction::AShr:
return Expression::ASHR;
case Instruction::And:
return Expression::AND;
case Instruction::Or:
return Expression::OR;
case Instruction::Xor:
return Expression::XOR;
// THIS SHOULD NEVER HAPPEN
default:
assert(0 && "Binary operator with unknown opcode?");
return Expression::ADD;
}
}
Expression::ExpressionOpcode ValueTable::getOpcode(CmpInst* C) {
if (C->getOpcode() == Instruction::ICmp) {
switch (C->getPredicate()) {
case ICmpInst::ICMP_EQ:
return Expression::ICMPEQ;
case ICmpInst::ICMP_NE:
return Expression::ICMPNE;
case ICmpInst::ICMP_UGT:
return Expression::ICMPUGT;
case ICmpInst::ICMP_UGE:
return Expression::ICMPUGE;
case ICmpInst::ICMP_ULT:
return Expression::ICMPULT;
case ICmpInst::ICMP_ULE:
return Expression::ICMPULE;
case ICmpInst::ICMP_SGT:
return Expression::ICMPSGT;
case ICmpInst::ICMP_SGE:
return Expression::ICMPSGE;
case ICmpInst::ICMP_SLT:
return Expression::ICMPSLT;
case ICmpInst::ICMP_SLE:
return Expression::ICMPSLE;
// THIS SHOULD NEVER HAPPEN
default:
assert(0 && "Comparison with unknown predicate?");
return Expression::ICMPEQ;
}
} else {
switch (C->getPredicate()) {
case FCmpInst::FCMP_OEQ:
return Expression::FCMPOEQ;
case FCmpInst::FCMP_OGT:
return Expression::FCMPOGT;
case FCmpInst::FCMP_OGE:
return Expression::FCMPOGE;
case FCmpInst::FCMP_OLT:
return Expression::FCMPOLT;
case FCmpInst::FCMP_OLE:
return Expression::FCMPOLE;
case FCmpInst::FCMP_ONE:
return Expression::FCMPONE;
case FCmpInst::FCMP_ORD:
return Expression::FCMPORD;
case FCmpInst::FCMP_UNO:
return Expression::FCMPUNO;
case FCmpInst::FCMP_UEQ:
return Expression::FCMPUEQ;
case FCmpInst::FCMP_UGT:
return Expression::FCMPUGT;
case FCmpInst::FCMP_UGE:
return Expression::FCMPUGE;
case FCmpInst::FCMP_ULT:
return Expression::FCMPULT;
case FCmpInst::FCMP_ULE:
return Expression::FCMPULE;
case FCmpInst::FCMP_UNE:
return Expression::FCMPUNE;
// THIS SHOULD NEVER HAPPEN
default:
assert(0 && "Comparison with unknown predicate?");
return Expression::FCMPOEQ;
}
}
}
Expression::ExpressionOpcode
ValueTable::getOpcode(CastInst* C) {
switch(C->getOpcode()) {
case Instruction::Trunc:
return Expression::TRUNC;
case Instruction::ZExt:
return Expression::ZEXT;
case Instruction::SExt:
return Expression::SEXT;
case Instruction::FPToUI:
return Expression::FPTOUI;
case Instruction::FPToSI:
return Expression::FPTOSI;
case Instruction::UIToFP:
return Expression::UITOFP;
case Instruction::SIToFP:
return Expression::SITOFP;
case Instruction::FPTrunc:
return Expression::FPTRUNC;
case Instruction::FPExt:
return Expression::FPEXT;
case Instruction::PtrToInt:
return Expression::PTRTOINT;
case Instruction::IntToPtr:
return Expression::INTTOPTR;
case Instruction::BitCast:
return Expression::BITCAST;
// THIS SHOULD NEVER HAPPEN
default:
assert(0 && "Cast operator with unknown opcode?");
return Expression::BITCAST;
}
}
Expression ValueTable::create_expression(BinaryOperator* BO) {
Expression e;
e.firstVN = lookup_or_add(BO->getOperand(0));
e.secondVN = lookup_or_add(BO->getOperand(1));
e.thirdVN = 0;
e.type = BO->getType();
e.opcode = getOpcode(BO);
return e;
}
Expression ValueTable::create_expression(CmpInst* C) {
Expression e;
e.firstVN = lookup_or_add(C->getOperand(0));
e.secondVN = lookup_or_add(C->getOperand(1));
e.thirdVN = 0;
e.type = C->getType();
e.opcode = getOpcode(C);
return e;
}
Expression ValueTable::create_expression(CastInst* C) {
Expression e;
e.firstVN = lookup_or_add(C->getOperand(0));
e.secondVN = 0;
e.thirdVN = 0;
e.type = C->getType();
e.opcode = getOpcode(C);
return e;
}
Expression ValueTable::create_expression(ShuffleVectorInst* S) {
Expression e;
e.firstVN = lookup_or_add(S->getOperand(0));
e.secondVN = lookup_or_add(S->getOperand(1));
e.thirdVN = lookup_or_add(S->getOperand(2));
e.type = S->getType();
e.opcode = Expression::SHUFFLE;
return e;
}
Expression ValueTable::create_expression(ExtractElementInst* E) {
Expression e;
e.firstVN = lookup_or_add(E->getOperand(0));
e.secondVN = lookup_or_add(E->getOperand(1));
e.thirdVN = 0;
e.type = E->getType();
e.opcode = Expression::EXTRACT;
return e;
}
Expression ValueTable::create_expression(InsertElementInst* I) {
Expression e;
e.firstVN = lookup_or_add(I->getOperand(0));
e.secondVN = lookup_or_add(I->getOperand(1));
e.thirdVN = lookup_or_add(I->getOperand(2));
e.type = I->getType();
e.opcode = Expression::INSERT;
return e;
}
Expression ValueTable::create_expression(SelectInst* I) {
Expression e;
e.firstVN = lookup_or_add(I->getCondition());
e.secondVN = lookup_or_add(I->getTrueValue());
e.thirdVN = lookup_or_add(I->getFalseValue());
e.type = I->getType();
e.opcode = Expression::SELECT;
return e;
}
Expression ValueTable::create_expression(GetElementPtrInst* G) {
Expression e;
e.firstVN = lookup_or_add(G->getPointerOperand());
e.secondVN = 0;
e.thirdVN = 0;
e.type = G->getType();
e.opcode = Expression::GEP;
for (GetElementPtrInst::op_iterator I = G->idx_begin(), E = G->idx_end();
I != E; ++I)
e.varargs.push_back(lookup_or_add(*I));
return e;
}
//===----------------------------------------------------------------------===//
// ValueTable External Functions
//===----------------------------------------------------------------------===//
/// lookup_or_add - Returns the value number for the specified value, assigning
/// it a new number if it did not have one before.
uint32_t ValueTable::lookup_or_add(Value* V) {
DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V);
if (VI != valueNumbering.end())
return VI->second;
if (BinaryOperator* BO = dyn_cast<BinaryOperator>(V)) {
Expression e = create_expression(BO);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (CmpInst* C = dyn_cast<CmpInst>(V)) {
Expression e = create_expression(C);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (ShuffleVectorInst* U = dyn_cast<ShuffleVectorInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (ExtractElementInst* U = dyn_cast<ExtractElementInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (InsertElementInst* U = dyn_cast<InsertElementInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (SelectInst* U = dyn_cast<SelectInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (CastInst* U = dyn_cast<CastInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(V)) {
Expression e = create_expression(U);
DenseMap<Expression, uint32_t>::iterator EI = expressionNumbering.find(e);
if (EI != expressionNumbering.end()) {
valueNumbering.insert(std::make_pair(V, EI->second));
return EI->second;
} else {
expressionNumbering.insert(std::make_pair(e, nextValueNumber));
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
} else {
valueNumbering.insert(std::make_pair(V, nextValueNumber));
return nextValueNumber++;
}
}
/// lookup - Returns the value number of the specified value. Fails if
/// the value has not yet been numbered.
uint32_t ValueTable::lookup(Value* V) const {
DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V);
if (VI != valueNumbering.end())
return VI->second;
else
assert(0 && "Value not numbered?");
return 0;
}
/// add - Add the specified value with the given value number, removing
/// its old number, if any
void ValueTable::add(Value* V, uint32_t num) {
DenseMap<Value*, uint32_t>::iterator VI = valueNumbering.find(V);
if (VI != valueNumbering.end())
valueNumbering.erase(VI);
valueNumbering.insert(std::make_pair(V, num));
}
/// clear - Remove all entries from the ValueTable
void ValueTable::clear() {
valueNumbering.clear();
expressionNumbering.clear();
nextValueNumber = 1;
}
/// erase - Remove a value from the value numbering
void ValueTable::erase(Value* V) {
valueNumbering.erase(V);
}
/// size - Return the number of assigned value numbers
unsigned ValueTable::size() {
// NOTE: zero is never assigned
return nextValueNumber;
}
namespace {
//===----------------------------------------------------------------------===//
// ValueNumberedSet Class
//===----------------------------------------------------------------------===//
class ValueNumberedSet {
private:
SmallPtrSet<Value*, 8> contents;
BitVector numbers;
public:
ValueNumberedSet() { numbers.resize(1); }
ValueNumberedSet(const ValueNumberedSet& other) {
numbers = other.numbers;
contents = other.contents;
}
typedef SmallPtrSet<Value*, 8>::iterator iterator;
iterator begin() { return contents.begin(); }
iterator end() { return contents.end(); }
bool insert(Value* v) { return contents.insert(v); }
void insert(iterator I, iterator E) { contents.insert(I, E); }
void erase(Value* v) { contents.erase(v); }
unsigned count(Value* v) { return contents.count(v); }
size_t size() { return contents.size(); }
void set(unsigned i) {
if (i >= numbers.size())
numbers.resize(i+1);
numbers.set(i);
}
void operator=(const ValueNumberedSet& other) {
contents = other.contents;
numbers = other.numbers;
}
void reset(unsigned i) {
if (i < numbers.size())
numbers.reset(i);
}
bool test(unsigned i) {
if (i >= numbers.size())
return false;
return numbers.test(i);
}
void clear() {
contents.clear();
numbers.clear();
}
};
}
//===----------------------------------------------------------------------===//
// GVNPRE Pass
//===----------------------------------------------------------------------===//
namespace {
class VISIBILITY_HIDDEN GVNPRE : public FunctionPass {
bool runOnFunction(Function &F);
public:
static char ID; // Pass identification, replacement for typeid
GVNPRE() : FunctionPass(&ID) {}
private:
ValueTable VN;
SmallVector<Instruction*, 8> createdExpressions;
DenseMap<BasicBlock*, ValueNumberedSet> availableOut;
DenseMap<BasicBlock*, ValueNumberedSet> anticipatedIn;
DenseMap<BasicBlock*, ValueNumberedSet> generatedPhis;
// This transformation requires dominator postdominator info
virtual void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesCFG();
AU.addRequiredID(BreakCriticalEdgesID);
AU.addRequired<UnifyFunctionExitNodes>();
AU.addRequired<DominatorTree>();
}
// Helper fuctions
// FIXME: eliminate or document these better
void dump(ValueNumberedSet& s) const ;
void clean(ValueNumberedSet& set) ;
Value* find_leader(ValueNumberedSet& vals, uint32_t v) ;
Value* phi_translate(Value* V, BasicBlock* pred, BasicBlock* succ) ;
void phi_translate_set(ValueNumberedSet& anticIn, BasicBlock* pred,
BasicBlock* succ, ValueNumberedSet& out) ;
void topo_sort(ValueNumberedSet& set,
SmallVector<Value*, 8>& vec) ;
void cleanup() ;
bool elimination() ;
void val_insert(ValueNumberedSet& s, Value* v) ;
void val_replace(ValueNumberedSet& s, Value* v) ;
bool dependsOnInvoke(Value* V) ;
void buildsets_availout(BasicBlock::iterator I,
ValueNumberedSet& currAvail,
ValueNumberedSet& currPhis,
ValueNumberedSet& currExps,
SmallPtrSet<Value*, 16>& currTemps);
bool buildsets_anticout(BasicBlock* BB,
ValueNumberedSet& anticOut,
SmallPtrSet<BasicBlock*, 8>& visited);
unsigned buildsets_anticin(BasicBlock* BB,
ValueNumberedSet& anticOut,
ValueNumberedSet& currExps,
SmallPtrSet<Value*, 16>& currTemps,
SmallPtrSet<BasicBlock*, 8>& visited);
void buildsets(Function& F) ;
void insertion_pre(Value* e, BasicBlock* BB,
DenseMap<BasicBlock*, Value*>& avail,
std::map<BasicBlock*,ValueNumberedSet>& new_set);
unsigned insertion_mergepoint(SmallVector<Value*, 8>& workList,
df_iterator<DomTreeNode*>& D,
std::map<BasicBlock*, ValueNumberedSet>& new_set);
bool insertion(Function& F) ;
};
char GVNPRE::ID = 0;
}
// createGVNPREPass - The public interface to this file...
FunctionPass *llvm::createGVNPREPass() { return new GVNPRE(); }
static RegisterPass<GVNPRE> X("gvnpre",
"Global Value Numbering/Partial Redundancy Elimination");
STATISTIC(NumInsertedVals, "Number of values inserted");
STATISTIC(NumInsertedPhis, "Number of PHI nodes inserted");
STATISTIC(NumEliminated, "Number of redundant instructions eliminated");
/// find_leader - Given a set and a value number, return the first
/// element of the set with that value number, or 0 if no such element
/// is present
Value* GVNPRE::find_leader(ValueNumberedSet& vals, uint32_t v) {
if (!vals.test(v))
return 0;
for (ValueNumberedSet::iterator I = vals.begin(), E = vals.end();
I != E; ++I)
if (v == VN.lookup(*I))
return *I;
assert(0 && "No leader found, but present bit is set?");
return 0;
}
/// val_insert - Insert a value into a set only if there is not a value
/// with the same value number already in the set
void GVNPRE::val_insert(ValueNumberedSet& s, Value* v) {
uint32_t num = VN.lookup(v);
if (!s.test(num))
s.insert(v);
}
/// val_replace - Insert a value into a set, replacing any values already in
/// the set that have the same value number
void GVNPRE::val_replace(ValueNumberedSet& s, Value* v) {
if (s.count(v)) return;
uint32_t num = VN.lookup(v);
Value* leader = find_leader(s, num);
if (leader != 0)
s.erase(leader);
s.insert(v);
s.set(num);
}
/// phi_translate - Given a value, its parent block, and a predecessor of its
/// parent, translate the value into legal for the predecessor block. This
/// means translating its operands (and recursively, their operands) through
/// any phi nodes in the parent into values available in the predecessor
Value* GVNPRE::phi_translate(Value* V, BasicBlock* pred, BasicBlock* succ) {
if (V == 0)
return 0;
// Unary Operations
if (CastInst* U = dyn_cast<CastInst>(V)) {
Value* newOp1 = 0;
if (isa<Instruction>(U->getOperand(0)))
newOp1 = phi_translate(U->getOperand(0), pred, succ);
else
newOp1 = U->getOperand(0);
if (newOp1 == 0)
return 0;
if (newOp1 != U->getOperand(0)) {
Instruction* newVal = 0;
if (CastInst* C = dyn_cast<CastInst>(U))
newVal = CastInst::Create(C->getOpcode(),
newOp1, C->getType(),
C->getName()+".expr");
uint32_t v = VN.lookup_or_add(newVal);
Value* leader = find_leader(availableOut[pred], v);
if (leader == 0) {
createdExpressions.push_back(newVal);
return newVal;
} else {
VN.erase(newVal);
delete newVal;
return leader;
}
}
// Binary Operations
} if (isa<BinaryOperator>(V) || isa<CmpInst>(V) ||
isa<ExtractElementInst>(V)) {
User* U = cast<User>(V);
Value* newOp1 = 0;
if (isa<Instruction>(U->getOperand(0)))
newOp1 = phi_translate(U->getOperand(0), pred, succ);
else
newOp1 = U->getOperand(0);
if (newOp1 == 0)
return 0;
Value* newOp2 = 0;
if (isa<Instruction>(U->getOperand(1)))
newOp2 = phi_translate(U->getOperand(1), pred, succ);
else
newOp2 = U->getOperand(1);
if (newOp2 == 0)
return 0;
if (newOp1 != U->getOperand(0) || newOp2 != U->getOperand(1)) {
Instruction* newVal = 0;
if (BinaryOperator* BO = dyn_cast<BinaryOperator>(U))
newVal = BinaryOperator::Create(BO->getOpcode(),
newOp1, newOp2,
BO->getName()+".expr");
else if (CmpInst* C = dyn_cast<CmpInst>(U))
newVal = CmpInst::Create(C->getOpcode(),
C->getPredicate(),
newOp1, newOp2,
C->getName()+".expr");
else if (ExtractElementInst* E = dyn_cast<ExtractElementInst>(U))
newVal = new ExtractElementInst(newOp1, newOp2, E->getName()+".expr");
uint32_t v = VN.lookup_or_add(newVal);
Value* leader = find_leader(availableOut[pred], v);
if (leader == 0) {
createdExpressions.push_back(newVal);
return newVal;
} else {
VN.erase(newVal);
delete newVal;
return leader;
}
}
// Ternary Operations
} else if (isa<ShuffleVectorInst>(V) || isa<InsertElementInst>(V) ||
isa<SelectInst>(V)) {
User* U = cast<User>(V);
Value* newOp1 = 0;
if (isa<Instruction>(U->getOperand(0)))
newOp1 = phi_translate(U->getOperand(0), pred, succ);
else
newOp1 = U->getOperand(0);
if (newOp1 == 0)
return 0;
Value* newOp2 = 0;
if (isa<Instruction>(U->getOperand(1)))
newOp2 = phi_translate(U->getOperand(1), pred, succ);
else
newOp2 = U->getOperand(1);
if (newOp2 == 0)
return 0;
Value* newOp3 = 0;
if (isa<Instruction>(U->getOperand(2)))
newOp3 = phi_translate(U->getOperand(2), pred, succ);
else
newOp3 = U->getOperand(2);
if (newOp3 == 0)
return 0;
if (newOp1 != U->getOperand(0) ||
newOp2 != U->getOperand(1) ||
newOp3 != U->getOperand(2)) {
Instruction* newVal = 0;
if (ShuffleVectorInst* S = dyn_cast<ShuffleVectorInst>(U))
newVal = new ShuffleVectorInst(newOp1, newOp2, newOp3,
S->getName() + ".expr");
else if (InsertElementInst* I = dyn_cast<InsertElementInst>(U))
newVal = InsertElementInst::Create(newOp1, newOp2, newOp3,
I->getName() + ".expr");
else if (SelectInst* I = dyn_cast<SelectInst>(U))
newVal = SelectInst::Create(newOp1, newOp2, newOp3,
I->getName() + ".expr");
uint32_t v = VN.lookup_or_add(newVal);
Value* leader = find_leader(availableOut[pred], v);
if (leader == 0) {
createdExpressions.push_back(newVal);
return newVal;
} else {
VN.erase(newVal);
delete newVal;
return leader;
}
}
// Varargs operators
} else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(V)) {
Value* newOp1 = 0;
if (isa<Instruction>(U->getPointerOperand()))
newOp1 = phi_translate(U->getPointerOperand(), pred, succ);
else
newOp1 = U->getPointerOperand();
if (newOp1 == 0)
return 0;
bool changed_idx = false;
SmallVector<Value*, 4> newIdx;
for (GetElementPtrInst::op_iterator I = U->idx_begin(), E = U->idx_end();
I != E; ++I)
if (isa<Instruction>(*I)) {
Value* newVal = phi_translate(*I, pred, succ);
newIdx.push_back(newVal);
if (newVal != *I)
changed_idx = true;
} else {
newIdx.push_back(*I);
}
if (newOp1 != U->getPointerOperand() || changed_idx) {
Instruction* newVal =
GetElementPtrInst::Create(newOp1,
newIdx.begin(), newIdx.end(),
U->getName()+".expr");
uint32_t v = VN.lookup_or_add(newVal);
Value* leader = find_leader(availableOut[pred], v);
if (leader == 0) {
createdExpressions.push_back(newVal);
return newVal;
} else {
VN.erase(newVal);
delete newVal;
return leader;
}
}
// PHI Nodes
} else if (PHINode* P = dyn_cast<PHINode>(V)) {
if (P->getParent() == succ)
return P->getIncomingValueForBlock(pred);
}
return V;
}
/// phi_translate_set - Perform phi translation on every element of a set
void GVNPRE::phi_translate_set(ValueNumberedSet& anticIn,
BasicBlock* pred, BasicBlock* succ,
ValueNumberedSet& out) {
for (ValueNumberedSet::iterator I = anticIn.begin(),
E = anticIn.end(); I != E; ++I) {
Value* V = phi_translate(*I, pred, succ);
if (V != 0 && !out.test(VN.lookup_or_add(V))) {
out.insert(V);
out.set(VN.lookup(V));
}
}
}
/// dependsOnInvoke - Test if a value has an phi node as an operand, any of
/// whose inputs is an invoke instruction. If this is true, we cannot safely
/// PRE the instruction or anything that depends on it.
bool GVNPRE::dependsOnInvoke(Value* V) {
if (PHINode* p = dyn_cast<PHINode>(V)) {
for (PHINode::op_iterator I = p->op_begin(), E = p->op_end(); I != E; ++I)
if (isa<InvokeInst>(*I))
return true;
return false;
} else {
return false;
}
}
/// clean - Remove all non-opaque values from the set whose operands are not
/// themselves in the set, as well as all values that depend on invokes (see
/// above)
void GVNPRE::clean(ValueNumberedSet& set) {
SmallVector<Value*, 8> worklist;
worklist.reserve(set.size());
topo_sort(set, worklist);
for (unsigned i = 0; i < worklist.size(); ++i) {
Value* v = worklist[i];
// Handle unary ops
if (CastInst* U = dyn_cast<CastInst>(v)) {
bool lhsValid = !isa<Instruction>(U->getOperand(0));
lhsValid |= set.test(VN.lookup(U->getOperand(0)));
if (lhsValid)
lhsValid = !dependsOnInvoke(U->getOperand(0));
if (!lhsValid) {
set.erase(U);
set.reset(VN.lookup(U));
}
// Handle binary ops
} else if (isa<BinaryOperator>(v) || isa<CmpInst>(v) ||
isa<ExtractElementInst>(v)) {
User* U = cast<User>(v);
bool lhsValid = !isa<Instruction>(U->getOperand(0));
lhsValid |= set.test(VN.lookup(U->getOperand(0)));
if (lhsValid)
lhsValid = !dependsOnInvoke(U->getOperand(0));
bool rhsValid = !isa<Instruction>(U->getOperand(1));
rhsValid |= set.test(VN.lookup(U->getOperand(1)));
if (rhsValid)
rhsValid = !dependsOnInvoke(U->getOperand(1));
if (!lhsValid || !rhsValid) {
set.erase(U);
set.reset(VN.lookup(U));
}
// Handle ternary ops
} else if (isa<ShuffleVectorInst>(v) || isa<InsertElementInst>(v) ||
isa<SelectInst>(v)) {
User* U = cast<User>(v);
bool lhsValid = !isa<Instruction>(U->getOperand(0));
lhsValid |= set.test(VN.lookup(U->getOperand(0)));
if (lhsValid)
lhsValid = !dependsOnInvoke(U->getOperand(0));
bool rhsValid = !isa<Instruction>(U->getOperand(1));
rhsValid |= set.test(VN.lookup(U->getOperand(1)));
if (rhsValid)
rhsValid = !dependsOnInvoke(U->getOperand(1));
bool thirdValid = !isa<Instruction>(U->getOperand(2));
thirdValid |= set.test(VN.lookup(U->getOperand(2)));
if (thirdValid)
thirdValid = !dependsOnInvoke(U->getOperand(2));
if (!lhsValid || !rhsValid || !thirdValid) {
set.erase(U);
set.reset(VN.lookup(U));
}
// Handle varargs ops
} else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(v)) {
bool ptrValid = !isa<Instruction>(U->getPointerOperand());
ptrValid |= set.test(VN.lookup(U->getPointerOperand()));
if (ptrValid)
ptrValid = !dependsOnInvoke(U->getPointerOperand());
bool varValid = true;
for (GetElementPtrInst::op_iterator I = U->idx_begin(), E = U->idx_end();
I != E; ++I)
if (varValid) {
varValid &= !isa<Instruction>(*I) || set.test(VN.lookup(*I));
varValid &= !dependsOnInvoke(*I);
}
if (!ptrValid || !varValid) {
set.erase(U);
set.reset(VN.lookup(U));
}
}
}
}
/// topo_sort - Given a set of values, sort them by topological
/// order into the provided vector.
void GVNPRE::topo_sort(ValueNumberedSet& set, SmallVector<Value*, 8>& vec) {
SmallPtrSet<Value*, 16> visited;
SmallVector<Value*, 8> stack;
for (ValueNumberedSet::iterator I = set.begin(), E = set.end();
I != E; ++I) {
if (visited.count(*I) == 0)
stack.push_back(*I);
while (!stack.empty()) {
Value* e = stack.back();
// Handle unary ops
if (CastInst* U = dyn_cast<CastInst>(e)) {
Value* l = find_leader(set, VN.lookup(U->getOperand(0)));
if (l != 0 && isa<Instruction>(l) &&
visited.count(l) == 0)
stack.push_back(l);
else {
vec.push_back(e);
visited.insert(e);
stack.pop_back();
}
// Handle binary ops
} else if (isa<BinaryOperator>(e) || isa<CmpInst>(e) ||
isa<ExtractElementInst>(e)) {
User* U = cast<User>(e);
Value* l = find_leader(set, VN.lookup(U->getOperand(0)));
Value* r = find_leader(set, VN.lookup(U->getOperand(1)));
if (l != 0 && isa<Instruction>(l) &&
visited.count(l) == 0)
stack.push_back(l);
else if (r != 0 && isa<Instruction>(r) &&
visited.count(r) == 0)
stack.push_back(r);
else {
vec.push_back(e);
visited.insert(e);
stack.pop_back();
}
// Handle ternary ops
} else if (isa<InsertElementInst>(e) || isa<ShuffleVectorInst>(e) ||
isa<SelectInst>(e)) {
User* U = cast<User>(e);
Value* l = find_leader(set, VN.lookup(U->getOperand(0)));
Value* r = find_leader(set, VN.lookup(U->getOperand(1)));
Value* m = find_leader(set, VN.lookup(U->getOperand(2)));
if (l != 0 && isa<Instruction>(l) &&
visited.count(l) == 0)
stack.push_back(l);
else if (r != 0 && isa<Instruction>(r) &&
visited.count(r) == 0)
stack.push_back(r);
else if (m != 0 && isa<Instruction>(m) &&
visited.count(m) == 0)
stack.push_back(m);
else {
vec.push_back(e);
visited.insert(e);
stack.pop_back();
}
// Handle vararg ops
} else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(e)) {
Value* p = find_leader(set, VN.lookup(U->getPointerOperand()));
if (p != 0 && isa<Instruction>(p) &&
visited.count(p) == 0)
stack.push_back(p);
else {
bool push_va = false;
for (GetElementPtrInst::op_iterator I = U->idx_begin(),
E = U->idx_end(); I != E; ++I) {
Value * v = find_leader(set, VN.lookup(*I));
if (v != 0 && isa<Instruction>(v) && visited.count(v) == 0) {
stack.push_back(v);
push_va = true;
}
}
if (!push_va) {
vec.push_back(e);
visited.insert(e);
stack.pop_back();
}
}
// Handle opaque ops
} else {
visited.insert(e);
vec.push_back(e);
stack.pop_back();
}
}
stack.clear();
}
}
/// dump - Dump a set of values to standard error
void GVNPRE::dump(ValueNumberedSet& s) const {
DOUT << "{ ";
for (ValueNumberedSet::iterator I = s.begin(), E = s.end();
I != E; ++I) {
DOUT << "" << VN.lookup(*I) << ": ";
DEBUG((*I)->dump());
}
DOUT << "}\n\n";
}
/// elimination - Phase 3 of the main algorithm. Perform full redundancy
/// elimination by walking the dominator tree and removing any instruction that
/// is dominated by another instruction with the same value number.
bool GVNPRE::elimination() {
bool changed_function = false;
SmallVector<std::pair<Instruction*, Value*>, 8> replace;
SmallVector<Instruction*, 8> erase;
DominatorTree& DT = getAnalysis<DominatorTree>();
for (df_iterator<DomTreeNode*> DI = df_begin(DT.getRootNode()),
E = df_end(DT.getRootNode()); DI != E; ++DI) {
BasicBlock* BB = DI->getBlock();
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
BI != BE; ++BI) {
if (isa<BinaryOperator>(BI) || isa<CmpInst>(BI) ||
isa<ShuffleVectorInst>(BI) || isa<InsertElementInst>(BI) ||
isa<ExtractElementInst>(BI) || isa<SelectInst>(BI) ||
isa<CastInst>(BI) || isa<GetElementPtrInst>(BI)) {
if (availableOut[BB].test(VN.lookup(BI)) &&
!availableOut[BB].count(BI)) {
Value *leader = find_leader(availableOut[BB], VN.lookup(BI));
if (Instruction* Instr = dyn_cast<Instruction>(leader))
if (Instr->getParent() != 0 && Instr != BI) {
replace.push_back(std::make_pair(BI, leader));
erase.push_back(BI);
++NumEliminated;
}
}
}
}
}
while (!replace.empty()) {
std::pair<Instruction*, Value*> rep = replace.back();
replace.pop_back();
rep.first->replaceAllUsesWith(rep.second);
changed_function = true;
}
for (SmallVector<Instruction*, 8>::iterator I = erase.begin(),
E = erase.end(); I != E; ++I)
(*I)->eraseFromParent();
return changed_function;
}
/// cleanup - Delete any extraneous values that were created to represent
/// expressions without leaders.
void GVNPRE::cleanup() {
while (!createdExpressions.empty()) {
Instruction* I = createdExpressions.back();
createdExpressions.pop_back();
delete I;
}
}
/// buildsets_availout - When calculating availability, handle an instruction
/// by inserting it into the appropriate sets
void GVNPRE::buildsets_availout(BasicBlock::iterator I,
ValueNumberedSet& currAvail,
ValueNumberedSet& currPhis,
ValueNumberedSet& currExps,
SmallPtrSet<Value*, 16>& currTemps) {
// Handle PHI nodes
if (PHINode* p = dyn_cast<PHINode>(I)) {
unsigned num = VN.lookup_or_add(p);
currPhis.insert(p);
currPhis.set(num);
// Handle unary ops
} else if (CastInst* U = dyn_cast<CastInst>(I)) {
Value* leftValue = U->getOperand(0);
unsigned num = VN.lookup_or_add(U);
if (isa<Instruction>(leftValue))
if (!currExps.test(VN.lookup(leftValue))) {
currExps.insert(leftValue);
currExps.set(VN.lookup(leftValue));
}
if (!currExps.test(num)) {
currExps.insert(U);
currExps.set(num);
}
// Handle binary ops
} else if (isa<BinaryOperator>(I) || isa<CmpInst>(I) ||
isa<ExtractElementInst>(I)) {
User* U = cast<User>(I);
Value* leftValue = U->getOperand(0);
Value* rightValue = U->getOperand(1);
unsigned num = VN.lookup_or_add(U);
if (isa<Instruction>(leftValue))
if (!currExps.test(VN.lookup(leftValue))) {
currExps.insert(leftValue);
currExps.set(VN.lookup(leftValue));
}
if (isa<Instruction>(rightValue))
if (!currExps.test(VN.lookup(rightValue))) {
currExps.insert(rightValue);
currExps.set(VN.lookup(rightValue));
}
if (!currExps.test(num)) {
currExps.insert(U);
currExps.set(num);
}
// Handle ternary ops
} else if (isa<InsertElementInst>(I) || isa<ShuffleVectorInst>(I) ||
isa<SelectInst>(I)) {
User* U = cast<User>(I);
Value* leftValue = U->getOperand(0);
Value* rightValue = U->getOperand(1);
Value* thirdValue = U->getOperand(2);
VN.lookup_or_add(U);
unsigned num = VN.lookup_or_add(U);
if (isa<Instruction>(leftValue))
if (!currExps.test(VN.lookup(leftValue))) {
currExps.insert(leftValue);
currExps.set(VN.lookup(leftValue));
}
if (isa<Instruction>(rightValue))
if (!currExps.test(VN.lookup(rightValue))) {
currExps.insert(rightValue);
currExps.set(VN.lookup(rightValue));
}
if (isa<Instruction>(thirdValue))
if (!currExps.test(VN.lookup(thirdValue))) {
currExps.insert(thirdValue);
currExps.set(VN.lookup(thirdValue));
}
if (!currExps.test(num)) {
currExps.insert(U);
currExps.set(num);
}
// Handle vararg ops
} else if (GetElementPtrInst* U = dyn_cast<GetElementPtrInst>(I)) {
Value* ptrValue = U->getPointerOperand();
VN.lookup_or_add(U);
unsigned num = VN.lookup_or_add(U);
if (isa<Instruction>(ptrValue))
if (!currExps.test(VN.lookup(ptrValue))) {
currExps.insert(ptrValue);
currExps.set(VN.lookup(ptrValue));
}
for (GetElementPtrInst::op_iterator OI = U->idx_begin(), OE = U->idx_end();
OI != OE; ++OI)
if (isa<Instruction>(*OI) && !currExps.test(VN.lookup(*OI))) {
currExps.insert(*OI);
currExps.set(VN.lookup(*OI));
}
if (!currExps.test(VN.lookup(U))) {
currExps.insert(U);
currExps.set(num);
}
// Handle opaque ops
} else if (!I->isTerminator()){
VN.lookup_or_add(I);
currTemps.insert(I);
}
if (!I->isTerminator())
if (!currAvail.test(VN.lookup(I))) {
currAvail.insert(I);
currAvail.set(VN.lookup(I));
}
}
/// buildsets_anticout - When walking the postdom tree, calculate the ANTIC_OUT
/// set as a function of the ANTIC_IN set of the block's predecessors
bool GVNPRE::buildsets_anticout(BasicBlock* BB,
ValueNumberedSet& anticOut,
SmallPtrSet<BasicBlock*, 8>& visited) {
if (BB->getTerminator()->getNumSuccessors() == 1) {
if (BB->getTerminator()->getSuccessor(0) != BB &&
visited.count(BB->getTerminator()->getSuccessor(0)) == 0) {
return true;
}
else {
phi_translate_set(anticipatedIn[BB->getTerminator()->getSuccessor(0)],
BB, BB->getTerminator()->getSuccessor(0), anticOut);
}
} else if (BB->getTerminator()->getNumSuccessors() > 1) {
BasicBlock* first = BB->getTerminator()->getSuccessor(0);
for (ValueNumberedSet::iterator I = anticipatedIn[first].begin(),
E = anticipatedIn[first].end(); I != E; ++I) {
anticOut.insert(*I);
anticOut.set(VN.lookup(*I));
}
for (unsigned i = 1; i < BB->getTerminator()->getNumSuccessors(); ++i) {
BasicBlock* currSucc = BB->getTerminator()->getSuccessor(i);
ValueNumberedSet& succAnticIn = anticipatedIn[currSucc];
SmallVector<Value*, 16> temp;
for (ValueNumberedSet::iterator I = anticOut.begin(),
E = anticOut.end(); I != E; ++I)
if (!succAnticIn.test(VN.lookup(*I)))
temp.push_back(*I);
for (SmallVector<Value*, 16>::iterator I = temp.begin(), E = temp.end();
I != E; ++I) {
anticOut.erase(*I);
anticOut.reset(VN.lookup(*I));
}
}
}
return false;
}
/// buildsets_anticin - Walk the postdom tree, calculating ANTIC_OUT for
/// each block. ANTIC_IN is then a function of ANTIC_OUT and the GEN
/// sets populated in buildsets_availout
unsigned GVNPRE::buildsets_anticin(BasicBlock* BB,
ValueNumberedSet& anticOut,
ValueNumberedSet& currExps,
SmallPtrSet<Value*, 16>& currTemps,
SmallPtrSet<BasicBlock*, 8>& visited) {
ValueNumberedSet& anticIn = anticipatedIn[BB];
unsigned old = anticIn.size();
bool defer = buildsets_anticout(BB, anticOut, visited);
if (defer)
return 0;
anticIn.clear();
for (ValueNumberedSet::iterator I = anticOut.begin(),
E = anticOut.end(); I != E; ++I) {
anticIn.insert(*I);
anticIn.set(VN.lookup(*I));
}
for (ValueNumberedSet::iterator I = currExps.begin(),
E = currExps.end(); I != E; ++I) {
if (!anticIn.test(VN.lookup(*I))) {
anticIn.insert(*I);
anticIn.set(VN.lookup(*I));
}
}
for (SmallPtrSet<Value*, 16>::iterator I = currTemps.begin(),
E = currTemps.end(); I != E; ++I) {
anticIn.erase(*I);
anticIn.reset(VN.lookup(*I));
}
clean(anticIn);
anticOut.clear();
if (old != anticIn.size())
return 2;
else
return 1;
}
/// buildsets - Phase 1 of the main algorithm. Construct the AVAIL_OUT
/// and the ANTIC_IN sets.
void GVNPRE::buildsets(Function& F) {
DenseMap<BasicBlock*, ValueNumberedSet> generatedExpressions;
DenseMap<BasicBlock*, SmallPtrSet<Value*, 16> > generatedTemporaries;
DominatorTree &DT = getAnalysis<DominatorTree>();
// Phase 1, Part 1: calculate AVAIL_OUT
// Top-down walk of the dominator tree
for (df_iterator<DomTreeNode*> DI = df_begin(DT.getRootNode()),
E = df_end(DT.getRootNode()); DI != E; ++DI) {
// Get the sets to update for this block
ValueNumberedSet& currExps = generatedExpressions[DI->getBlock()];
ValueNumberedSet& currPhis = generatedPhis[DI->getBlock()];
SmallPtrSet<Value*, 16>& currTemps = generatedTemporaries[DI->getBlock()];
ValueNumberedSet& currAvail = availableOut[DI->getBlock()];
BasicBlock* BB = DI->getBlock();
// A block inherits AVAIL_OUT from its dominator
if (DI->getIDom() != 0)
currAvail = availableOut[DI->getIDom()->getBlock()];
for (BasicBlock::iterator BI = BB->begin(), BE = BB->end();
BI != BE; ++BI)
buildsets_availout(BI, currAvail, currPhis, currExps,
currTemps);
}
// Phase 1, Part 2: calculate ANTIC_IN
SmallPtrSet<BasicBlock*, 8> visited;
SmallPtrSet<BasicBlock*, 4> block_changed;
for (Function::iterator FI = F.begin(), FE = F.end(); FI != FE; ++FI)
block_changed.insert(FI);
bool changed = true;
unsigned iterations = 0;
while (changed) {
changed = false;
ValueNumberedSet anticOut;
// Postorder walk of the CFG
for (po_iterator<BasicBlock*> BBI = po_begin(&F.getEntryBlock()),
BBE = po_end(&F.getEntryBlock()); BBI != BBE; ++BBI) {
BasicBlock* BB = *BBI;
if (block_changed.count(BB) != 0) {
unsigned ret = buildsets_anticin(BB, anticOut,generatedExpressions[BB],
generatedTemporaries[BB], visited);
if (ret == 0) {
changed = true;
continue;
} else {
visited.insert(BB);
if (ret == 2)
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB);
PI != PE; ++PI) {
block_changed.insert(*PI);
}
else
block_changed.erase(BB);
changed |= (ret == 2);
}
}
}
iterations++;
}
}
/// insertion_pre - When a partial redundancy has been identified, eliminate it
/// by inserting appropriate values into the predecessors and a phi node in
/// the main block
void GVNPRE::insertion_pre(Value* e, BasicBlock* BB,
DenseMap<BasicBlock*, Value*>& avail,
std::map<BasicBlock*, ValueNumberedSet>& new_sets) {
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) {
Value* e2 = avail[*PI];
if (!availableOut[*PI].test(VN.lookup(e2))) {
User* U = cast<User>(e2);
Value* s1 = 0;
if (isa<BinaryOperator>(U->getOperand(0)) ||
isa<CmpInst>(U->getOperand(0)) ||
isa<ShuffleVectorInst>(U->getOperand(0)) ||
isa<ExtractElementInst>(U->getOperand(0)) ||
isa<InsertElementInst>(U->getOperand(0)) ||
isa<SelectInst>(U->getOperand(0)) ||
isa<CastInst>(U->getOperand(0)) ||
isa<GetElementPtrInst>(U->getOperand(0)))
s1 = find_leader(availableOut[*PI], VN.lookup(U->getOperand(0)));
else
s1 = U->getOperand(0);
Value* s2 = 0;
if (isa<BinaryOperator>(U) ||
isa<CmpInst>(U) ||
isa<ShuffleVectorInst>(U) ||
isa<ExtractElementInst>(U) ||
isa<InsertElementInst>(U) ||
isa<SelectInst>(U)) {
if (isa<BinaryOperator>(U->getOperand(1)) ||
isa<CmpInst>(U->getOperand(1)) ||
isa<ShuffleVectorInst>(U->getOperand(1)) ||
isa<ExtractElementInst>(U->getOperand(1)) ||
isa<InsertElementInst>(U->getOperand(1)) ||
isa<SelectInst>(U->getOperand(1)) ||
isa<CastInst>(U->getOperand(1)) ||
isa<GetElementPtrInst>(U->getOperand(1))) {
s2 = find_leader(availableOut[*PI], VN.lookup(U->getOperand(1)));
} else {
s2 = U->getOperand(1);
}
}
// Ternary Operators
Value* s3 = 0;
if (isa<ShuffleVectorInst>(U) ||
isa<InsertElementInst>(U) ||
isa<SelectInst>(U)) {
if (isa<BinaryOperator>(U->getOperand(2)) ||
isa<CmpInst>(U->getOperand(2)) ||
isa<ShuffleVectorInst>(U->getOperand(2)) ||
isa<ExtractElementInst>(U->getOperand(2)) ||
isa<InsertElementInst>(U->getOperand(2)) ||
isa<SelectInst>(U->getOperand(2)) ||
isa<CastInst>(U->getOperand(2)) ||
isa<GetElementPtrInst>(U->getOperand(2))) {
s3 = find_leader(availableOut[*PI], VN.lookup(U->getOperand(2)));
} else {
s3 = U->getOperand(2);
}
}
// Vararg operators
SmallVector<Value*, 4> sVarargs;
if (GetElementPtrInst* G = dyn_cast<GetElementPtrInst>(U)) {
for (GetElementPtrInst::op_iterator OI = G->idx_begin(),
OE = G->idx_end(); OI != OE; ++OI) {
if (isa<BinaryOperator>(*OI) ||
isa<CmpInst>(*OI) ||
isa<ShuffleVectorInst>(*OI) ||
isa<ExtractElementInst>(*OI) ||
isa<InsertElementInst>(*OI) ||
isa<SelectInst>(*OI) ||
isa<CastInst>(*OI) ||
isa<GetElementPtrInst>(*OI)) {
sVarargs.push_back(find_leader(availableOut[*PI],
VN.lookup(*OI)));
} else {
sVarargs.push_back(*OI);
}
}
}
Value* newVal = 0;
if (BinaryOperator* BO = dyn_cast<BinaryOperator>(U))
newVal = BinaryOperator::Create(BO->getOpcode(), s1, s2,
BO->getName()+".gvnpre",
(*PI)->getTerminator());
else if (CmpInst* C = dyn_cast<CmpInst>(U))
newVal = CmpInst::Create(C->getOpcode(), C->getPredicate(), s1, s2,
C->getName()+".gvnpre",
(*PI)->getTerminator());
else if (ShuffleVectorInst* S = dyn_cast<ShuffleVectorInst>(U))
newVal = new ShuffleVectorInst(s1, s2, s3, S->getName()+".gvnpre",
(*PI)->getTerminator());
else if (InsertElementInst* S = dyn_cast<InsertElementInst>(U))
newVal = InsertElementInst::Create(s1, s2, s3, S->getName()+".gvnpre",
(*PI)->getTerminator());
else if (ExtractElementInst* S = dyn_cast<ExtractElementInst>(U))
newVal = new ExtractElementInst(s1, s2, S->getName()+".gvnpre",
(*PI)->getTerminator());
else if (SelectInst* S = dyn_cast<SelectInst>(U))
newVal = SelectInst::Create(s1, s2, s3, S->getName()+".gvnpre",
(*PI)->getTerminator());
else if (CastInst* C = dyn_cast<CastInst>(U))
newVal = CastInst::Create(C->getOpcode(), s1, C->getType(),
C->getName()+".gvnpre",
(*PI)->getTerminator());
else if (GetElementPtrInst* G = dyn_cast<GetElementPtrInst>(U))
newVal = GetElementPtrInst::Create(s1, sVarargs.begin(), sVarargs.end(),
G->getName()+".gvnpre",
(*PI)->getTerminator());
VN.add(newVal, VN.lookup(U));
ValueNumberedSet& predAvail = availableOut[*PI];
val_replace(predAvail, newVal);
val_replace(new_sets[*PI], newVal);
predAvail.set(VN.lookup(newVal));
DenseMap<BasicBlock*, Value*>::iterator av = avail.find(*PI);
if (av != avail.end())
avail.erase(av);
avail.insert(std::make_pair(*PI, newVal));
++NumInsertedVals;
}
}
PHINode* p = 0;
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE; ++PI) {
if (p == 0)
p = PHINode::Create(avail[*PI]->getType(), "gvnpre-join", BB->begin());
p->addIncoming(avail[*PI], *PI);
}
VN.add(p, VN.lookup(e));
val_replace(availableOut[BB], p);
availableOut[BB].set(VN.lookup(e));
generatedPhis[BB].insert(p);
generatedPhis[BB].set(VN.lookup(e));
new_sets[BB].insert(p);
new_sets[BB].set(VN.lookup(e));
++NumInsertedPhis;
}
/// insertion_mergepoint - When walking the dom tree, check at each merge
/// block for the possibility of a partial redundancy. If present, eliminate it
unsigned GVNPRE::insertion_mergepoint(SmallVector<Value*, 8>& workList,
df_iterator<DomTreeNode*>& D,
std::map<BasicBlock*, ValueNumberedSet >& new_sets) {
bool changed_function = false;
bool new_stuff = false;
BasicBlock* BB = D->getBlock();
for (unsigned i = 0; i < workList.size(); ++i) {
Value* e = workList[i];
if (isa<BinaryOperator>(e) || isa<CmpInst>(e) ||
isa<ExtractElementInst>(e) || isa<InsertElementInst>(e) ||
isa<ShuffleVectorInst>(e) || isa<SelectInst>(e) || isa<CastInst>(e) ||
isa<GetElementPtrInst>(e)) {
if (availableOut[D->getIDom()->getBlock()].test(VN.lookup(e)))
continue;
DenseMap<BasicBlock*, Value*> avail;
bool by_some = false;
bool all_same = true;
Value * first_s = 0;
for (pred_iterator PI = pred_begin(BB), PE = pred_end(BB); PI != PE;
++PI) {
Value *e2 = phi_translate(e, *PI, BB);
Value *e3 = find_leader(availableOut[*PI], VN.lookup(e2));
if (e3 == 0) {
DenseMap<BasicBlock*, Value*>::iterator av = avail.find(*PI);
if (av != avail.end())
avail.erase(av);
avail.insert(std::make_pair(*PI, e2));
all_same = false;
} else {
DenseMap<BasicBlock*, Value*>::iterator av = avail.find(*PI);
if (av != avail.end())
avail.erase(av);
avail.insert(std::make_pair(*PI, e3));
by_some = true;
if (first_s == 0)
first_s = e3;
else if (first_s != e3)
all_same = false;
}
}
if (by_some && !all_same &&
!generatedPhis[BB].test(VN.lookup(e))) {
insertion_pre(e, BB, avail, new_sets);
changed_function = true;
new_stuff = true;
}
}
}
unsigned retval = 0;
if (changed_function)
retval += 1;
if (new_stuff)
retval += 2;
return retval;
}
/// insert - Phase 2 of the main algorithm. Walk the dominator tree looking for
/// merge points. When one is found, check for a partial redundancy. If one is
/// present, eliminate it. Repeat this walk until no changes are made.
bool GVNPRE::insertion(Function& F) {
bool changed_function = false;
DominatorTree &DT = getAnalysis<DominatorTree>();
std::map<BasicBlock*, ValueNumberedSet> new_sets;
bool new_stuff = true;
while (new_stuff) {
new_stuff = false;
for (df_iterator<DomTreeNode*> DI = df_begin(DT.getRootNode()),
E = df_end(DT.getRootNode()); DI != E; ++DI) {
BasicBlock* BB = DI->getBlock();
if (BB == 0)
continue;
ValueNumberedSet& availOut = availableOut[BB];
ValueNumberedSet& anticIn = anticipatedIn[BB];
// Replace leaders with leaders inherited from dominator
if (DI->getIDom() != 0) {
ValueNumberedSet& dom_set = new_sets[DI->getIDom()->getBlock()];
for (ValueNumberedSet::iterator I = dom_set.begin(),
E = dom_set.end(); I != E; ++I) {
val_replace(new_sets[BB], *I);
val_replace(availOut, *I);
}
}
// If there is more than one predecessor...
if (pred_begin(BB) != pred_end(BB) && ++pred_begin(BB) != pred_end(BB)) {
SmallVector<Value*, 8> workList;
workList.reserve(anticIn.size());
topo_sort(anticIn, workList);
unsigned result = insertion_mergepoint(workList, DI, new_sets);
if (result & 1)
changed_function = true;
if (result & 2)
new_stuff = true;
}
}
}
return changed_function;
}
// GVNPRE::runOnFunction - This is the main transformation entry point for a
// function.
//
bool GVNPRE::runOnFunction(Function &F) {
// Clean out global sets from any previous functions
VN.clear();
createdExpressions.clear();
availableOut.clear();
anticipatedIn.clear();
generatedPhis.clear();
bool changed_function = false;
// Phase 1: BuildSets
// This phase calculates the AVAIL_OUT and ANTIC_IN sets
buildsets(F);
// Phase 2: Insert
// This phase inserts values to make partially redundant values
// fully redundant
changed_function |= insertion(F);
// Phase 3: Eliminate
// This phase performs trivial full redundancy elimination
changed_function |= elimination();
// Phase 4: Cleanup
// This phase cleans up values that were created solely
// as leaders for expressions
cleanup();
return changed_function;
}