blob: edb5119f00d6933419fd4c5883cee2c134b1987a [file] [log] [blame]
//===- PgmDependenceGraph.h - Enumerate the PDG for a function --*- 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.
//
//===----------------------------------------------------------------------===//
//
// The Program Dependence Graph (PDG) for a single function represents all
// data and control dependences for the function. This file provides an
// iterator to enumerate all these dependences. In particular, it enumerates:
//
// -- Data dependences on memory locations, computed using the
// MemoryDepAnalysis pass;
// -- Data dependences on SSA registers, directly from Def-Use edges of Values;
// -- Control dependences, computed using postdominance frontiers
// (NOT YET IMPLEMENTED).
//
// Note that this file does not create an explicit dependence graph --
// it only provides an iterator to traverse the PDG conceptually.
// The MemoryDepAnalysis does build an explicit graph, which is used internally
// here. That graph could be augmented with the other dependences above if
// desired, but for most uses there will be little need to do that.
//
// Key Classes:
//
// enum PDGIteratorFlags -- Specify which dependences to enumerate.
//
// class PDGIterator -- The PDG iterator. This is essentially like a
// pointer to class Dependence, but doesn't explicitly
// construct a Dependence object for each dependence.
//
// class PgmDependenceGraph -- Interface to obtain PDGIterators for each
// instruction.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H
#define LLVM_ANALYSIS_PGMDEPENDENCEGRAPH_H
#include "llvm/Analysis/DependenceGraph.h"
#include "llvm/Analysis/MemoryDepAnalysis.h"
/* #include "llvm/Analysis/PostDominators.h" -- see below */
#include "llvm/Instruction.h"
#include "llvm/Pass.h"
#include "Support/iterator"
class DSGraph;
class DependenceGraph;
class PgmDependenceGraph;
///---------------------------------------------------------------------------
/// enum PDGIteratorFlags
///
/// These bit flags specify which dependences incident on a statement are to be
/// enumerated: Memory deps, SSA deps, Control deps, or any combination thereof.
///---------------------------------------------------------------------------
enum PDGIteratorFlags {
MemoryDeps = 0x1, // load/store/call deps
SSADeps = 0x2, // SSA deps (true)
ControlDeps = /* 0x4*/ 0x0, // control dependences
AllDataDeps = MemoryDeps | SSADeps, // shorthand for data deps
AllDeps = MemoryDeps | SSADeps | ControlDeps // shorthand for all three
};
///---------------------------------------------------------------------------
/// struct DepIterState
///
/// This data type is primarily an internal implementation detail.
/// It are exposed here only to give inlinable access to field dep,
/// which is the representation for the current dependence pointed to by
/// a PgmDependenceGraph::iterator.
///---------------------------------------------------------------------------
class DepIterState {
private:
typedef char IterStateFlags;
static const IterStateFlags NoFlag, MemDone, SSADone, AllDone, FirstTimeFlag;
public:
DepGraphNode* depNode; // the node being enumerated
DependenceGraph::iterator memDepIter; // pointer to current memory dep
Instruction::op_iterator ssaInEdgeIter; // pointer to current SSA in-dep
Value::use_iterator ssaOutEdgeIter; // pointer to current SSA out-dep
DependenceGraph* memDepGraph; // the core dependence graph
Dependence dep; // the "current" dependence
PDGIteratorFlags depFlags:8; // which deps are we enumerating?
IterStateFlags iterFlags:8; // marking where the iter stands
/*ctor*/ DepIterState (DependenceGraph* _memDepGraph,
Instruction& I,
bool incomingDeps,
PDGIteratorFlags whichDeps);
bool operator==(const DepIterState& S) {
assert(memDepGraph == S.memDepGraph &&
"Incompatible iterators! This is a probable sign of something BAD.");
return (iterFlags == S.iterFlags &&
dep == S.dep && depFlags == S.depFlags && depNode == S.depNode &&
memDepIter == S.memDepIter && ssaInEdgeIter == S.ssaInEdgeIter &&
ssaOutEdgeIter == S.ssaOutEdgeIter);
}
// Is the iteration completely done?
//
bool done () const { return iterFlags & AllDone; }
// Bump this iterator logically by 1 (to next dependence) and reset the
// dep field to represent the new dependence if there is one.
// Set done = true otherwise.
//
void Next ();
// Find the first memory dependence for the current Mem In/Out iterators.
// Sets dep to that dependence and returns true if one is found.
// Returns false and leaves dep unchanged otherwise.
//
bool SetFirstMemoryDep();
// Find the next valid data dependence for the current SSA In/Out iterators.
// A valid data dependence is one that is to/from an Instruction.
// E.g., an SSA edge from a formal parameter is not a valid dependence.
// Sets dep to that dependence and returns true if a valid one is found.
// Returns false and leaves dep unchanged otherwise.
//
bool SetFirstSSADep ();
};
///---------------------------------------------------------------------------
/// The dependence iterator class. This class represents a pointer to
/// a single dependence in the program dependence graph. It is essentially
/// like a pointer to an object of class Dependence but it is much more
/// efficient to retrieve information about the dependence directly rather
/// than constructing the equivalent Dependence object (since that object
/// is normally not constructed for SSA def-use dependences).
///---------------------------------------------------------------------------
class PDGIterator: public forward_iterator<Dependence, ptrdiff_t> {
DepIterState* istate;
#if 0
/*copy*/ PDGIterator (const PDGIterator& I); // do not implement!
PDGIterator& operator= (const PDGIterator& I); // do not implement!
/*copy*/ PDGIterator (PDGIterator& I) : istate(I.istate) {
I.istate = NULL; // ensure this is not deleted twice.
}
#endif
friend class PgmDependenceGraph;
public:
typedef PDGIterator _Self;
/*ctor*/ PDGIterator (DepIterState* _istate) : istate(_istate) { }
/*dtor*/ ~PDGIterator () { delete istate; }
/*copy*/ PDGIterator (const PDGIterator& I)
: istate(new DepIterState(*I.istate)) { }
PDGIterator& operator= (const PDGIterator& I) {
if (istate) delete istate;
istate = new DepIterState(*I.istate);
return *this;
}
// Check if the iteration is complete
//
bool fini() const { return !istate || istate->done(); }
// Retrieve the underlying Dependence. Returns NULL if fini().
//
Dependence* operator*() const { return fini() ? NULL : &istate->dep; }
Dependence* operator->() const { assert(!fini()); return &istate->dep; }
// Increment the iterator
//
_Self& operator++() { if (!fini()) istate->Next(); return *this;}
_Self& operator++(int); // do not implement!
// Equality comparison: a "null" state should compare equal to done
// This is efficient for comparing with "end" or with itself, but could
// be quite inefficient for other cases.
//
bool operator==(const PDGIterator& I) const {
if (I.istate == NULL) // most common case: iter == end()
return (istate == NULL || istate->done());
if (istate == NULL)
return (I.istate == NULL || I.istate->done());
return (*istate == *I.istate);
}
bool operator!=(const PDGIterator& I) const {
return ! (*this == I);
}
};
///---------------------------------------------------------------------------
/// class PgmDependenceGraph:
///
/// This pass enumerates dependences incident on each instruction in a function.
/// It can be made a FunctionPass once a Pass (such as Parallelize) is
/// allowed to use a FunctionPass such as this one.
///---------------------------------------------------------------------------
class PgmDependenceGraph: public Pass {
/// Information about the function being analyzed.
///
DependenceGraph* memDepGraph;
// print helper function.
void printOutgoingSSADeps(Instruction& I, std::ostream &O);
// MakeIterator --
// The first version creates and initializes an iterator as specified.
// The second version creates a null iterator representing end-of-iteration.
//
PDGIterator MakeIterator (Instruction& I,
bool incomingDeps,
PDGIteratorFlags whichDeps);
PDGIterator MakeIterator () { return PDGIterator(NULL); }
friend class PDGIterator;
friend class DepIterState;
public:
typedef PDGIterator iterator;
/* typedef PDGIterator<const Dependence> const iterator; */
public:
PgmDependenceGraph() : memDepGraph(NULL) { }
~PgmDependenceGraph() { }
/// Iterators to enumerate the program dependence graph for a function.
/// Note that this does not provide "end" iterators to check for completion.
/// Instead, just use iterator::fini() or iterator::operator*() == NULL
//
iterator inDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
return MakeIterator(I, /*inDeps*/ true, whichDeps);
}
iterator inDepEnd (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
return MakeIterator();
}
iterator outDepBegin(Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
return MakeIterator(I, /*inDeps*/ false, whichDeps);
}
iterator outDepEnd (Instruction& I, PDGIteratorFlags whichDeps = AllDeps) {
return MakeIterator();
}
///------------------------------------------------------------------------
/// TEMPORARY FUNCTIONS TO MAKE THIS A MODULE PASS ---
/// These functions will go away once this class becomes a FunctionPass.
/// Driver function to compute dependence graphs for every function.
///
bool run(Module& M) { return true; }
/// getGraph() -- Retrieve the pgm dependence graph for a function.
/// This is temporary and will go away once this is a FunctionPass.
/// At that point, this class itself will be the PgmDependenceGraph you want.
///
PgmDependenceGraph& getGraph(Function& F) {
Visiting(F);
return *this;
}
private:
void Visiting(Function& F) {
memDepGraph = &getAnalysis<MemoryDepAnalysis>().getGraph(F);
}
public:
///----END TEMPORARY FUNCTIONS---------------------------------------------
/// This initializes the program dependence graph iterator for a function.
///
bool runOnFunction(Function& func) {
Visiting(func);
return true;
}
/// getAnalysisUsage - This does not modify anything.
/// It uses the Memory Dependence Analysis pass.
/// It needs to use the PostDominanceFrontier pass, but cannot because
/// that is a FunctionPass. This means control dependence are not emumerated.
///
void getAnalysisUsage(AnalysisUsage &AU) const {
AU.setPreservesAll();
AU.addRequired<MemoryDepAnalysis>();
/* AU.addRequired<PostDominanceFrontier>(); */
}
/// Debugging support methods
///
void print(std::ostream &O) const;
void dump() const;
};
//===----------------------------------------------------------------------===//
#endif