mirror of
https://gitlab.winehq.org/wine/wine-gecko.git
synced 2024-09-13 09:24:08 -07:00
Bug 640318 - LIR control-flow graph gml output (r+nnethercote,wmaddox)
--HG-- extra : convert_revision : 45ca084d9cbe063ce96e2b0bd2f7df8a562d0b2f
This commit is contained in:
parent
a7253cc393
commit
8880e03d8b
@ -89,7 +89,6 @@ namespace nanojit
|
||||
if (mem) {
|
||||
Chunk* chunk = (Chunk*) mem;
|
||||
chunk->prev = current_chunk;
|
||||
chunk->size = chunkbytes;
|
||||
current_chunk = chunk;
|
||||
current_top = (char*)chunk->data;
|
||||
current_limit = (char*)mem + chunkbytes;
|
||||
@ -99,17 +98,6 @@ namespace nanojit
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
size_t Allocator::getBytesAllocated()
|
||||
{
|
||||
size_t n = 0;
|
||||
Chunk *c = current_chunk;
|
||||
while (c) {
|
||||
n += c->size;
|
||||
c = c->prev;
|
||||
}
|
||||
return n;
|
||||
}
|
||||
}
|
||||
|
||||
#endif // FEATURE_NANOJIT
|
||||
|
@ -90,8 +90,6 @@ namespace nanojit
|
||||
return p;
|
||||
}
|
||||
|
||||
size_t getBytesAllocated();
|
||||
|
||||
protected:
|
||||
void* allocSlow(size_t nbytes, bool fallible = false);
|
||||
bool fill(size_t minbytes, bool fallible);
|
||||
@ -99,7 +97,6 @@ namespace nanojit
|
||||
class Chunk {
|
||||
public:
|
||||
Chunk* prev;
|
||||
size_t size;
|
||||
int64_t data[1]; // int64_t forces 8-byte alignment.
|
||||
};
|
||||
|
||||
|
@ -98,10 +98,10 @@ namespace nanojit
|
||||
return (int)((x + 512) >> 10);
|
||||
}
|
||||
|
||||
void CodeAlloc::getStats(size_t& total, size_t& frag_size, size_t& free_size) {
|
||||
total = 0;
|
||||
frag_size = 0;
|
||||
free_size = 0;
|
||||
void CodeAlloc::logStats() {
|
||||
size_t total = 0;
|
||||
size_t frag_size = 0;
|
||||
size_t free_size = 0;
|
||||
int free_count = 0;
|
||||
for (CodeList* hb = heapblocks; hb != 0; hb = hb->next) {
|
||||
total += bytesPerAlloc;
|
||||
@ -114,11 +114,6 @@ namespace nanojit
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeAlloc::logStats() {
|
||||
size_t total, frag_size, free_size;
|
||||
getStats(total, frag_size, free_size);
|
||||
avmplus::AvmLog("code-heap: %dk free %dk fragmented %d\n",
|
||||
round(total), round(free_size), frag_size);
|
||||
}
|
||||
|
@ -217,9 +217,6 @@ namespace nanojit
|
||||
/** return the total number of bytes held by this CodeAlloc. */
|
||||
size_t size();
|
||||
|
||||
/** get stats about heap usage */
|
||||
void getStats(size_t& total, size_t& frag_size, size_t& free_size);
|
||||
|
||||
/** print out stats about heap usage */
|
||||
void logStats();
|
||||
|
||||
|
@ -157,6 +157,350 @@ namespace nanojit
|
||||
_prevIns = ins;
|
||||
return ins;
|
||||
}
|
||||
|
||||
|
||||
// build a control flow graph that can be used for display
|
||||
CfgLister::CfgLister(LirFilter* in, Allocator& alloc, CfgMode mode)
|
||||
: LirFilter(in), _alloc(alloc), _alt(alloc), _edges(alloc), _vertices(alloc), _ids(alloc), _mode(mode)
|
||||
{
|
||||
_count = 1; // real programmers start with 1
|
||||
_prior = 0;
|
||||
}
|
||||
|
||||
LIns* CfgLister::read()
|
||||
{
|
||||
bool priorAsVertex = false; // true, implies that the last processed instruction is a vertex
|
||||
|
||||
LIns *ins = in->read();
|
||||
_ids.put(ins, _count++);
|
||||
|
||||
LOpcode op = ins->opcode();
|
||||
LIns* target;
|
||||
switch (op) {
|
||||
case LIR_j:
|
||||
case LIR_jt:
|
||||
case LIR_jf:
|
||||
case LIR_addjovi:
|
||||
case LIR_subjovi:
|
||||
case LIR_muljovi:
|
||||
CASE64(LIR_addjovq:)
|
||||
CASE64(LIR_subjovq:)
|
||||
target = ins->getTarget();
|
||||
addEdge(ins, target);
|
||||
_vertices.put(target,true);
|
||||
priorAsVertex = (_mode == CFG_BB);
|
||||
break;
|
||||
|
||||
case LIR_jtbl: {
|
||||
uint32_t tableSize = ins->getTableSize();
|
||||
NanoAssert(tableSize > 0);
|
||||
for (uint32_t i = 0; i < tableSize; i++)
|
||||
{
|
||||
target = ins->getTarget();
|
||||
addEdge(ins, ins->getTarget());
|
||||
_vertices.put(target,true);
|
||||
}
|
||||
priorAsVertex = (_mode == CFG_BB);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
;
|
||||
}
|
||||
|
||||
// each instruction is a vertex in mode CFG_INS (except imm's which are ignored)
|
||||
priorAsVertex = ( _prior && _mode == CFG_INS && !_prior->isImmAny() ) ? true : priorAsVertex;
|
||||
|
||||
if (_prior && priorAsVertex)
|
||||
_vertices.put(_prior,true);
|
||||
|
||||
_prior = ins;
|
||||
return ins;
|
||||
}
|
||||
|
||||
void CfgLister::addEdge(LIns* from, LIns* to)
|
||||
{
|
||||
InsList* list = _edges.get(from);
|
||||
if (!list) {
|
||||
list = new (_alloc) InsList(_alloc);
|
||||
_edges.put(from,list);
|
||||
}
|
||||
NanoAssert( from && to && (from != to) ); // valid instructions
|
||||
NanoAssert( _ids.containsKey(to) || to->isop(LIR_label) ); // we should have seen the instruction already or its a backwards jump to label
|
||||
list->add(to);
|
||||
|
||||
// identify both sides of edge to later allow them to be re-mapped to other instructions
|
||||
_alt.put(from,from);
|
||||
_alt.put(to,to);
|
||||
}
|
||||
|
||||
uint32_t CfgLister::node2id(LIns* i)
|
||||
{
|
||||
NanoAssert( _ids.containsKey(i) );
|
||||
uint32_t id = _ids.get(i);
|
||||
return _count - id;
|
||||
}
|
||||
|
||||
const char* CfgLister::nodeName(LIns* i, InsBuf& b, LInsPrinter* printer)
|
||||
{
|
||||
// short names used in block per instruction mode
|
||||
const char* str = ( _mode == CFG_INS ) ? printer->lirNameMap->lookupName(i) : 0;
|
||||
str = !str ? printer->formatIns(&b, i) : str;
|
||||
return str;
|
||||
}
|
||||
|
||||
const char* CfgLister::nodeShape(LIns* i, InsSet* pseudos)
|
||||
{
|
||||
const char* shape = "roundrectangle";
|
||||
if (i->isGuard())
|
||||
shape = "hexagon";
|
||||
else if ( pseudos->containsKey(i) )
|
||||
shape = "ellipse";
|
||||
else if ( edgeCountOf(i) > 1 )
|
||||
shape = "diamond";
|
||||
return shape;
|
||||
}
|
||||
|
||||
uint32_t CfgLister::edgeCountOf(LIns* i)
|
||||
{
|
||||
uint32_t a = 0;
|
||||
Seq<LIns*>* l = _edges.get(i) ? _edges.get(i)->get() : 0;
|
||||
for(; l; l=l->tail)
|
||||
a++;
|
||||
return a;
|
||||
}
|
||||
|
||||
void CfgLister::printGmlCfg(FILE* f, LInsPrinter* printer, InsSet* makeProxyNodesFor)
|
||||
{
|
||||
fprintf(f, "graph [ directed 1 hierarchic 1\n");
|
||||
|
||||
// now on the 2nd pass, walk each instruction and add
|
||||
// it to a list until we reach the top of the block,
|
||||
// at which point we print out the node contents.
|
||||
// We also track any incoming edges into any instruction
|
||||
// of this node and map them to the top instruction of the node,
|
||||
// so that our edges get displayed correctly.
|
||||
InsList n(_alloc); // running list of instruction for the block
|
||||
InsSet incoming(_alloc); // running list of incoming edges into the block
|
||||
bool last = true; // true, when we're processing the last instruction of a block
|
||||
LIns* priorBlock = 0; // prior block that was just processed.
|
||||
LIns* priorIns = 0; // last instruction encountered
|
||||
|
||||
LirReader rdr(finalIns());
|
||||
LIns* ins = rdr.read();
|
||||
for (; !ins->isop(LIR_start); ins = rdr.read())
|
||||
{
|
||||
// if last instruction of the block is not terminal then add a fall-thru edge
|
||||
if (priorBlock && last)
|
||||
{
|
||||
last = false;
|
||||
LOpcode op = ins->opcode();
|
||||
if ( !ins->isUnConditionalBranch() && !isRetOpcode(op))
|
||||
addEdge(ins, priorBlock); // fall-thru
|
||||
}
|
||||
|
||||
// process new block?
|
||||
if ( _vertices.containsKey(ins) )
|
||||
{
|
||||
// re-map all incoming edges to any instruction in the block, to the blocks' first instruction
|
||||
InsSet::Iter inc(incoming);
|
||||
while(inc.next())
|
||||
_alt.put(inc.key(), ins);
|
||||
|
||||
n.insert(ins);
|
||||
printNode(f, &n, printer, makeProxyNodesFor);
|
||||
|
||||
// ready to process the next block
|
||||
n.clear();
|
||||
incoming.clear();
|
||||
priorBlock = ins;
|
||||
last = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
// add the instruction to our running list and note any incoming edges to the instruction
|
||||
bool ignore = ins->isImmAny();
|
||||
if (!ignore)
|
||||
n.insert(ins);
|
||||
if ( _alt.containsKey(ins) )
|
||||
incoming.put(ins,true);
|
||||
|
||||
priorIns = ins;
|
||||
}
|
||||
}
|
||||
|
||||
// after once against re-mapping all edges, print the final node
|
||||
InsSet::Iter inc(incoming);
|
||||
while(inc.next())
|
||||
_alt.put(inc.key(), ins);
|
||||
|
||||
n.insert(ins);
|
||||
printNode(f, &n, printer, makeProxyNodesFor);
|
||||
|
||||
// now write out the edge list
|
||||
printEdges(f, printer, makeProxyNodesFor);
|
||||
fprintf(f, "]\n");
|
||||
}
|
||||
|
||||
// prints a node that consists of a sequence of instructions, the first of which is used
|
||||
// to populate the node attributes, such as shape.
|
||||
void CfgLister::printNode(FILE* f, InsList* nodeIns, LInsPrinter* printer, InsSet* pseudo)
|
||||
{
|
||||
// first instruction in the list is the 'node ins'
|
||||
Seq<LIns*>* list = nodeIns->get();
|
||||
LIns* ins = list->head;
|
||||
|
||||
InsBuf str;
|
||||
uint32_t id = node2id(ins);
|
||||
const char* text = nodeName(ins, str, printer);
|
||||
const char* shape = nodeShape(ins, pseudo);
|
||||
gmlNodePrefix(f, id, shape);
|
||||
gmlNodeTextLine(f, text, 0);
|
||||
|
||||
for (list=list->tail; list; list=list->tail)
|
||||
{
|
||||
LIns* i = list->head;
|
||||
text = nodeName(i, str, printer);
|
||||
gmlNodeTextLine(f, text, 1);
|
||||
}
|
||||
|
||||
gmlNodeSuffix(f);
|
||||
}
|
||||
|
||||
void CfgLister::printEdges(FILE* f, LInsPrinter* printer, InsSet* makeProxyNodesFor)
|
||||
{
|
||||
uint32_t pseudoId = ~0; // ids for proxy nodes
|
||||
InsBuf str;
|
||||
HashMap<LIns*, InsList*>::Iter ite(_edges);
|
||||
while(ite.next())
|
||||
{
|
||||
LIns* origSrc = ite.key();
|
||||
LIns* src = _alt.containsKey(origSrc) ? _alt.get(origSrc) : src;
|
||||
uint32_t sid = node2id(src);
|
||||
Seq<LIns*>* l = ite.value()->get();
|
||||
while (l)
|
||||
{
|
||||
LIns* origDst = l->head;
|
||||
LIns* dst = _alt.get(origDst); // destination mapping
|
||||
uint32_t did = node2id(dst);
|
||||
|
||||
bool proxyNode = makeProxyNodesFor->containsKey(origDst);
|
||||
if (_mode != CFG_INS && proxyNode)
|
||||
{
|
||||
// in most modes, edges to proxies are ignored.
|
||||
l = l->tail;
|
||||
continue;
|
||||
}
|
||||
|
||||
// do we want to add a pseudo node for destination; removes clutter from the graph
|
||||
if (proxyNode)
|
||||
{
|
||||
did = --pseudoId;
|
||||
gmlNode(f, did, "ellipse", nodeName(dst, str, printer));
|
||||
NanoAssert(did > _count); // graph is too large to render correctly
|
||||
}
|
||||
|
||||
const char* str_dashed = "dashed";
|
||||
const char* str_solid = "solid";
|
||||
const char* str_red = "#E00000";
|
||||
const char* str_gray = "#AAAAAA";
|
||||
|
||||
const char* text = 0;
|
||||
const char* style = str_dashed;
|
||||
const char* fill = str_gray;
|
||||
const char* width = 0;
|
||||
|
||||
if ( origSrc->isConditionalBranch() )
|
||||
{
|
||||
bool explicitEdge = origSrc->getTarget() == origDst;
|
||||
if (explicitEdge)
|
||||
{
|
||||
// this is the non fall-thru edge
|
||||
style = str_solid;
|
||||
fill = 0; //default fill
|
||||
text = origSrc->isop(LIR_jf) ? "0" : "1";
|
||||
}
|
||||
else
|
||||
{
|
||||
// not taken edge
|
||||
text = origSrc->isop(LIR_jf) ? "1" : "0";
|
||||
}
|
||||
}
|
||||
if (did < sid)
|
||||
{
|
||||
// 'backwards' movements are red and large by default
|
||||
style = str_solid;
|
||||
fill = str_red;
|
||||
width = "2";
|
||||
}
|
||||
gmlEdge(f, sid, did, style, fill, width, text);
|
||||
l = l->tail;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CfgLister::gmlNodePrefix(FILE* f, uint32_t id, const char* shape)
|
||||
{
|
||||
fprintf(f, " node [\n");
|
||||
fprintf(f, " id %d\n", id);
|
||||
fprintf(f, " graphics [\n");
|
||||
fprintf(f, " type \"%s\"\n", shape);
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " LabelGraphics [\n");
|
||||
fprintf(f, " alignment \"left\"\n");
|
||||
fprintf(f, " fontName \"Consolas\"\n");
|
||||
fprintf(f, " anchor \"tl\"\n"); // Top Left
|
||||
fprintf(f, " text \"");
|
||||
}
|
||||
|
||||
void CfgLister::gmlNodeTextLine(FILE* f, const char* text, int32_t tabCount)
|
||||
{
|
||||
while(tabCount-->0)
|
||||
fprintf(f, "\t");
|
||||
fprintf(f, "%s\n", text);
|
||||
}
|
||||
|
||||
void CfgLister::gmlNodeSuffix(FILE* f)
|
||||
{
|
||||
fprintf(f, " \"\n");
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " ]\n");
|
||||
}
|
||||
|
||||
void CfgLister::gmlNode(FILE* f, uint32_t id, const char* shape, const char* title)
|
||||
{
|
||||
fprintf(f, " node [\n");
|
||||
fprintf(f, " id %d\n", id);
|
||||
fprintf(f, " graphics [\n");
|
||||
fprintf(f, " type \"%s\"\n", shape);
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " LabelGraphics [\n");
|
||||
fprintf(f, " text \"%s\"\n", title);
|
||||
fprintf(f, " alignment \"left\"\n");
|
||||
fprintf(f, " fontName \"Consolas\"\n");
|
||||
fprintf(f, " anchor \"tl\"\n"); // Top Left
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " ]\n");
|
||||
}
|
||||
|
||||
void CfgLister::gmlEdge(FILE* f, uint32_t srcId, uint32_t dstId, const char* style, const char* fill, const char* width, const char* text)
|
||||
{
|
||||
fprintf(f, " edge [\n");
|
||||
fprintf(f, " source %d\n", srcId);
|
||||
fprintf(f, " target %d\n", dstId);
|
||||
fprintf(f, " graphics [\n");
|
||||
fprintf(f, " arrow \"last\"\n");
|
||||
if (style) fprintf(f, " style \"%s\"\n", style);
|
||||
if (fill) fprintf(f, " fill \"%s\"\n", fill);
|
||||
if (width) fprintf(f, " width %s\n", width);
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " LabelGraphics [\n");
|
||||
if (text) fprintf(f, " text \"%s\"\n", text);
|
||||
fprintf(f, " model \"three_center\"\n");
|
||||
fprintf(f, " fontStyle \"bold\"\n");
|
||||
fprintf(f, " ]\n");
|
||||
fprintf(f, " ]\n");
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
// LCompressedBuffer
|
||||
@ -1376,7 +1720,7 @@ namespace nanojit
|
||||
void retire(LIns* i) {
|
||||
RetiredEntry *e = new (alloc) RetiredEntry();
|
||||
e->i = i;
|
||||
SeqBuilder<LIns*> livelist(alloc);
|
||||
InsList livelist(alloc);
|
||||
HashMap<LIns*, LIns*>::Iter iter(live);
|
||||
int live_count = 0;
|
||||
while (iter.next()) {
|
||||
@ -3092,7 +3436,7 @@ namespace nanojit
|
||||
LIns *args[] = { split(a) };
|
||||
return out->insCall(call, args);
|
||||
}
|
||||
|
||||
|
||||
LIns* SoftFloatFilter::callD2(const CallInfo *call, LIns *a, LIns *b) {
|
||||
LIns *args[] = { split(b), split(a) };
|
||||
return split(call, args);
|
||||
@ -3106,7 +3450,7 @@ namespace nanojit
|
||||
LIns* SoftFloatFilter::ins1(LOpcode op, LIns *a) {
|
||||
const CallInfo *ci = softFloatOps.opmap[op];
|
||||
if (ci) {
|
||||
if (ci->returnType() == ARGTYPE_D)
|
||||
if (ci->returnType() == ARGTYPE_D)
|
||||
return callD1(ci, a);
|
||||
else
|
||||
return callI1(ci, a);
|
||||
|
@ -745,7 +745,7 @@ namespace nanojit
|
||||
if (isInReg()) {
|
||||
Register r = { sharedFields.regnum };
|
||||
return r;
|
||||
} else {
|
||||
} else {
|
||||
return deprecated_UnknownReg;
|
||||
}
|
||||
}
|
||||
@ -985,8 +985,16 @@ namespace nanojit
|
||||
return isImmI() || isImmQorD();
|
||||
}
|
||||
|
||||
bool isConditionalBranch() const {
|
||||
return isop(LIR_jt) || isop(LIR_jf) || isJov();
|
||||
}
|
||||
|
||||
bool isUnConditionalBranch() const {
|
||||
return isop(LIR_j) || isop(LIR_jtbl);
|
||||
}
|
||||
|
||||
bool isBranch() const {
|
||||
return isop(LIR_jt) || isop(LIR_jf) || isop(LIR_j) || isop(LIR_jtbl) || isJov();
|
||||
return isConditionalBranch() || isUnConditionalBranch();
|
||||
}
|
||||
|
||||
LTy retType() const {
|
||||
@ -1035,7 +1043,7 @@ namespace nanojit
|
||||
|
||||
typedef SeqBuilder<LIns*> InsList;
|
||||
typedef SeqBuilder<char*> StringList;
|
||||
|
||||
typedef HashMap<LIns*,bool> InsSet;
|
||||
|
||||
// 0-operand form. Used for LIR_start and LIR_label.
|
||||
class LInsOp0
|
||||
@ -1990,7 +1998,7 @@ namespace nanojit
|
||||
// be true, else we would have side-exited. So if we see 'cmp' again
|
||||
// we can treat it like a constant. This table records such
|
||||
// comparisons.
|
||||
HashMap <LIns*, bool> knownCmpValues;
|
||||
InsSet knownCmpValues;
|
||||
|
||||
// If true, we will not add new instructions to the CSE tables, but we
|
||||
// will continue to CSE instructions that match existing table
|
||||
@ -2469,6 +2477,100 @@ namespace nanojit
|
||||
void finish();
|
||||
LIns* read();
|
||||
};
|
||||
|
||||
/**
|
||||
* A reverse filter for LIR that generates a control-flow graph in gml format.
|
||||
* More information on Graph Modelling Language (gml) can be found here:
|
||||
* http://en.wikipedia.org/wiki/Graph_Modelling_Language
|
||||
* An excellent tool for manipulating the graphs produced by this code
|
||||
* is yED (http://www.yworks.com/en/products_yed_about.html).
|
||||
*
|
||||
* The raw output produced by this class contains connectively (i,e edge)
|
||||
* information (including formatting), and node (i.e. vertex) data, but
|
||||
* does not contain any positional information.
|
||||
* Thus when opening the .gml file, all the nodes will likely appear stacked
|
||||
* on one another. An auto-layout tool like yEd can then re-position the
|
||||
* nodes for better viewing. E.g. Tools->Fit Node to Label followed by
|
||||
* Layout->Hierarchical->Interactive produces a relatively convential
|
||||
* looking flow-control graph.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* LirReader reader(frag->lastIns);
|
||||
* CfgLister cfg(&reader, alloc);
|
||||
*
|
||||
* for (LIns* ins = cfg.read(); !ins->isop(LIR_start); ins = cfg.read()) {}
|
||||
*
|
||||
* cfg.printGmlCfg(f, frag->lirbuf->printer, proxiesFor);
|
||||
* fclose(f);
|
||||
*
|
||||
* The first and second parameters to printGmlCfg() are an open FILE* and
|
||||
* a populated LInsPrinter, respectively. The printer must be able to produce
|
||||
* a name from either the lirNameMap or a call to formatIns().
|
||||
*
|
||||
* The 3rd parameter to primtGmlCfg(), proxiesFor can be used to limit
|
||||
* the number of edges in the graph. If an edge points to a vertex (LIns) in
|
||||
* this set, then a new node is created, with the same name as the original,
|
||||
* and the edge will point to that node.
|
||||
*
|
||||
* Algortihm:
|
||||
*
|
||||
* During the first pass (i.e. CfgLister::read()), we capture edges and vertices
|
||||
* at an instruction level. Recall that this is during a backwards pass, so for
|
||||
* forward branches we won't know whether an instruction we've seen already is
|
||||
* the target of a branch or not, until we reach the branch. I.e. we see the
|
||||
* target instructions first and don't yet know they are targets.
|
||||
*
|
||||
* On the 2nd pass (i.e. printGmlCfg) we use the list of branch targets from the
|
||||
* first pass (i.e. _vertices) and group instructions into them. This is where
|
||||
* _alt comes into play, it provides a map from any instruction to the first
|
||||
* instruction of the containing block.
|
||||
*/
|
||||
class CfgLister : public LirFilter
|
||||
{
|
||||
public:
|
||||
virtual LIns* read();
|
||||
|
||||
typedef enum _CfgMode
|
||||
{
|
||||
CFG_EBB // extended basic blocks
|
||||
, CFG_BB // basic blocks
|
||||
, CFG_INS // 1 block per instruction
|
||||
}
|
||||
CfgMode;
|
||||
|
||||
CfgLister(LirFilter* in, Allocator& alloc, CfgMode mode=CFG_EBB);
|
||||
|
||||
void printGmlCfg(FILE* f, LInsPrinter* printer, InsSet* makeProxyNodesFor);
|
||||
|
||||
private:
|
||||
void addEdge(LIns* from, LIns* to);
|
||||
uint32_t node2id(LIns* i);
|
||||
const char* nodeName(LIns* i, InsBuf& b, LInsPrinter* printer);
|
||||
const char* nodeShape(LIns* i, InsSet* pseudo);
|
||||
uint32_t edgeCountOf(LIns* i);
|
||||
|
||||
void printEdges(FILE* f, LInsPrinter* printer, InsSet* pseudo);
|
||||
void printNode(FILE* f, InsList* nodeIns, LInsPrinter* printer, InsSet* pseudo);
|
||||
|
||||
void gmlNode(FILE* f, uint32_t id, const char* shape, const char* title);
|
||||
void gmlEdge(FILE* f, uint32_t srcId, uint32_t dstId, const char* style, const char* fill, const char* width, const char* text);
|
||||
|
||||
//alternate form of gmlNode
|
||||
void gmlNodePrefix(FILE* f, uint32_t id, const char* shape);
|
||||
void gmlNodeSuffix(FILE* f);
|
||||
void gmlNodeTextLine(FILE* f, const char* text, int32_t tabCount);
|
||||
|
||||
Allocator& _alloc;
|
||||
HashMap<LIns*, LIns*> _alt; // allow edge src/dst to be re-mapped to another instruction
|
||||
HashMap<LIns*, InsList*> _edges; // from,to list
|
||||
InsSet _vertices; // node list
|
||||
HashMap<LIns*, uint32_t> _ids; // ins -> unique id
|
||||
LIns* _prior; // state maintained during read()
|
||||
uint32_t _count; // state maintained during read()
|
||||
CfgMode _mode; // mode selector
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user