summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp')
-rw-r--r--llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp355
1 files changed, 0 insertions, 355 deletions
diff --git a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp b/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
deleted file mode 100644
index 2ab3379faed..00000000000
--- a/llvm/tools/llvm-exegesis/lib/InstructionSnippetGenerator.cpp
+++ /dev/null
@@ -1,355 +0,0 @@
-//===-- InstructionSnippetGenerator.cpp -------------------------*- C++ -*-===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-
-#include "InstructionSnippetGenerator.h"
-#include "llvm/ADT/MapVector.h"
-#include "llvm/ADT/STLExtras.h"
-#include "llvm/ADT/SmallSet.h"
-#include "llvm/MC/MCInstBuilder.h"
-#include <algorithm>
-#include <unordered_map>
-#include <unordered_set>
-
-namespace exegesis {
-
-void Variable::print(llvm::raw_ostream &OS,
- const llvm::MCRegisterInfo *RegInfo) const {
- OS << "IsUse=" << IsUse << " IsDef=" << IsDef << " possible regs: {";
- for (const size_t Reg : PossibleRegisters) {
- if (RegInfo)
- OS << RegInfo->getName(Reg);
- else
- OS << Reg;
- OS << ",";
- }
- OS << "} ";
- if (ExplicitOperands.empty()) {
- OS << "implicit";
- } else {
- OS << "explicit ops: {";
- for (const size_t Op : ExplicitOperands)
- OS << Op << ",";
- OS << "}";
- }
- OS << "\n";
-}
-
-// Update the state of a Variable with an explicit operand.
-static void updateExplicitOperandVariable(const llvm::MCRegisterInfo &RegInfo,
- const llvm::MCInstrDesc &InstrInfo,
- const size_t OpIndex,
- const llvm::BitVector &ReservedRegs,
- Variable &Var) {
- const bool IsDef = OpIndex < InstrInfo.getNumDefs();
- if (IsDef)
- Var.IsDef = true;
- if (!IsDef)
- Var.IsUse = true;
- Var.ExplicitOperands.push_back(OpIndex);
- const llvm::MCOperandInfo &OpInfo = InstrInfo.opInfo_begin()[OpIndex];
- if (OpInfo.RegClass >= 0) {
- Var.IsReg = true;
- for (const llvm::MCPhysReg &Reg : RegInfo.getRegClass(OpInfo.RegClass)) {
- if (!ReservedRegs[Reg])
- Var.PossibleRegisters.insert(Reg);
- }
- }
-}
-
-static Variable &findVariableWithOperand(llvm::SmallVector<Variable, 8> &Vars,
- size_t OpIndex) {
- // Vars.size() is small (<10) so a linear scan is good enough.
- for (Variable &Var : Vars) {
- if (llvm::is_contained(Var.ExplicitOperands, OpIndex))
- return Var;
- }
- assert(false && "Illegal state");
- static Variable *const EmptyVariable = new Variable();
- return *EmptyVariable;
-}
-
-llvm::SmallVector<Variable, 8>
-getVariables(const llvm::MCRegisterInfo &RegInfo,
- const llvm::MCInstrDesc &InstrInfo,
- const llvm::BitVector &ReservedRegs) {
- llvm::SmallVector<Variable, 8> Vars;
- // For each operand, its "tied to" operand or -1.
- llvm::SmallVector<int, 10> TiedToMap;
- for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) {
- TiedToMap.push_back(InstrInfo.getOperandConstraint(I, llvm::MCOI::TIED_TO));
- }
- // Adding non tied operands.
- for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) {
- if (TiedToMap[I] >= 0)
- continue; // dropping tied ones.
- Vars.emplace_back();
- updateExplicitOperandVariable(RegInfo, InstrInfo, I, ReservedRegs,
- Vars.back());
- }
- // Adding tied operands to existing variables.
- for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) {
- if (TiedToMap[I] < 0)
- continue; // dropping non-tied ones.
- updateExplicitOperandVariable(RegInfo, InstrInfo, I, ReservedRegs,
- findVariableWithOperand(Vars, TiedToMap[I]));
- }
- // Adding implicit defs.
- for (size_t I = 0, E = InstrInfo.getNumImplicitDefs(); I < E; ++I) {
- Vars.emplace_back();
- Variable &Var = Vars.back();
- const llvm::MCPhysReg Reg = InstrInfo.getImplicitDefs()[I];
- assert(!ReservedRegs[Reg] && "implicit def of reserved register");
- Var.PossibleRegisters.insert(Reg);
- Var.IsDef = true;
- Var.IsReg = true;
- }
- // Adding implicit uses.
- for (size_t I = 0, E = InstrInfo.getNumImplicitUses(); I < E; ++I) {
- Vars.emplace_back();
- Variable &Var = Vars.back();
- const llvm::MCPhysReg Reg = InstrInfo.getImplicitUses()[I];
- assert(!ReservedRegs[Reg] && "implicit use of reserved register");
- Var.PossibleRegisters.insert(Reg);
- Var.IsUse = true;
- Var.IsReg = true;
- }
-
- return Vars;
-}
-
-VariableAssignment::VariableAssignment(size_t VarIdx,
- llvm::MCPhysReg AssignedReg)
- : VarIdx(VarIdx), AssignedReg(AssignedReg) {}
-
-bool VariableAssignment::operator==(const VariableAssignment &Other) const {
- return std::tie(VarIdx, AssignedReg) ==
- std::tie(Other.VarIdx, Other.AssignedReg);
-}
-
-bool VariableAssignment::operator<(const VariableAssignment &Other) const {
- return std::tie(VarIdx, AssignedReg) <
- std::tie(Other.VarIdx, Other.AssignedReg);
-}
-
-void dumpAssignmentChain(const llvm::MCRegisterInfo &RegInfo,
- const AssignmentChain &Chain) {
- for (const VariableAssignment &Assignment : Chain) {
- llvm::outs() << llvm::format("(%d %s) ", Assignment.VarIdx,
- RegInfo.getName(Assignment.AssignedReg));
- }
- llvm::outs() << "\n";
-}
-
-std::vector<AssignmentChain>
-computeSequentialAssignmentChains(const llvm::MCRegisterInfo &RegInfo,
- llvm::ArrayRef<Variable> Vars) {
- using graph::Node;
- graph::Graph Graph;
-
- // Add register aliasing to the graph.
- setupRegisterAliasing(RegInfo, Graph);
-
- // Adding variables to the graph.
- for (size_t I = 0, E = Vars.size(); I < E; ++I) {
- const Variable &Var = Vars[I];
- const Node N = Node::Var(I);
- if (Var.IsDef) {
- Graph.connect(Node::In(), N);
- for (const size_t Reg : Var.PossibleRegisters)
- Graph.connect(N, Node::Reg(Reg));
- }
- if (Var.IsUse) {
- Graph.connect(N, Node::Out());
- for (const size_t Reg : Var.PossibleRegisters)
- Graph.connect(Node::Reg(Reg), N);
- }
- }
-
- // Find all possible dependency chains (aka all possible paths from In to Out
- // node).
- std::vector<AssignmentChain> AllChains;
- for (;;) {
- const auto Path = Graph.getPathFrom(Node::In(), Node::Out());
- if (Path.empty())
- break;
- switch (Path.size()) {
- case 0:
- case 1:
- case 2:
- case 4:
- assert(false && "Illegal state");
- break;
- case 3: { // IN -> variable -> OUT
- const size_t VarIdx = Path[1].varValue();
- for (size_t Reg : Vars[VarIdx].PossibleRegisters) {
- AllChains.emplace_back();
- AllChains.back().emplace(VarIdx, Reg);
- }
- Graph.disconnect(Path[0], Path[1]); // IN -> variable
- Graph.disconnect(Path[1], Path[2]); // variable -> OUT
- break;
- }
- default: { // IN -> var1 -> Reg[...] -> var2 -> OUT
- const size_t Last = Path.size() - 1;
- const size_t Var1 = Path[1].varValue();
- const llvm::MCPhysReg Reg1 = Path[2].regValue();
- const llvm::MCPhysReg Reg2 = Path[Last - 2].regValue();
- const size_t Var2 = Path[Last - 1].varValue();
- AllChains.emplace_back();
- AllChains.back().emplace(Var1, Reg1);
- AllChains.back().emplace(Var2, Reg2);
- Graph.disconnect(Path[1], Path[2]); // Var1 -> Reg[0]
- break;
- }
- }
- }
-
- return AllChains;
-}
-
-std::vector<llvm::MCPhysReg>
-getRandomAssignment(llvm::ArrayRef<Variable> Vars,
- llvm::ArrayRef<AssignmentChain> Chains,
- const std::function<size_t(size_t)> &RandomIndexForSize) {
- // Registers are initialized with 0 (aka NoRegister).
- std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
- if (Chains.empty())
- return Registers;
- // Pick one of the chains and set Registers that are fully constrained (have
- // no degrees of freedom).
- const size_t ChainIndex = RandomIndexForSize(Chains.size());
- for (const VariableAssignment Assignment : Chains[ChainIndex])
- Registers[Assignment.VarIdx] = Assignment.AssignedReg;
- // Registers with remaining degrees of freedom are assigned randomly.
- for (size_t I = 0, E = Vars.size(); I < E; ++I) {
- llvm::MCPhysReg &Reg = Registers[I];
- const Variable &Var = Vars[I];
- const auto &PossibleRegisters = Var.PossibleRegisters;
- if (Reg > 0 || PossibleRegisters.empty())
- continue;
- Reg = PossibleRegisters[RandomIndexForSize(PossibleRegisters.size())];
- }
- return Registers;
-}
-
-// Finds a matching register `reg` for variable `VarIdx` and sets
-// `RegAssignments[r]` to `VarIdx`. Returns false if no matching can be found.
-// `seen.count(r)` is 1 if register `reg` has been processed.
-static bool findMatchingRegister(
- llvm::ArrayRef<Variable> Vars, const size_t VarIdx,
- std::unordered_set<llvm::MCPhysReg> &Seen,
- std::unordered_map<llvm::MCPhysReg, size_t> &RegAssignments) {
- for (const llvm::MCPhysReg Reg : Vars[VarIdx].PossibleRegisters) {
- if (!Seen.count(Reg)) {
- Seen.insert(Reg); // Mark `Reg` as seen.
- // If `Reg` is not assigned to a variable, or if `Reg` was assigned to a
- // variable which has an alternate possible register, assign `Reg` to
- // variable `VarIdx`. Since `Reg` is marked as assigned in the above line,
- // `RegAssignments[r]` in the following recursive call will not get
- // assigned `Reg` again.
- const auto AssignedVarIt = RegAssignments.find(Reg);
- if (AssignedVarIt == RegAssignments.end() ||
- findMatchingRegister(Vars, AssignedVarIt->second, Seen,
- RegAssignments)) {
- RegAssignments[Reg] = VarIdx;
- return true;
- }
- }
- }
- return false;
-}
-
-// This is actually a maximum bipartite matching problem:
-// https://en.wikipedia.org/wiki/Matching_(graph_theory)#Bipartite_matching
-// The graph has variables on the left and registers on the right, with an edge
-// between variable `I` and register `Reg` iff
-// `Vars[I].PossibleRegisters.count(A)`.
-// Note that a greedy approach won't work for cases like:
-// Vars[0] PossibleRegisters={C,B}
-// Vars[1] PossibleRegisters={A,B}
-// Vars[2] PossibleRegisters={A,C}
-// There is a feasible solution {0->B, 1->A, 2->C}, but the greedy solution is
-// {0->C, 1->A, oops}.
-std::vector<llvm::MCPhysReg>
-getExclusiveAssignment(llvm::ArrayRef<Variable> Vars) {
- // `RegAssignments[r]` is the variable id that was assigned register `Reg`.
- std::unordered_map<llvm::MCPhysReg, size_t> RegAssignments;
-
- for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E; ++VarIdx) {
- if (!Vars[VarIdx].IsReg)
- continue;
- std::unordered_set<llvm::MCPhysReg> Seen;
- if (!findMatchingRegister(Vars, VarIdx, Seen, RegAssignments))
- return {}; // Infeasible.
- }
-
- std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
- for (const auto &RegVarIdx : RegAssignments)
- Registers[RegVarIdx.second] = RegVarIdx.first;
- return Registers;
-}
-
-std::vector<llvm::MCPhysReg>
-getGreedyAssignment(llvm::ArrayRef<Variable> Vars) {
- std::vector<llvm::MCPhysReg> Registers(Vars.size(), 0);
- llvm::SmallSet<llvm::MCPhysReg, 8> Assigned;
- for (size_t VarIdx = 0, E = Vars.size(); VarIdx < E; ++VarIdx) {
- const auto &Var = Vars[VarIdx];
- if (!Var.IsReg)
- continue;
- if (Var.PossibleRegisters.empty())
- return {};
- // Try possible registers until an unassigned one is found.
- for (const auto Reg : Var.PossibleRegisters) {
- if (Assigned.insert(Reg).second) {
- Registers[VarIdx] = Reg;
- break;
- }
- }
- // Fallback to first possible register.
- if (Registers[VarIdx] == 0)
- Registers[VarIdx] = Var.PossibleRegisters[0];
- }
- return Registers;
-}
-
-llvm::MCInst generateMCInst(const llvm::MCInstrDesc &InstrInfo,
- llvm::ArrayRef<Variable> Vars,
- llvm::ArrayRef<llvm::MCPhysReg> VarRegs) {
- const size_t NumOperands = InstrInfo.getNumOperands();
- llvm::SmallVector<llvm::MCPhysReg, 16> OperandToRegister(NumOperands, 0);
-
- // We browse the variable and for each explicit operands we set the selected
- // register in the OperandToRegister array.
- for (size_t I = 0, E = Vars.size(); I < E; ++I) {
- for (const size_t OpIndex : Vars[I].ExplicitOperands) {
- OperandToRegister[OpIndex] = VarRegs[I];
- }
- }
-
- // Building the instruction.
- llvm::MCInstBuilder Builder(InstrInfo.getOpcode());
- for (size_t I = 0, E = InstrInfo.getNumOperands(); I < E; ++I) {
- const llvm::MCOperandInfo &OpInfo = InstrInfo.opInfo_begin()[I];
- switch (OpInfo.OperandType) {
- case llvm::MCOI::OperandType::OPERAND_REGISTER:
- Builder.addReg(OperandToRegister[I]);
- break;
- case llvm::MCOI::OperandType::OPERAND_IMMEDIATE:
- Builder.addImm(1);
- break;
- default:
- Builder.addOperand(llvm::MCOperand());
- }
- }
-
- return Builder;
-}
-
-} // namespace exegesis
OpenPOWER on IntegriCloud