blob: a034c92d51ccd7313731eee0475ddf7f7cc5a3da [file] [log] [blame]
//===- llvm/Analysis/InstForest.h - Partition Func into forest --*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file was developed by the LLVM research group and is distributed under
// the University of Illinois Open Source License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This interface is used to partition a method into a forest of instruction
// trees, where the following invariants hold:
//
// 1. The instructions in a tree are all related to each other through use
// relationships.
// 2. All instructions in a tree are members of the same basic block
// 3. All instructions in a tree (with the exception of the root), may have only
// a single user.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_INSTFOREST_H
#define LLVM_ANALYSIS_INSTFOREST_H
#include "llvm/Function.h"
#include "Support/Tree.h"
#include <map>
template<class Payload> class InstTreeNode;
template<class Payload> class InstForest;
//===----------------------------------------------------------------------===//
// Class InstTreeNode
//===----------------------------------------------------------------------===//
//
// There is an instance of this class for each node in the instruction forest.
// There should be a node for every instruction in the tree, as well as
// Temporary nodes that correspond to other trees in the forest and to variables
// and global variables. Constants have their own special node.
//
template<class Payload>
class InstTreeNode :
public Tree<InstTreeNode<Payload>,
std::pair<std::pair<Value*, char>, Payload> > {
friend class InstForest<Payload>;
typedef Tree<InstTreeNode<Payload>,
std::pair<std::pair<Value*, char>, Payload> > super;
// Constants used for the node type value
enum NodeTypeTy {
ConstNode = Value::ConstantVal,
BasicBlockNode = Value::BasicBlockVal,
InstructionNode = Value::InstructionVal,
TemporaryNode = -1
};
// Helper functions to make accessing our data nicer...
const Value *getValue() const { return getTreeData().first.first; }
Value *getValue() { return getTreeData().first.first; }
enum NodeTypeTy getNodeType() const {
return (enum NodeTypeTy)getTreeData().first.second;
}
InstTreeNode(const InstTreeNode &); // Do not implement
void operator=(const InstTreeNode &); // Do not implement
// Only creatable by InstForest
InstTreeNode(InstForest<Payload> &IF, Value *V, InstTreeNode *Parent);
bool CanMergeInstIntoTree(Instruction *Inst);
public:
// Accessor functions...
inline Payload &getData() { return getTreeData().second; }
inline const Payload &getData() const { return getTreeData().second; }
// Type checking functions...
inline bool isConstant() const { return getNodeType() == ConstNode; }
inline bool isBasicBlock() const { return getNodeType() == BasicBlockNode; }
inline bool isInstruction() const { return getNodeType() == InstructionNode; }
inline bool isTemporary() const { return getNodeType() == TemporaryNode; }
// Accessors for different node types...
inline Constant *getConstant() {
return cast<Constant>(getValue());
}
inline const Constant *getConstant() const {
return cast<Constant>(getValue());
}
inline BasicBlock *getBasicBlock() {
return cast<BasicBlock>(getValue());
}
inline const BasicBlock *getBasicBlock() const {
return cast<BasicBlock>(getValue());
}
inline Instruction *getInstruction() {
assert(isInstruction() && "getInstruction() on non instruction node!");
return cast<Instruction>(getValue());
}
inline const Instruction *getInstruction() const {
assert(isInstruction() && "getInstruction() on non instruction node!");
return cast<Instruction>(getValue());
}
inline Instruction *getTemporary() {
assert(isTemporary() && "getTemporary() on non temporary node!");
return cast<Instruction>(getValue());
}
inline const Instruction *getTemporary() const {
assert(isTemporary() && "getTemporary() on non temporary node!");
return cast<Instruction>(getValue());
}
public:
// print - Called by operator<< below...
void print(std::ostream &o, unsigned Indent) const {
o << std::string(Indent*2, ' ');
switch (getNodeType()) {
case ConstNode : o << "Constant : "; break;
case BasicBlockNode : o << "BasicBlock : " << getValue()->getName() << "\n";
return;
case InstructionNode: o << "Instruction: "; break;
case TemporaryNode : o << "Temporary : "; break;
default: o << "UNKNOWN NODE TYPE: " << getNodeType() << "\n"; abort();
}
o << getValue();
if (!isa<Instruction>(getValue())) o << "\n";
for (unsigned i = 0; i < getNumChildren(); ++i)
getChild(i)->print(o, Indent+1);
}
};
template<class Payload>
inline std::ostream &operator<<(std::ostream &o,
const InstTreeNode<Payload> *N) {
N->print(o, 0); return o;
}
//===----------------------------------------------------------------------===//
// Class InstForest
//===----------------------------------------------------------------------===//
//
// This class represents the instruction forest itself. It exposes iterators
// to an underlying vector of Instruction Trees. Each root of the tree is
// guaranteed to be an instruction node. The constructor builds the forest.
//
template<class Payload>
class InstForest : public std::vector<InstTreeNode<Payload> *> {
friend class InstTreeNode<Payload>;
typedef typename std::vector<InstTreeNode<Payload> *>::const_iterator const_iterator;
// InstMap - Map contains entries for ALL instructions in the method and the
// InstTreeNode that they correspond to.
//
std::map<Instruction*, InstTreeNode<Payload> *> InstMap;
void addInstMapping(Instruction *I, InstTreeNode<Payload> *IN) {
InstMap.insert(std::make_pair(I, IN));
}
void removeInstFromRootList(Instruction *I) {
for (unsigned i = size(); i > 0; --i)
if (operator[](i-1)->getValue() == I) {
erase(begin()+i-1);
return;
}
}
public:
// ctor - Create an instruction forest for the specified method...
InstForest(Function *F) {
for (Function::iterator BB = F->begin(), BBE = F->end(); BB != BBE; ++BB)
for (BasicBlock::iterator I = BB->begin(), E = BB->end(); I != E; ++I)
if (!getInstNode(I)) { // Do we already have a tree for this inst?
// No, create one! InstTreeNode ctor automatically adds the
// created node into our InstMap
push_back(new InstTreeNode<Payload>(*this, I, 0));
}
}
// dtor - Free the trees...
~InstForest() {
for (unsigned i = size(); i != 0; --i)
delete operator[](i-1);
}
// getInstNode - Return the instruction node that corresponds to the specified
// instruction... This node may be embeded in a larger tree, in which case
// the parent pointer can be used to find the root of the tree.
//
inline InstTreeNode<Payload> *getInstNode(Instruction *Inst) {
typename std::map<Instruction*, InstTreeNode<Payload> *>::iterator I =
InstMap.find(Inst);
if (I != InstMap.end()) return I->second;
return 0;
}
inline const InstTreeNode<Payload> *getInstNode(const Instruction *Inst)const{
typename std::map<Instruction*, InstTreeNode<Payload>*>::const_iterator I =
InstMap.find(Inst);
if (I != InstMap.end()) return I->second;
return 0;
}
// print - Called by operator<< below...
void print(std::ostream &out) const {
for (const_iterator I = begin(), E = end(); I != E; ++I)
out << *I;
}
};
template<class Payload>
inline std::ostream &operator<<(std::ostream &o, const InstForest<Payload> &IF){
IF.print(o); return o;
}
//===----------------------------------------------------------------------===//
// Method Implementations
//===----------------------------------------------------------------------===//
// CanMergeInstIntoTree - Return true if it is allowed to merge the specified
// instruction into 'this' instruction tree. This is allowed iff:
// 1. The instruction is in the same basic block as the current one
// 2. The instruction has only one use
//
template <class Payload>
bool InstTreeNode<Payload>::CanMergeInstIntoTree(Instruction *I) {
if (!I->use_empty() && !I->hasOneUse()) return false;
return I->getParent() == cast<Instruction>(getValue())->getParent();
}
// InstTreeNode ctor - This constructor creates the instruction tree for the
// specified value. If the value is an instruction, it recursively creates the
// internal/child nodes and adds them to the instruction forest.
//
template <class Payload>
InstTreeNode<Payload>::InstTreeNode(InstForest<Payload> &IF, Value *V,
InstTreeNode *Parent) : super(Parent) {
getTreeData().first.first = V; // Save tree node
if (!isa<Instruction>(V)) {
assert((isa<Constant>(V) || isa<BasicBlock>(V) ||
isa<Argument>(V) || isa<GlobalValue>(V)) &&
"Unrecognized value type for InstForest Partition!");
if (isa<Constant>(V))
getTreeData().first.second = ConstNode;
else if (isa<BasicBlock>(V))
getTreeData().first.second = BasicBlockNode;
else
getTreeData().first.second = TemporaryNode;
return;
}
// Must be an instruction then... see if we can include it in this tree!
Instruction *I = cast<Instruction>(V);
if (Parent && !Parent->CanMergeInstIntoTree(I)) {
// Not root node of tree, but mult uses?
getTreeData().first.second = TemporaryNode; // Must be a temporary!
return;
}
// Otherwise, we are an internal instruction node. We must process our
// uses and add them as children of this node.
//
std::vector<InstTreeNode*> Children;
// Make sure that the forest knows about us!
IF.addInstMapping(I, this);
// Walk the operands of the instruction adding children for all of the uses
// of the instruction...
//
for (Instruction::op_iterator OI = I->op_begin(); OI != I->op_end(); ++OI) {
Value *Operand = *OI;
InstTreeNode<Payload> *IN = IF.getInstNode(dyn_cast<Instruction>(Operand));
if (IN && CanMergeInstIntoTree(cast<Instruction>(Operand))) {
Children.push_back(IN);
IF.removeInstFromRootList(cast<Instruction>(Operand));
} else {
// No node for this child yet... create one now!
Children.push_back(new InstTreeNode(IF, *OI, this));
}
}
setChildren(Children);
getTreeData().first.second = InstructionNode;
}
#endif