void Function::printCFGraph(const char *filePath) { FILE *out = fopen(filePath, "a"); if (!out) { ERROR("failed to open file: %s\n", filePath); return; } INFO("printing control flow graph to: %s\n", filePath); fprintf(out, "digraph G {\n"); for (IteratorRef it = cfg.iteratorDFS(); !it->end(); it->next()) { BasicBlock *bb = BasicBlock::get( reinterpret_cast<Graph::Node *>(it->get())); int idA = bb->getId(); for (Graph::EdgeIterator ei = bb->cfg.outgoing(); !ei.end(); ei.next()) { int idB = BasicBlock::get(ei.getNode())->getId(); switch (ei.getType()) { case Graph::Edge::TREE: fprintf(out, "\t%i -> %i;\n", idA, idB); break; case Graph::Edge::FORWARD: fprintf(out, "\t%i -> %i [color=green];\n", idA, idB); break; case Graph::Edge::CROSS: fprintf(out, "\t%i -> %i [color=red];\n", idA, idB); break; case Graph::Edge::BACK: fprintf(out, "\t%i -> %i;\n", idA, idB); break; case Graph::Edge::DUMMY: fprintf(out, "\t%i -> %i [style=dotted];\n", idA, idB); break; default: assert(0); break; } } } fprintf(out, "}\n"); fclose(out); }
// Efficiently Computing Static Single Assignment Form and // the Control Dependence Graph, // R. Cytron, J. Ferrante, B. K. Rosen, M. N. Wegman, F. K. Zadeck bool Function::convertToSSA() { // 0. calculate live in variables (for pruned SSA) buildLiveSets(); // 1. create the dominator tree domTree = new DominatorTree(&cfg); reinterpret_cast<DominatorTree *>(domTree)->findDominanceFrontiers(); // 2. insert PHI functions DLList workList; LValue *lval; BasicBlock *bb; int var; int iterCount = 0; int *hasAlready = new int[allBBlocks.getSize() * 2]; int *work = &hasAlready[allBBlocks.getSize()]; memset(hasAlready, 0, allBBlocks.getSize() * 2 * sizeof(int)); // for each variable for (var = 0; var < allLValues.getSize(); ++var) { if (!allLValues.get(var)) continue; lval = reinterpret_cast<Value *>(allLValues.get(var))->asLValue(); if (!lval || lval->defs.empty()) continue; ++iterCount; // TODO: don't add phi functions for values that aren't used outside // the BB they're defined in // gather blocks with assignments to lval in workList for (Value::DefIterator d = lval->defs.begin(); d != lval->defs.end(); ++d) { bb = ((*d)->getInsn() ? (*d)->getInsn()->bb : NULL); if (!bb) continue; // instruction likely been removed but not XXX deleted if (work[bb->getId()] == iterCount) continue; work[bb->getId()] = iterCount; workList.insert(bb); } // for each block in workList, insert a phi for lval in the block's // dominance frontier (if we haven't already done so) for (DLList::Iterator wI = workList.iterator(); !wI.end(); wI.erase()) { bb = BasicBlock::get(wI); DLList::Iterator dfIter = bb->getDF().iterator(); for (; !dfIter.end(); dfIter.next()) { Instruction *phi; BasicBlock *dfBB = BasicBlock::get(dfIter); if (hasAlready[dfBB->getId()] >= iterCount) continue; hasAlready[dfBB->getId()] = iterCount; // pruned SSA: don't need a phi if the value is not live-in if (!dfBB->liveSet.test(lval->id)) continue; phi = new_Instruction(this, OP_PHI, typeOfSize(lval->reg.size)); dfBB->insertTail(phi); phi->setDef(0, lval); for (int s = 0; s < dfBB->cfg.incidentCount(); ++s) phi->setSrc(s, lval); if (work[dfBB->getId()] < iterCount) { work[dfBB->getId()] = iterCount; wI.insert(dfBB); } } } } delete[] hasAlready; RenamePass rename(this); return rename.run(); }