blob: f6bdc9d73ee2507a1aef4d0105aa42ae7bd2c1d3 [file] [log] [blame]
//===-- OperandGraph.cpp ----------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#include "OperandGraph.h"
#include "llvm/MC/MCRegisterInfo.h"
namespace exegesis {
namespace graph {
void Node::dump(const llvm::MCRegisterInfo &RegInfo) const {
switch (type()) {
case NodeType::VARIABLE:
printf(" %d", varValue());
break;
case NodeType::REG:
printf(" %s", RegInfo.getName(regValue()));
break;
case NodeType::IN:
printf(" IN");
break;
case NodeType::OUT:
printf(" OUT");
break;
}
}
NodeType Node::type() const { return first; }
int Node::regValue() const {
assert(first == NodeType::REG && "regValue() called on non-reg");
return second;
}
int Node::varValue() const {
assert(first == NodeType::VARIABLE && "varValue() called on non-var");
return second;
}
void Graph::connect(const Node From, const Node To) {
AdjacencyLists[From].insert(To);
}
void Graph::disconnect(const Node From, const Node To) {
AdjacencyLists[From].erase(To);
}
std::vector<Node> Graph::getPathFrom(const Node From, const Node To) const {
std::vector<Node> Path;
NodeSet Seen;
dfs(From, To, Path, Seen);
return Path;
}
// DFS is implemented recursively, this is fine as graph size is small (~250
// nodes, ~200 edges, longuest path depth < 10).
bool Graph::dfs(const Node Current, const Node Sentinel,
std::vector<Node> &Path, NodeSet &Seen) const {
Path.push_back(Current);
Seen.insert(Current);
if (Current == Sentinel)
return true;
if (AdjacencyLists.count(Current)) {
for (const Node Next : AdjacencyLists.find(Current)->second) {
if (Seen.count(Next))
continue;
if (dfs(Next, Sentinel, Path, Seen))
return true;
}
}
Path.pop_back();
return false;
}
// For each Register Units we walk up their parents.
// Let's take the case of the A register family:
//
// RAX
// ^
// EAX
// ^
// AX
// ^ ^
// AH AL
//
// Register Units are AH and AL.
// Walking them up gives the following lists:
// AH->AX->EAX->RAX and AL->AX->EAX->RAX
// When walking the lists we add connect current to parent both ways leading to
// the following connections:
//
// AL<->AX, AH<->AX, AX<->EAX, EAX<->RAX
// We repeat this process for all Unit Registers to cover all connections.
void setupRegisterAliasing(const llvm::MCRegisterInfo &RegInfo,
Graph &TheGraph) {
using SuperItr = llvm::MCSuperRegIterator;
for (size_t Reg = 0, E = RegInfo.getNumRegUnits(); Reg < E; ++Reg) {
size_t Current = Reg;
for (SuperItr Super(Reg, &RegInfo); Super.isValid(); ++Super) {
const Node A = Node::Reg(Current);
const Node B = Node::Reg(*Super);
TheGraph.connect(A, B);
TheGraph.connect(B, A);
Current = *Super;
}
}
}
} // namespace graph
} // namespace exegesis