void BoundFactsCalculator::NaturalDFS(Node::Ptr cur) { nodeColor[cur] = 1; NodeIterator nbegin, nend; cur->outs(nbegin, nend); for (; nbegin != nend; ++nbegin) if (nodeColor.find(*nbegin) == nodeColor.end()) NaturalDFS(*nbegin); reverseOrder.push_back(cur); }
void dfs(Node::Ptr source, std::map<Node::Ptr, int> &state, std::set<Edge::Ptr> &skipEdges) { // DFS from the node given by source // If we meet a node twice without having to backtrack first, // insert that incoming edge into skipEdges. // // A node n has state[n] > 0 if it is on the path currently // being explored. EdgeIterator b, e; source->outs(b, e); vector<Edge::Ptr> edges; for ( ; b!=e; ++b) { Edge::Ptr edge = *b; edges.push_back(edge); } std::stable_sort(edges.begin(), edges.end(), edgeSort); //state[source]++; std::map<Node::Ptr, int>::iterator ssit = state.find(source); if(ssit == state.end()) boost::tuples::tie(ssit,boost::tuples::ignore) = state.insert(make_pair(source,1)); else (*ssit).second++; vector<Edge::Ptr>::iterator eit = edges.begin(); for ( ; eit != edges.end(); ++eit) { Edge::Ptr edge = *eit; Node::Ptr cur = edge->target(); std::map<Node::Ptr, int>::iterator sit = state.find(cur); bool done = (sit != state.end()); if(done && (*sit).second > 0) skipEdges.insert(edge); if(!done) dfs(cur, state, skipEdges); } //state[source]--; (*ssit).second--; }
bool Graph::printDOT(const std::string& fileName) { FILE *file = fopen(fileName.c_str(), "w"); if (file == NULL) { return false; } fprintf(file, "digraph G {\n"); NodeSet visited; std::queue<Node::Ptr> worklist; NodeIterator entryBegin, entryEnd; entryNodes(entryBegin, entryEnd); // Initialize visitor worklist for (NodeIterator iter = entryBegin; iter != entryEnd; ++iter) { worklist.push(*iter); } // Put the entry nodes on their own (minimum) rank fprintf(file, " { rank = min;"); for (NodeIterator iter = entryBegin; iter != entryEnd; ++iter) { fprintf(file, "\"%p\"; ", (*iter).get()); } fprintf(file, "}\n"); NodeIterator exitBegin, exitEnd; exitNodes(exitBegin, exitEnd); // Put the entry nodes on their own (minimum) rank fprintf(file, " { rank = max;"); for (NodeIterator iter = exitBegin; iter != exitEnd; ++iter) { fprintf(file, "\"%p\"; ", (*iter).get()); } fprintf(file, "}\n"); while (!worklist.empty()) { Node::Ptr source = worklist.front(); worklist.pop(); //fprintf(stderr, "Considering node %s\n", source->format().c_str()); // We may have already treated this node... if (visited.find(source) != visited.end()) { //fprintf(stderr, "\t skipping previously visited node\n"); continue; } //fprintf(stderr, "\t inserting %s into visited set, %d elements pre-insert\n", source->format().c_str(), visited.size()); visited.insert(source); fprintf(file, "\t%s\n", source->DOTshape().c_str()); fprintf(file, "\t%s\n", source->DOTrank().c_str()); fprintf(file, "\t\"%p\" [label=\"%s\"];\n", source.get(), source->DOTname().c_str()); NodeIterator outBegin, outEnd; source->outs(outBegin, outEnd); for (; outBegin != outEnd; ++outBegin) { Node::Ptr target = *outBegin; if (!target->DOTinclude()) continue; //fprintf(file, "\t %s -> %s;\n", source->DOTname().c_str(), target->DOTname().c_str()); fprintf(file, "\t \"%p\" -> \"%p\";\n", source.get(), target.get()); if (visited.find(target) == visited.end()) { //fprintf(stderr, "\t\t adding child %s\n", target->format().c_str()); worklist.push(target); } else { //fprintf(stderr, "\t\t skipping previously visited child %s\n", //target->format().c_str()); } } } fprintf(file, "}\n\n\n"); fclose(file); return true; }
bool BoundFactsCalculator::CalculateBoundedFacts() { /* We use a dataflow analysis to calculate the value bound * of each register and potentially some memory locations. * The key steps of the dataflow analysis are * 1. Determine the analysis order: * First calculate all strongly connected components (SCC) * of the graph. The flow analysis inside a SCC is * iterative. The flow analysis between several SCCs * is done topologically. * 2. For each node, need to calculate the meet and * calculate the transfer function. * 1. The meet should be simply an intersection of all the bounded facts * along all paths. * 2. To calculate the transfer function, we first get the symbolic expression * of the instrution for the node. Then depending on the instruction operation * and the meet result, we know what are still bounded. For example, loading * memory is always unbounded; doing and operation on a register with a constant * makes the register bounded. */ DetermineAnalysisOrder(); queue<Node::Ptr> workingList; unordered_set<Node::Ptr, Node::NodePtrHasher> inQueue; unordered_map<Node::Ptr, int, Node::NodePtrHasher> inQueueLimit; for (int curOrder = 0; curOrder <= orderStamp; ++curOrder) { // We first determine which nodes are // in this SCC vector<Node::Ptr> curNodes; NodeIterator nbegin, nend; slice->allNodes(nbegin, nend); for (; nbegin != nend; ++nbegin) { if (analysisOrder[*nbegin] == curOrder) { curNodes.push_back(*nbegin); workingList.push(*nbegin); inQueue.insert(*nbegin); } } if (!HasIncomingEdgesFromLowerLevel(curOrder, curNodes)) { // If this SCC is an entry SCC, // we choose a node inside the SCC // and let it be top. // This should only contain the virtual entry node parsing_printf("This SCC does not incoming edges from outside\n"); boundFactsIn[curNodes[0]] = new BoundFact(); boundFactsOut[curNodes[0]] = new BoundFact(); } parsing_printf("Starting analysis inside SCC %d\n", curOrder); // We now start iterative analysis inside the SCC while (!workingList.empty()) { // We get the current node Node::Ptr curNode = workingList.front(); workingList.pop(); inQueue.erase(curNode); SliceNode::Ptr node = boost::static_pointer_cast<SliceNode>(curNode); ++inQueueLimit[curNode]; if (inQueueLimit[curNode] > IN_QUEUE_LIMIT) continue; BoundFact* oldFactIn = GetBoundFactIn(curNode); parsing_printf("Calculate Meet for %lx", node->addr()); if (node->assign()) { parsing_printf(", insn: %s\n", node->assign()->insn()->format().c_str()); } else { if (node->block() == NULL) parsing_printf(", the VirtualExit node\n"); else parsing_printf(", the VirtualEntry node\n"); } parsing_printf("\tOld fact for %lx:\n", node->addr()); if (oldFactIn == NULL) parsing_printf("\t\t do not exist\n"); else oldFactIn->Print(); // We find all predecessors of the current node // and calculates the union of the analysis results // from the predecessors BoundFact* newFactIn = Meet(curNode); parsing_printf("\tNew fact at %lx\n", node->addr()); if (newFactIn != NULL) newFactIn->Print(); else parsing_printf("\t\tNot calculated\n"); // If the current node has not been calcualted yet, // or the new meet results are different from the // old ones, we keep the new results if (newFactIn != NULL && (oldFactIn == NULL || *oldFactIn != *newFactIn)) { parsing_printf("\tFacts change!\n"); if (oldFactIn != NULL) delete oldFactIn; boundFactsIn[curNode] = newFactIn; BoundFact* newFactOut = new BoundFact(*newFactIn); // The current node has a transfer function // that changes the analysis results CalcTransferFunction(curNode, newFactOut); if (boundFactsOut.find(curNode) != boundFactsOut.end() && boundFactsOut[curNode] != NULL) delete boundFactsOut[curNode]; boundFactsOut[curNode] = newFactOut; curNode->outs(nbegin, nend); for (; nbegin != nend; ++nbegin) // We only add node inside current SCC into the working list if (inQueue.find(*nbegin) == inQueue.end() && analysisOrder[*nbegin] == curOrder) { workingList.push(*nbegin); inQueue.insert(*nbegin); } } else { if (newFactIn != NULL) delete newFactIn; parsing_printf("\tFacts do not change!\n"); } } } return true; }