Jit/codegen/copy_graph.cpp (94 lines of code) (raw):
// Copyright (c) Facebook, Inc. and its affiliates. (http://www.facebook.com)
#include "Jit/codegen/copy_graph.h"
namespace jit {
namespace codegen {
constexpr int CopyGraph::kTempLoc;
CopyGraph::Node::~Node() {
if (child_node.isLinked()) {
child_node.Unlink();
}
if (leaf_node.isLinked()) {
leaf_node.Unlink();
}
}
void CopyGraph::addEdge(int from, int to) {
auto parent = getNode(from);
auto child = getNode(to);
JIT_DCHECK(child->parent == nullptr, "child already has a parent");
setParent(child, parent);
}
CopyGraph::Node* CopyGraph::getNode(int loc) {
auto pair = nodes_.emplace(
std::piecewise_construct,
std::forward_as_tuple(loc),
std::forward_as_tuple(loc));
if (pair.second) {
// Every node starts as a leaf.
leaf_nodes_.PushBack(pair.first->second);
}
return &pair.first->second;
}
void CopyGraph::setParent(Node* child, Node* parent) {
JIT_DCHECK(child != parent, "Can't make node its own parent");
if (child->child_node.isLinked()) {
child->child_node.Unlink();
}
child->parent = parent;
if (parent != nullptr) {
parent->children.PushBack(*child);
if (parent->leaf_node.isLinked()) {
parent->leaf_node.Unlink();
}
}
}
bool CopyGraph::inRegisterCycle(Node* node) {
auto cursor = node;
do {
if (cursor->loc < 0) {
return false;
}
cursor = cursor->parent;
} while (cursor != node);
return true;
}
std::vector<CopyGraph::Op> CopyGraph::process() {
// The high-level algorithm is:
//
// 1. Pick an arbitrary leaf node L. If there are none, goto 5.
//
// 2. Generate a copy from L's parent P to L.
// 3. Remove L from the graph.
// 4. If P has a parent and is now a leaf node, set L = P and goto
// 2. Otherwise, goto 1.
//
// 5. With no leaf nodes left, all remaining nodes must be part of a
// cycle. Since nodes can't have multiple incoming edges, each cycle is a
// a simple linked list.
//
// 6. Pick an arbitrary node N in the graph. If there are none, return.
// 7. If the cycle contains any memory locations, goto 11.
//
// 8. Clear N's children (there will only be 1) to break the cycle.
// 9. Generate an exchange between N and N's parent.
// 10. If N has a parent P, set N = P and goto 9. Otherwise,
// remove all nodes in the cycle and goto 6.
//
// 11. Generate a copy from N to the temp location.
// 12. Create a node T for the temp location.
// 13. Set N's child's parent to T, breaking the cycle and turning N into a
// leaf node.
// 14. Repeat steps 1-4 until no leaf nodes are left. Goto 6.
std::vector<Op> ops;
processLeafNodes(ops);
while (!nodes_.empty()) {
auto node = &nodes_.begin()->second;
if (inRegisterCycle(node)) {
setParent(&node->children.Front(), nullptr);
while (node->parent != nullptr) {
ops.emplace_back(Op::Kind::kExchange, node->loc, node->parent->loc);
auto parent = node->parent;
nodes_.erase(node->loc);
node = parent;
}
nodes_.erase(node->loc);
continue;
}
ops.emplace_back(Op::Kind::kCopy, node->loc, kTempLoc);
auto temp_node = getNode(kTempLoc);
auto child = &node->children.Front();
setParent(child, temp_node);
leaf_nodes_.PushBack(*node);
processLeafNodes(ops);
}
return ops;
}
void CopyGraph::processLeafNodes(std::vector<Op>& ops) {
while (!leaf_nodes_.IsEmpty()) {
auto node = &leaf_nodes_.Front();
leaf_nodes_.PopFront();
auto parent = node->parent;
ops.emplace_back(Op::Kind::kCopy, parent->loc, node->loc);
nodes_.erase(node->loc);
if (parent->children.IsEmpty()) {
if (parent->parent == nullptr) {
// The parent has no parent, so this was the last copy in this chain.
nodes_.erase(parent->loc);
} else {
// Process the parent next.
leaf_nodes_.PushFront(*parent);
}
}
}
}
} // namespace codegen
} // namespace jit