mirror of
https://github.com/c64scene-ar/llvm-6502.git
synced 2025-06-21 18:24:23 +00:00
Iterator that enumerates the ProgramDependenceGraph (PDG) for a function,
i.e., enumerates all data and control dependences for the function. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@4958 91177308-0d34-0410-b5e6-96231b3b80d8
This commit is contained in:
308
include/llvm/Analysis/PgmDependenceGraph.h
Normal file
308
include/llvm/Analysis/PgmDependenceGraph.h
Normal file
@ -0,0 +1,308 @@
|
|||||||
|
//===- PgmDependenceGraph.h - Enumerate the PDG for a function --*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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/Value.h"
|
||||||
|
#include "llvm/Pass.h"
|
||||||
|
#include "Support/NonCopyable.h"
|
||||||
|
#include <iterator>
|
||||||
|
|
||||||
|
|
||||||
|
class Instruction;
|
||||||
|
class Function;
|
||||||
|
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
|
250
lib/Analysis/DataStructure/PgmDependenceGraph.cpp
Normal file
250
lib/Analysis/DataStructure/PgmDependenceGraph.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
//===- PgmDependenceGraph.cpp - Enumerate PDG for a function ----*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/Analysis/PgmDependenceGraph.h"
|
||||||
|
#include "llvm/Analysis/MemoryDepAnalysis.h"
|
||||||
|
#include "llvm/Analysis/PostDominators.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
|
#include "llvm/BasicBlock.h"
|
||||||
|
#include "llvm/Instruction.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// class DepIterState
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const DepIterState::IterStateFlags DepIterState::NoFlag = 0x0;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::MemDone = 0x1;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::SSADone = 0x2;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::AllDone = 0x4;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::FirstTimeFlag= 0x8;
|
||||||
|
|
||||||
|
// Find the first memory dependence for the current Mem In/Out iterators.
|
||||||
|
// Find the first memory dependence for the current Mem In/Out iterators.
|
||||||
|
// Sets dep to that dependence and returns true if one is found.
|
||||||
|
//
|
||||||
|
bool DepIterState::SetFirstMemoryDep()
|
||||||
|
{
|
||||||
|
if (! (depFlags & MemoryDeps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
|
||||||
|
if (( doIncomingDeps && memDepIter == memDepGraph->inDepEnd( *depNode)) ||
|
||||||
|
(!doIncomingDeps && memDepIter == memDepGraph->outDepEnd(*depNode)))
|
||||||
|
{
|
||||||
|
iterFlags |= MemDone;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dep = *memDepIter; // simple copy from dependence in memory DepGraph
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find the first 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 DepIterState::SetFirstSSADep()
|
||||||
|
{
|
||||||
|
if (! (depFlags & SSADeps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
Instruction* firstTarget = NULL;
|
||||||
|
|
||||||
|
// Increment the In or Out iterator till it runs out or we find a valid dep
|
||||||
|
if (doIncomingDeps)
|
||||||
|
for (Instruction::op_iterator E = depNode->getInstr().op_end();
|
||||||
|
ssaInEdgeIter != E &&
|
||||||
|
(firstTarget = dyn_cast<Instruction>(ssaInEdgeIter->get()))== NULL; )
|
||||||
|
++ssaInEdgeIter;
|
||||||
|
else
|
||||||
|
for (Value::use_iterator E = depNode->getInstr().use_end();
|
||||||
|
ssaOutEdgeIter != E &&
|
||||||
|
(firstTarget = dyn_cast<Instruction>(*ssaOutEdgeIter)) == NULL; )
|
||||||
|
++ssaOutEdgeIter;
|
||||||
|
|
||||||
|
// If the iterator ran out before we found a valid dep, there isn't one.
|
||||||
|
if (!firstTarget)
|
||||||
|
{
|
||||||
|
iterFlags |= SSADone;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a simple dependence object to represent this SSA dependence.
|
||||||
|
dep = Dependence(memDepGraph->getNode(*firstTarget, /*create*/ true),
|
||||||
|
TrueDependence, doIncomingDeps);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DepIterState::DepIterState(DependenceGraph* _memDepGraph,
|
||||||
|
Instruction& I,
|
||||||
|
bool incomingDeps,
|
||||||
|
PDGIteratorFlags whichDeps)
|
||||||
|
: memDepGraph(_memDepGraph),
|
||||||
|
depFlags(whichDeps),
|
||||||
|
iterFlags(NoFlag)
|
||||||
|
{
|
||||||
|
depNode = memDepGraph->getNode(I, /*create*/ true);
|
||||||
|
|
||||||
|
if (incomingDeps)
|
||||||
|
{
|
||||||
|
if (whichDeps & MemoryDeps) memDepIter= memDepGraph->inDepBegin(*depNode);
|
||||||
|
if (whichDeps & SSADeps) ssaInEdgeIter = I.op_begin();
|
||||||
|
/* Initialize control dependence iterator here. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (whichDeps & MemoryDeps) memDepIter=memDepGraph->outDepBegin(*depNode);
|
||||||
|
if (whichDeps & SSADeps) ssaOutEdgeIter = I.use_begin();
|
||||||
|
/* Initialize control dependence iterator here. */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the dependence to the first of a memory dep or an SSA dep
|
||||||
|
// and set the done flag if either is found. Otherwise, set the
|
||||||
|
// init flag to indicate that the iterators have just been initialized.
|
||||||
|
//
|
||||||
|
if (!SetFirstMemoryDep() && !SetFirstSSADep())
|
||||||
|
iterFlags |= AllDone;
|
||||||
|
else
|
||||||
|
iterFlags |= FirstTimeFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function for ++ operator that bumps iterator by 1 (to next
|
||||||
|
// dependence) and resets the dep field to represent the new dependence.
|
||||||
|
//
|
||||||
|
void DepIterState::Next()
|
||||||
|
{
|
||||||
|
// firstMemDone and firstSsaDone are used to indicate when the memory or
|
||||||
|
// SSA iterators just ran out, or when this is the very first increment.
|
||||||
|
// In either case, the next iterator (if any) should not be incremented.
|
||||||
|
//
|
||||||
|
bool firstMemDone = iterFlags & FirstTimeFlag;
|
||||||
|
bool firstSsaDone = iterFlags & FirstTimeFlag;
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
|
||||||
|
if (depFlags & MemoryDeps && ! (iterFlags & MemDone))
|
||||||
|
{
|
||||||
|
iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
++memDepIter;
|
||||||
|
if (SetFirstMemoryDep())
|
||||||
|
return;
|
||||||
|
firstMemDone = true; // flags that we _just_ rolled over
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depFlags & SSADeps && ! (iterFlags & SSADone))
|
||||||
|
{
|
||||||
|
// Don't increment the SSA iterator if we either just rolled over from
|
||||||
|
// the memory dep iterator, or if the SSA iterator is already done.
|
||||||
|
iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
if (! firstMemDone)
|
||||||
|
if (doIncomingDeps) ++ssaInEdgeIter;
|
||||||
|
else ++ssaOutEdgeIter;
|
||||||
|
if (SetFirstSSADep())
|
||||||
|
return;
|
||||||
|
firstSsaDone = true; // flags if we just rolled over
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depFlags & ControlDeps != 0)
|
||||||
|
{
|
||||||
|
assert(0 && "Cannot handle control deps");
|
||||||
|
// iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// This iterator is now complete.
|
||||||
|
iterFlags |= AllDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// class PgmDependenceGraph
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// MakeIterator -- Create and initialize an iterator as specified.
|
||||||
|
//
|
||||||
|
PDGIterator PgmDependenceGraph::MakeIterator(Instruction& I,
|
||||||
|
bool incomingDeps,
|
||||||
|
PDGIteratorFlags whichDeps)
|
||||||
|
{
|
||||||
|
assert(memDepGraph && "Function not initialized!");
|
||||||
|
return PDGIterator(new DepIterState(memDepGraph, I, incomingDeps, whichDeps));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::printOutgoingSSADeps(Instruction& I,
|
||||||
|
std::ostream &O)
|
||||||
|
{
|
||||||
|
iterator SI = this->outDepBegin(I, SSADeps);
|
||||||
|
iterator SE = this->outDepEnd(I, SSADeps);
|
||||||
|
if (SI == SE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
O << "\n Outgoing SSA dependences:\n";
|
||||||
|
for ( ; SI != SE; ++SI)
|
||||||
|
{
|
||||||
|
O << "\t";
|
||||||
|
SI->print(O);
|
||||||
|
O << " to instruction:";
|
||||||
|
O << SI->getSink()->getInstr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::print(std::ostream &O) const
|
||||||
|
{
|
||||||
|
MemoryDepAnalysis& graphSet = getAnalysis<MemoryDepAnalysis>();
|
||||||
|
|
||||||
|
// TEMPORARY LOOP
|
||||||
|
for (hash_map<Function*, DependenceGraph*>::iterator
|
||||||
|
I = graphSet.funcMap.begin(), E = graphSet.funcMap.end();
|
||||||
|
I != E; ++I)
|
||||||
|
{
|
||||||
|
Function* func = I->first;
|
||||||
|
DependenceGraph* depGraph = I->second;
|
||||||
|
const_cast<PgmDependenceGraph*>(this)->runOnFunction(*func);
|
||||||
|
|
||||||
|
O << "DEPENDENCE GRAPH FOR FUNCTION " << func->getName() << ":\n";
|
||||||
|
for (Function::iterator BB=func->begin(), FE=func->end(); BB != FE; ++BB)
|
||||||
|
for (BasicBlock::iterator II=BB->begin(), IE=BB->end(); II !=IE; ++II)
|
||||||
|
{
|
||||||
|
DepGraphNode* dgNode = depGraph->getNode(*II, /*create*/ true);
|
||||||
|
dgNode->print(O);
|
||||||
|
const_cast<PgmDependenceGraph*>(this)->printOutgoingSSADeps(*II, O);
|
||||||
|
}
|
||||||
|
} // END TEMPORARY LOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::dump() const
|
||||||
|
{
|
||||||
|
this->print(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterAnalysis<PgmDependenceGraph>
|
||||||
|
Z("pgmdep", "Enumerate Program Dependence Graph (data and control)");
|
250
lib/Analysis/IPA/PgmDependenceGraph.cpp
Normal file
250
lib/Analysis/IPA/PgmDependenceGraph.cpp
Normal file
@ -0,0 +1,250 @@
|
|||||||
|
//===- PgmDependenceGraph.cpp - Enumerate PDG for a function ----*- C++ -*-===//
|
||||||
|
//
|
||||||
|
// 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.
|
||||||
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
||||||
|
#include "llvm/Analysis/PgmDependenceGraph.h"
|
||||||
|
#include "llvm/Analysis/MemoryDepAnalysis.h"
|
||||||
|
#include "llvm/Analysis/PostDominators.h"
|
||||||
|
#include "llvm/Function.h"
|
||||||
|
#include "llvm/BasicBlock.h"
|
||||||
|
#include "llvm/Instruction.h"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// class DepIterState
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
const DepIterState::IterStateFlags DepIterState::NoFlag = 0x0;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::MemDone = 0x1;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::SSADone = 0x2;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::AllDone = 0x4;
|
||||||
|
const DepIterState::IterStateFlags DepIterState::FirstTimeFlag= 0x8;
|
||||||
|
|
||||||
|
// Find the first memory dependence for the current Mem In/Out iterators.
|
||||||
|
// Find the first memory dependence for the current Mem In/Out iterators.
|
||||||
|
// Sets dep to that dependence and returns true if one is found.
|
||||||
|
//
|
||||||
|
bool DepIterState::SetFirstMemoryDep()
|
||||||
|
{
|
||||||
|
if (! (depFlags & MemoryDeps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
|
||||||
|
if (( doIncomingDeps && memDepIter == memDepGraph->inDepEnd( *depNode)) ||
|
||||||
|
(!doIncomingDeps && memDepIter == memDepGraph->outDepEnd(*depNode)))
|
||||||
|
{
|
||||||
|
iterFlags |= MemDone;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
dep = *memDepIter; // simple copy from dependence in memory DepGraph
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Find the first 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 DepIterState::SetFirstSSADep()
|
||||||
|
{
|
||||||
|
if (! (depFlags & SSADeps))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
Instruction* firstTarget = NULL;
|
||||||
|
|
||||||
|
// Increment the In or Out iterator till it runs out or we find a valid dep
|
||||||
|
if (doIncomingDeps)
|
||||||
|
for (Instruction::op_iterator E = depNode->getInstr().op_end();
|
||||||
|
ssaInEdgeIter != E &&
|
||||||
|
(firstTarget = dyn_cast<Instruction>(ssaInEdgeIter->get()))== NULL; )
|
||||||
|
++ssaInEdgeIter;
|
||||||
|
else
|
||||||
|
for (Value::use_iterator E = depNode->getInstr().use_end();
|
||||||
|
ssaOutEdgeIter != E &&
|
||||||
|
(firstTarget = dyn_cast<Instruction>(*ssaOutEdgeIter)) == NULL; )
|
||||||
|
++ssaOutEdgeIter;
|
||||||
|
|
||||||
|
// If the iterator ran out before we found a valid dep, there isn't one.
|
||||||
|
if (!firstTarget)
|
||||||
|
{
|
||||||
|
iterFlags |= SSADone;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Create a simple dependence object to represent this SSA dependence.
|
||||||
|
dep = Dependence(memDepGraph->getNode(*firstTarget, /*create*/ true),
|
||||||
|
TrueDependence, doIncomingDeps);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
DepIterState::DepIterState(DependenceGraph* _memDepGraph,
|
||||||
|
Instruction& I,
|
||||||
|
bool incomingDeps,
|
||||||
|
PDGIteratorFlags whichDeps)
|
||||||
|
: memDepGraph(_memDepGraph),
|
||||||
|
depFlags(whichDeps),
|
||||||
|
iterFlags(NoFlag)
|
||||||
|
{
|
||||||
|
depNode = memDepGraph->getNode(I, /*create*/ true);
|
||||||
|
|
||||||
|
if (incomingDeps)
|
||||||
|
{
|
||||||
|
if (whichDeps & MemoryDeps) memDepIter= memDepGraph->inDepBegin(*depNode);
|
||||||
|
if (whichDeps & SSADeps) ssaInEdgeIter = I.op_begin();
|
||||||
|
/* Initialize control dependence iterator here. */
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
if (whichDeps & MemoryDeps) memDepIter=memDepGraph->outDepBegin(*depNode);
|
||||||
|
if (whichDeps & SSADeps) ssaOutEdgeIter = I.use_begin();
|
||||||
|
/* Initialize control dependence iterator here. */
|
||||||
|
}
|
||||||
|
|
||||||
|
// Set the dependence to the first of a memory dep or an SSA dep
|
||||||
|
// and set the done flag if either is found. Otherwise, set the
|
||||||
|
// init flag to indicate that the iterators have just been initialized.
|
||||||
|
//
|
||||||
|
if (!SetFirstMemoryDep() && !SetFirstSSADep())
|
||||||
|
iterFlags |= AllDone;
|
||||||
|
else
|
||||||
|
iterFlags |= FirstTimeFlag;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
// Helper function for ++ operator that bumps iterator by 1 (to next
|
||||||
|
// dependence) and resets the dep field to represent the new dependence.
|
||||||
|
//
|
||||||
|
void DepIterState::Next()
|
||||||
|
{
|
||||||
|
// firstMemDone and firstSsaDone are used to indicate when the memory or
|
||||||
|
// SSA iterators just ran out, or when this is the very first increment.
|
||||||
|
// In either case, the next iterator (if any) should not be incremented.
|
||||||
|
//
|
||||||
|
bool firstMemDone = iterFlags & FirstTimeFlag;
|
||||||
|
bool firstSsaDone = iterFlags & FirstTimeFlag;
|
||||||
|
bool doIncomingDeps = dep.getDepType() & IncomingFlag;
|
||||||
|
|
||||||
|
if (depFlags & MemoryDeps && ! (iterFlags & MemDone))
|
||||||
|
{
|
||||||
|
iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
++memDepIter;
|
||||||
|
if (SetFirstMemoryDep())
|
||||||
|
return;
|
||||||
|
firstMemDone = true; // flags that we _just_ rolled over
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depFlags & SSADeps && ! (iterFlags & SSADone))
|
||||||
|
{
|
||||||
|
// Don't increment the SSA iterator if we either just rolled over from
|
||||||
|
// the memory dep iterator, or if the SSA iterator is already done.
|
||||||
|
iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
if (! firstMemDone)
|
||||||
|
if (doIncomingDeps) ++ssaInEdgeIter;
|
||||||
|
else ++ssaOutEdgeIter;
|
||||||
|
if (SetFirstSSADep())
|
||||||
|
return;
|
||||||
|
firstSsaDone = true; // flags if we just rolled over
|
||||||
|
}
|
||||||
|
|
||||||
|
if (depFlags & ControlDeps != 0)
|
||||||
|
{
|
||||||
|
assert(0 && "Cannot handle control deps");
|
||||||
|
// iterFlags &= ~FirstTimeFlag; // clear "firstTime" flag
|
||||||
|
}
|
||||||
|
|
||||||
|
// This iterator is now complete.
|
||||||
|
iterFlags |= AllDone;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
// class PgmDependenceGraph
|
||||||
|
//----------------------------------------------------------------------------
|
||||||
|
|
||||||
|
|
||||||
|
// MakeIterator -- Create and initialize an iterator as specified.
|
||||||
|
//
|
||||||
|
PDGIterator PgmDependenceGraph::MakeIterator(Instruction& I,
|
||||||
|
bool incomingDeps,
|
||||||
|
PDGIteratorFlags whichDeps)
|
||||||
|
{
|
||||||
|
assert(memDepGraph && "Function not initialized!");
|
||||||
|
return PDGIterator(new DepIterState(memDepGraph, I, incomingDeps, whichDeps));
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::printOutgoingSSADeps(Instruction& I,
|
||||||
|
std::ostream &O)
|
||||||
|
{
|
||||||
|
iterator SI = this->outDepBegin(I, SSADeps);
|
||||||
|
iterator SE = this->outDepEnd(I, SSADeps);
|
||||||
|
if (SI == SE)
|
||||||
|
return;
|
||||||
|
|
||||||
|
O << "\n Outgoing SSA dependences:\n";
|
||||||
|
for ( ; SI != SE; ++SI)
|
||||||
|
{
|
||||||
|
O << "\t";
|
||||||
|
SI->print(O);
|
||||||
|
O << " to instruction:";
|
||||||
|
O << SI->getSink()->getInstr();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::print(std::ostream &O) const
|
||||||
|
{
|
||||||
|
MemoryDepAnalysis& graphSet = getAnalysis<MemoryDepAnalysis>();
|
||||||
|
|
||||||
|
// TEMPORARY LOOP
|
||||||
|
for (hash_map<Function*, DependenceGraph*>::iterator
|
||||||
|
I = graphSet.funcMap.begin(), E = graphSet.funcMap.end();
|
||||||
|
I != E; ++I)
|
||||||
|
{
|
||||||
|
Function* func = I->first;
|
||||||
|
DependenceGraph* depGraph = I->second;
|
||||||
|
const_cast<PgmDependenceGraph*>(this)->runOnFunction(*func);
|
||||||
|
|
||||||
|
O << "DEPENDENCE GRAPH FOR FUNCTION " << func->getName() << ":\n";
|
||||||
|
for (Function::iterator BB=func->begin(), FE=func->end(); BB != FE; ++BB)
|
||||||
|
for (BasicBlock::iterator II=BB->begin(), IE=BB->end(); II !=IE; ++II)
|
||||||
|
{
|
||||||
|
DepGraphNode* dgNode = depGraph->getNode(*II, /*create*/ true);
|
||||||
|
dgNode->print(O);
|
||||||
|
const_cast<PgmDependenceGraph*>(this)->printOutgoingSSADeps(*II, O);
|
||||||
|
}
|
||||||
|
} // END TEMPORARY LOOP
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void PgmDependenceGraph::dump() const
|
||||||
|
{
|
||||||
|
this->print(std::cerr);
|
||||||
|
}
|
||||||
|
|
||||||
|
static RegisterAnalysis<PgmDependenceGraph>
|
||||||
|
Z("pgmdep", "Enumerate Program Dependence Graph (data and control)");
|
Reference in New Issue
Block a user