11d94fb21SDaniel Sanders //===- GIMatchTree.cpp - A decision tree to match GIMatchDag's ------------===//
21d94fb21SDaniel Sanders //
31d94fb21SDaniel Sanders // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
41d94fb21SDaniel Sanders // See https://llvm.org/LICENSE.txt for license information.
51d94fb21SDaniel Sanders // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
61d94fb21SDaniel Sanders //
71d94fb21SDaniel Sanders //===----------------------------------------------------------------------===//
81d94fb21SDaniel Sanders
91d94fb21SDaniel Sanders #include "GIMatchTree.h"
10*bd059b3bSserge-sans-paille #include "GIMatchDagPredicate.h"
111d94fb21SDaniel Sanders
121d94fb21SDaniel Sanders #include "../CodeGenInstruction.h"
131d94fb21SDaniel Sanders
14af450eabSReid Kleckner #include "llvm/Support/Debug.h"
151d94fb21SDaniel Sanders #include "llvm/Support/Format.h"
161d94fb21SDaniel Sanders #include "llvm/Support/ScopedPrinter.h"
171d94fb21SDaniel Sanders #include "llvm/Support/raw_ostream.h"
181d94fb21SDaniel Sanders #include "llvm/TableGen/Error.h"
191d94fb21SDaniel Sanders #include "llvm/TableGen/Record.h"
201d94fb21SDaniel Sanders
211d94fb21SDaniel Sanders #define DEBUG_TYPE "gimatchtree"
221d94fb21SDaniel Sanders
231d94fb21SDaniel Sanders using namespace llvm;
241d94fb21SDaniel Sanders
writeDOTGraph(raw_ostream & OS) const251d94fb21SDaniel Sanders void GIMatchTree::writeDOTGraph(raw_ostream &OS) const {
261d94fb21SDaniel Sanders OS << "digraph \"matchtree\" {\n";
271d94fb21SDaniel Sanders writeDOTGraphNode(OS);
281d94fb21SDaniel Sanders OS << "}\n";
291d94fb21SDaniel Sanders }
301d94fb21SDaniel Sanders
writeDOTGraphNode(raw_ostream & OS) const311d94fb21SDaniel Sanders void GIMatchTree::writeDOTGraphNode(raw_ostream &OS) const {
321d94fb21SDaniel Sanders OS << format(" Node%p", this) << " [shape=record,label=\"{";
331d94fb21SDaniel Sanders if (Partitioner) {
341d94fb21SDaniel Sanders Partitioner->emitDescription(OS);
351d94fb21SDaniel Sanders OS << "|" << Partitioner->getNumPartitions() << " partitions|";
361d94fb21SDaniel Sanders } else
371d94fb21SDaniel Sanders OS << "No partitioner|";
381d94fb21SDaniel Sanders bool IsFullyTraversed = true;
391d94fb21SDaniel Sanders bool IsFullyTested = true;
401d94fb21SDaniel Sanders StringRef Separator = "";
411d94fb21SDaniel Sanders for (const auto &Leaf : PossibleLeaves) {
421d94fb21SDaniel Sanders OS << Separator << Leaf.getName();
431d94fb21SDaniel Sanders Separator = ",";
441d94fb21SDaniel Sanders if (!Leaf.isFullyTraversed())
451d94fb21SDaniel Sanders IsFullyTraversed = false;
461d94fb21SDaniel Sanders if (!Leaf.isFullyTested())
471d94fb21SDaniel Sanders IsFullyTested = false;
481d94fb21SDaniel Sanders }
491d94fb21SDaniel Sanders if (!Partitioner && !IsFullyTraversed)
501d94fb21SDaniel Sanders OS << "|Not fully traversed";
511d94fb21SDaniel Sanders if (!Partitioner && !IsFullyTested) {
521d94fb21SDaniel Sanders OS << "|Not fully tested";
531d94fb21SDaniel Sanders if (IsFullyTraversed) {
541d94fb21SDaniel Sanders for (const GIMatchTreeLeafInfo &Leaf : PossibleLeaves) {
551d94fb21SDaniel Sanders if (Leaf.isFullyTested())
561d94fb21SDaniel Sanders continue;
571d94fb21SDaniel Sanders OS << "\\n" << Leaf.getName() << ": " << &Leaf;
581d94fb21SDaniel Sanders for (const GIMatchDagPredicate *P : Leaf.untested_predicates())
591d94fb21SDaniel Sanders OS << *P;
601d94fb21SDaniel Sanders }
611d94fb21SDaniel Sanders }
621d94fb21SDaniel Sanders }
631d94fb21SDaniel Sanders OS << "}\"";
641d94fb21SDaniel Sanders if (!Partitioner &&
651d94fb21SDaniel Sanders (!IsFullyTraversed || !IsFullyTested || PossibleLeaves.size() > 1))
661d94fb21SDaniel Sanders OS << ",color=red";
671d94fb21SDaniel Sanders OS << "]\n";
681d94fb21SDaniel Sanders for (const auto &C : Children)
691d94fb21SDaniel Sanders C.writeDOTGraphNode(OS);
701d94fb21SDaniel Sanders writeDOTGraphEdges(OS);
711d94fb21SDaniel Sanders }
721d94fb21SDaniel Sanders
writeDOTGraphEdges(raw_ostream & OS) const731d94fb21SDaniel Sanders void GIMatchTree::writeDOTGraphEdges(raw_ostream &OS) const {
741d94fb21SDaniel Sanders for (const auto &Child : enumerate(Children)) {
751d94fb21SDaniel Sanders OS << format(" Node%p", this) << " -> " << format("Node%p", &Child.value())
761d94fb21SDaniel Sanders << " [label=\"#" << Child.index() << " ";
771d94fb21SDaniel Sanders Partitioner->emitPartitionName(OS, Child.index());
781d94fb21SDaniel Sanders OS << "\"]\n";
791d94fb21SDaniel Sanders }
801d94fb21SDaniel Sanders }
811d94fb21SDaniel Sanders
GIMatchTreeBuilderLeafInfo(GIMatchTreeBuilder & Builder,StringRef Name,unsigned RootIdx,const GIMatchDag & MatchDag,void * Data)821d94fb21SDaniel Sanders GIMatchTreeBuilderLeafInfo::GIMatchTreeBuilderLeafInfo(
831d94fb21SDaniel Sanders GIMatchTreeBuilder &Builder, StringRef Name, unsigned RootIdx,
841d94fb21SDaniel Sanders const GIMatchDag &MatchDag, void *Data)
851d94fb21SDaniel Sanders : Builder(Builder), Info(Name, RootIdx, Data), MatchDag(MatchDag),
861d94fb21SDaniel Sanders RemainingInstrNodes(BitVector(MatchDag.getNumInstrNodes(), true)),
871d94fb21SDaniel Sanders RemainingEdges(BitVector(MatchDag.getNumEdges(), true)),
881d94fb21SDaniel Sanders RemainingPredicates(BitVector(MatchDag.getNumPredicates(), true)),
891d94fb21SDaniel Sanders TraversableEdges(MatchDag.getNumEdges()),
901d94fb21SDaniel Sanders TestablePredicates(MatchDag.getNumPredicates()) {
911d94fb21SDaniel Sanders // Number all the predicates in this DAG
921d94fb21SDaniel Sanders for (auto &P : enumerate(MatchDag.predicates())) {
931d94fb21SDaniel Sanders PredicateIDs.insert(std::make_pair(P.value(), P.index()));
941d94fb21SDaniel Sanders }
951d94fb21SDaniel Sanders
961d94fb21SDaniel Sanders // Number all the predicate dependencies in this DAG and set up a bitvector
971d94fb21SDaniel Sanders // for each predicate indicating the unsatisfied dependencies.
981d94fb21SDaniel Sanders for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
991d94fb21SDaniel Sanders PredicateDepIDs.insert(std::make_pair(Dep.value(), Dep.index()));
1001d94fb21SDaniel Sanders }
1011d94fb21SDaniel Sanders UnsatisfiedPredDepsForPred.resize(MatchDag.getNumPredicates(),
1021d94fb21SDaniel Sanders BitVector(PredicateDepIDs.size()));
1031d94fb21SDaniel Sanders for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
1041d94fb21SDaniel Sanders unsigned ID = PredicateIDs.lookup(Dep.value()->getPredicate());
1051d94fb21SDaniel Sanders UnsatisfiedPredDepsForPred[ID].set(Dep.index());
1061d94fb21SDaniel Sanders }
1071d94fb21SDaniel Sanders }
1081d94fb21SDaniel Sanders
declareInstr(const GIMatchDagInstr * Instr,unsigned ID)1091d94fb21SDaniel Sanders void GIMatchTreeBuilderLeafInfo::declareInstr(const GIMatchDagInstr *Instr, unsigned ID) {
1101d94fb21SDaniel Sanders // Record the assignment of this instr to the given ID.
1111d94fb21SDaniel Sanders auto InfoI = InstrNodeToInfo.insert(std::make_pair(
1121d94fb21SDaniel Sanders Instr, GIMatchTreeInstrInfo(ID, Instr)));
1131d94fb21SDaniel Sanders InstrIDToInfo.insert(std::make_pair(ID, &InfoI.first->second));
1141d94fb21SDaniel Sanders
1151d94fb21SDaniel Sanders if (Instr == nullptr)
1161d94fb21SDaniel Sanders return;
1171d94fb21SDaniel Sanders
1181d94fb21SDaniel Sanders if (!Instr->getUserAssignedName().empty())
1191d94fb21SDaniel Sanders Info.bindInstrVariable(Instr->getUserAssignedName(), ID);
1201d94fb21SDaniel Sanders for (const auto &VarBinding : Instr->user_assigned_operand_names())
1211d94fb21SDaniel Sanders Info.bindOperandVariable(VarBinding.second, ID, VarBinding.first);
1221d94fb21SDaniel Sanders
1231d94fb21SDaniel Sanders // Clear the bit indicating we haven't visited this instr.
12488572024SKazu Hirata const auto &NodeI = find(MatchDag.instr_nodes(), Instr);
1251d94fb21SDaniel Sanders assert(NodeI != MatchDag.instr_nodes_end() && "Instr isn't in this DAG");
1261d94fb21SDaniel Sanders unsigned InstrIdx = MatchDag.getInstrNodeIdx(NodeI);
1271d94fb21SDaniel Sanders RemainingInstrNodes.reset(InstrIdx);
1281d94fb21SDaniel Sanders
1291d94fb21SDaniel Sanders // When we declare an instruction, we don't expose any traversable edges just
1301d94fb21SDaniel Sanders // yet. A partitioner has to check they exist and are registers before they
1311d94fb21SDaniel Sanders // are traversable.
1321d94fb21SDaniel Sanders
1331d94fb21SDaniel Sanders // When we declare an instruction, we potentially activate some predicates.
1341d94fb21SDaniel Sanders // Mark the dependencies that are now satisfied as a result of this
1351d94fb21SDaniel Sanders // instruction and mark any predicates whose dependencies are fully
1361d94fb21SDaniel Sanders // satisfied.
1371d94fb21SDaniel Sanders for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
1381d94fb21SDaniel Sanders if (Dep.value()->getRequiredMI() == Instr &&
1391d94fb21SDaniel Sanders Dep.value()->getRequiredMO() == nullptr) {
1401d94fb21SDaniel Sanders for (auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
1411d94fb21SDaniel Sanders DepsFor.value().reset(Dep.index());
1421d94fb21SDaniel Sanders if (DepsFor.value().none())
1431d94fb21SDaniel Sanders TestablePredicates.set(DepsFor.index());
1441d94fb21SDaniel Sanders }
1451d94fb21SDaniel Sanders }
1461d94fb21SDaniel Sanders }
1471d94fb21SDaniel Sanders }
1481d94fb21SDaniel Sanders
declareOperand(unsigned InstrID,unsigned OpIdx)1491d94fb21SDaniel Sanders void GIMatchTreeBuilderLeafInfo::declareOperand(unsigned InstrID,
1501d94fb21SDaniel Sanders unsigned OpIdx) {
1511d94fb21SDaniel Sanders const GIMatchDagInstr *Instr = InstrIDToInfo.lookup(InstrID)->getInstrNode();
1521d94fb21SDaniel Sanders
1531d94fb21SDaniel Sanders OperandIDToInfo.insert(std::make_pair(
1541d94fb21SDaniel Sanders std::make_pair(InstrID, OpIdx),
1551d94fb21SDaniel Sanders GIMatchTreeOperandInfo(Instr, OpIdx)));
1561d94fb21SDaniel Sanders
1571d94fb21SDaniel Sanders // When an operand becomes reachable, we potentially activate some traversals.
1581d94fb21SDaniel Sanders // Record the edges that can now be followed as a result of this
1591d94fb21SDaniel Sanders // instruction.
1601d94fb21SDaniel Sanders for (auto &E : enumerate(MatchDag.edges())) {
1611d94fb21SDaniel Sanders if (E.value()->getFromMI() == Instr &&
1621d94fb21SDaniel Sanders E.value()->getFromMO()->getIdx() == OpIdx) {
1631d94fb21SDaniel Sanders TraversableEdges.set(E.index());
1641d94fb21SDaniel Sanders }
1651d94fb21SDaniel Sanders }
1661d94fb21SDaniel Sanders
1671d94fb21SDaniel Sanders // When an operand becomes reachable, we potentially activate some predicates.
1681d94fb21SDaniel Sanders // Clear the dependencies that are now satisfied as a result of this
1691d94fb21SDaniel Sanders // operand and activate any predicates whose dependencies are fully
1701d94fb21SDaniel Sanders // satisfied.
1711d94fb21SDaniel Sanders for (auto &Dep : enumerate(MatchDag.predicate_edges())) {
1721d94fb21SDaniel Sanders if (Dep.value()->getRequiredMI() == Instr && Dep.value()->getRequiredMO() &&
1731d94fb21SDaniel Sanders Dep.value()->getRequiredMO()->getIdx() == OpIdx) {
1741d94fb21SDaniel Sanders for (auto &DepsFor : enumerate(UnsatisfiedPredDepsForPred)) {
1751d94fb21SDaniel Sanders DepsFor.value().reset(Dep.index());
1761d94fb21SDaniel Sanders if (DepsFor.value().none())
1771d94fb21SDaniel Sanders TestablePredicates.set(DepsFor.index());
1781d94fb21SDaniel Sanders }
1791d94fb21SDaniel Sanders }
1801d94fb21SDaniel Sanders }
1811d94fb21SDaniel Sanders }
1821d94fb21SDaniel Sanders
addPartitionersForInstr(unsigned InstrIdx)1831d94fb21SDaniel Sanders void GIMatchTreeBuilder::addPartitionersForInstr(unsigned InstrIdx) {
1841d94fb21SDaniel Sanders // Find the partitioners that can be used now that this node is
1851d94fb21SDaniel Sanders // uncovered. Our choices are:
1861d94fb21SDaniel Sanders // - Test the opcode
1871d94fb21SDaniel Sanders addPartitioner(std::make_unique<GIMatchTreeOpcodePartitioner>(InstrIdx));
1881d94fb21SDaniel Sanders }
1891d94fb21SDaniel Sanders
addPartitionersForOperand(unsigned InstrID,unsigned OpIdx)1901d94fb21SDaniel Sanders void GIMatchTreeBuilder::addPartitionersForOperand(unsigned InstrID,
1911d94fb21SDaniel Sanders unsigned OpIdx) {
1921d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << "Add partitioners for Instrs[" << InstrID
1931d94fb21SDaniel Sanders << "].getOperand(" << OpIdx << ")\n");
1941d94fb21SDaniel Sanders addPartitioner(
1951d94fb21SDaniel Sanders std::make_unique<GIMatchTreeVRegDefPartitioner>(InstrID, OpIdx));
1961d94fb21SDaniel Sanders }
1971d94fb21SDaniel Sanders
filterRedundantPartitioners()1981d94fb21SDaniel Sanders void GIMatchTreeBuilder::filterRedundantPartitioners() {
1991d94fb21SDaniel Sanders // TODO: Filter partitioners for facts that are already known
2001d94fb21SDaniel Sanders // - If we know the opcode, we can elide the num operand check so long as
2011d94fb21SDaniel Sanders // the instruction has a fixed number of operands.
2021d94fb21SDaniel Sanders // - If we know an exact number of operands then we can elide further number
2031d94fb21SDaniel Sanders // of operand checks.
2041d94fb21SDaniel Sanders // - If the current min number of operands exceeds the one we want to check
2051d94fb21SDaniel Sanders // then we can elide it.
2061d94fb21SDaniel Sanders }
2071d94fb21SDaniel Sanders
evaluatePartitioners()2081d94fb21SDaniel Sanders void GIMatchTreeBuilder::evaluatePartitioners() {
2091d94fb21SDaniel Sanders // Determine the partitioning the partitioner would produce
2101d94fb21SDaniel Sanders for (auto &Partitioner : Partitioners) {
2111d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Weighing up ";
2121d94fb21SDaniel Sanders Partitioner->emitDescription(dbgs()); dbgs() << "\n");
2131d94fb21SDaniel Sanders Partitioner->repartition(Leaves);
2141d94fb21SDaniel Sanders LLVM_DEBUG(Partitioner->emitPartitionResults(dbgs()));
2151d94fb21SDaniel Sanders }
2161d94fb21SDaniel Sanders }
2171d94fb21SDaniel Sanders
runStep()2181d94fb21SDaniel Sanders void GIMatchTreeBuilder::runStep() {
2191d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << "Building match tree node for " << TreeNode << "\n");
2201d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Rules reachable at this node:\n");
2211d94fb21SDaniel Sanders for (const auto &Leaf : Leaves) {
2221d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " " << Leaf.getName() << " (" << &Leaf.getInfo() << "\n");
2231d94fb21SDaniel Sanders TreeNode->addPossibleLeaf(Leaf.getInfo(), Leaf.isFullyTraversed(),
2241d94fb21SDaniel Sanders Leaf.isFullyTested());
2251d94fb21SDaniel Sanders }
2261d94fb21SDaniel Sanders
2271d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Partitioners available at this node:\n");
2281d94fb21SDaniel Sanders #ifndef NDEBUG
2291d94fb21SDaniel Sanders for (const auto &Partitioner : Partitioners)
2301d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " "; Partitioner->emitDescription(dbgs());
2311d94fb21SDaniel Sanders dbgs() << "\n");
2321d94fb21SDaniel Sanders #endif // ifndef NDEBUG
2331d94fb21SDaniel Sanders
2341d94fb21SDaniel Sanders // Check for unreachable rules. Rules are unreachable if they are preceeded by
2351d94fb21SDaniel Sanders // a fully tested rule.
2361d94fb21SDaniel Sanders // Note: This is only true for the current algorithm, if we allow the
2371d94fb21SDaniel Sanders // algorithm to compare equally valid rules then they will become
2381d94fb21SDaniel Sanders // reachable.
2391d94fb21SDaniel Sanders {
2401d94fb21SDaniel Sanders auto FullyTestedLeafI = Leaves.end();
2411d94fb21SDaniel Sanders for (auto LeafI = Leaves.begin(), LeafE = Leaves.end();
2421d94fb21SDaniel Sanders LeafI != LeafE; ++LeafI) {
2431d94fb21SDaniel Sanders if (LeafI->isFullyTraversed() && LeafI->isFullyTested())
2441d94fb21SDaniel Sanders FullyTestedLeafI = LeafI;
2451d94fb21SDaniel Sanders else if (FullyTestedLeafI != Leaves.end()) {
2461d94fb21SDaniel Sanders PrintError("Leaf " + LeafI->getName() + " is unreachable");
2471d94fb21SDaniel Sanders PrintNote("Leaf " + FullyTestedLeafI->getName() +
2481d94fb21SDaniel Sanders " will have already matched");
2491d94fb21SDaniel Sanders }
2501d94fb21SDaniel Sanders }
2511d94fb21SDaniel Sanders }
2521d94fb21SDaniel Sanders
2531d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Eliminating redundant partitioners:\n");
2541d94fb21SDaniel Sanders filterRedundantPartitioners();
2551d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Partitioners remaining:\n");
2561d94fb21SDaniel Sanders #ifndef NDEBUG
2571d94fb21SDaniel Sanders for (const auto &Partitioner : Partitioners)
2581d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " "; Partitioner->emitDescription(dbgs());
2591d94fb21SDaniel Sanders dbgs() << "\n");
2601d94fb21SDaniel Sanders #endif // ifndef NDEBUG
2611d94fb21SDaniel Sanders
2621d94fb21SDaniel Sanders if (Partitioners.empty()) {
2631d94fb21SDaniel Sanders // Nothing left to do but check we really did identify a single rule.
2641d94fb21SDaniel Sanders if (Leaves.size() > 1) {
2651d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << "Leaf contains multiple rules, drop after the first "
2661d94fb21SDaniel Sanders "fully tested rule\n");
2671d94fb21SDaniel Sanders auto FirstFullyTested =
2681c5b8482SKazu Hirata llvm::find_if(Leaves, [](const GIMatchTreeBuilderLeafInfo &X) {
2691d94fb21SDaniel Sanders return X.isFullyTraversed() && X.isFullyTested() &&
2701d94fb21SDaniel Sanders !X.getMatchDag().hasPostMatchPredicate();
2711d94fb21SDaniel Sanders });
2721d94fb21SDaniel Sanders if (FirstFullyTested != Leaves.end())
2731d94fb21SDaniel Sanders FirstFullyTested++;
2741d94fb21SDaniel Sanders
2751d94fb21SDaniel Sanders #ifndef NDEBUG
2761d94fb21SDaniel Sanders for (auto &Leaf : make_range(Leaves.begin(), FirstFullyTested))
2771d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Kept " << Leaf.getName() << "\n");
2781d94fb21SDaniel Sanders for (const auto &Leaf : make_range(FirstFullyTested, Leaves.end()))
2791d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Dropped " << Leaf.getName() << "\n");
2801d94fb21SDaniel Sanders #endif // ifndef NDEBUG
2811d94fb21SDaniel Sanders TreeNode->dropLeavesAfter(
2821d94fb21SDaniel Sanders std::distance(Leaves.begin(), FirstFullyTested));
2831d94fb21SDaniel Sanders }
2841d94fb21SDaniel Sanders for (const auto &Leaf : Leaves) {
2851d94fb21SDaniel Sanders if (!Leaf.isFullyTraversed()) {
2861d94fb21SDaniel Sanders PrintError("Leaf " + Leaf.getName() + " is not fully traversed");
2871d94fb21SDaniel Sanders PrintNote("This indicates a missing partitioner within tblgen");
2881d94fb21SDaniel Sanders Leaf.dump(errs());
2891d94fb21SDaniel Sanders for (unsigned InstrIdx : Leaf.untested_instrs())
2901d94fb21SDaniel Sanders PrintNote("Instr " + llvm::to_string(*Leaf.getInstr(InstrIdx)));
2911d94fb21SDaniel Sanders for (unsigned EdgeIdx : Leaf.untested_edges())
2921d94fb21SDaniel Sanders PrintNote("Edge " + llvm::to_string(*Leaf.getEdge(EdgeIdx)));
2931d94fb21SDaniel Sanders }
2941d94fb21SDaniel Sanders }
2951d94fb21SDaniel Sanders
2961d94fb21SDaniel Sanders // Copy out information about untested predicates so the user of the tree
2971d94fb21SDaniel Sanders // can deal with them.
2981d94fb21SDaniel Sanders for (auto LeafPair : zip(Leaves, TreeNode->possible_leaves())) {
2991d94fb21SDaniel Sanders const GIMatchTreeBuilderLeafInfo &BuilderLeaf = std::get<0>(LeafPair);
3001d94fb21SDaniel Sanders GIMatchTreeLeafInfo &TreeLeaf = std::get<1>(LeafPair);
3011d94fb21SDaniel Sanders if (!BuilderLeaf.isFullyTested())
3021d94fb21SDaniel Sanders for (unsigned PredicateIdx : BuilderLeaf.untested_predicates())
3031d94fb21SDaniel Sanders TreeLeaf.addUntestedPredicate(BuilderLeaf.getPredicate(PredicateIdx));
3041d94fb21SDaniel Sanders }
3051d94fb21SDaniel Sanders return;
3061d94fb21SDaniel Sanders }
3071d94fb21SDaniel Sanders
3081d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Weighing up partitioners:\n");
3091d94fb21SDaniel Sanders evaluatePartitioners();
3101d94fb21SDaniel Sanders
3111d94fb21SDaniel Sanders // Select the best partitioner by its ability to partition
3121d94fb21SDaniel Sanders // - Prefer partitioners that don't distinguish between partitions. This
3131d94fb21SDaniel Sanders // is to fail early on decisions that must go a single way.
3141d94fb21SDaniel Sanders auto PartitionerI = std::max_element(
3151d94fb21SDaniel Sanders Partitioners.begin(), Partitioners.end(),
3161d94fb21SDaniel Sanders [](const std::unique_ptr<GIMatchTreePartitioner> &A,
3171d94fb21SDaniel Sanders const std::unique_ptr<GIMatchTreePartitioner> &B) {
3181d94fb21SDaniel Sanders // We generally want partitioners that subdivide the
3191d94fb21SDaniel Sanders // ruleset as much as possible since these take fewer
3201d94fb21SDaniel Sanders // checks to converge on a particular rule. However,
3211d94fb21SDaniel Sanders // it's important to note that one leaf can end up in
3221d94fb21SDaniel Sanders // multiple partitions if the check isn't mutually
3231d94fb21SDaniel Sanders // exclusive (e.g. getVRegDef() vs isReg()).
3241d94fb21SDaniel Sanders // We therefore minimize average leaves per partition.
3251d94fb21SDaniel Sanders return (double)A->getNumLeavesWithDupes() / A->getNumPartitions() >
3261d94fb21SDaniel Sanders (double)B->getNumLeavesWithDupes() / B->getNumPartitions();
3271d94fb21SDaniel Sanders });
3281d94fb21SDaniel Sanders
3291d94fb21SDaniel Sanders // Select a partitioner and partition the ruleset
3301d94fb21SDaniel Sanders // Note that it's possible for a single rule to end up in multiple
3311d94fb21SDaniel Sanders // partitions. For example, an opcode test on a rule without an opcode
3321d94fb21SDaniel Sanders // predicate will result in it being passed to all partitions.
3331d94fb21SDaniel Sanders std::unique_ptr<GIMatchTreePartitioner> Partitioner = std::move(*PartitionerI);
3341d94fb21SDaniel Sanders Partitioners.erase(PartitionerI);
3351d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Selected partitioner: ";
3361d94fb21SDaniel Sanders Partitioner->emitDescription(dbgs()); dbgs() << "\n");
3371d94fb21SDaniel Sanders
3381d94fb21SDaniel Sanders assert(Partitioner->getNumPartitions() > 0 &&
3391d94fb21SDaniel Sanders "Must always partition into at least one partition");
3401d94fb21SDaniel Sanders
3411d94fb21SDaniel Sanders TreeNode->setNumChildren(Partitioner->getNumPartitions());
3421d94fb21SDaniel Sanders for (auto &C : enumerate(TreeNode->children())) {
3431d94fb21SDaniel Sanders SubtreeBuilders.emplace_back(&C.value(), NextInstrID);
3441d94fb21SDaniel Sanders Partitioner->applyForPartition(C.index(), *this, SubtreeBuilders.back());
3451d94fb21SDaniel Sanders }
3461d94fb21SDaniel Sanders
3471d94fb21SDaniel Sanders TreeNode->setPartitioner(std::move(Partitioner));
3481d94fb21SDaniel Sanders
3491d94fb21SDaniel Sanders // Recurse into the subtree builders. Each one must get a copy of the
3501d94fb21SDaniel Sanders // remaining partitioners as each path has to check everything.
3511d94fb21SDaniel Sanders for (auto &SubtreeBuilder : SubtreeBuilders) {
3521d94fb21SDaniel Sanders for (const auto &Partitioner : Partitioners)
3531d94fb21SDaniel Sanders SubtreeBuilder.addPartitioner(Partitioner->clone());
3541d94fb21SDaniel Sanders SubtreeBuilder.runStep();
3551d94fb21SDaniel Sanders }
3561d94fb21SDaniel Sanders }
3571d94fb21SDaniel Sanders
run()3581d94fb21SDaniel Sanders std::unique_ptr<GIMatchTree> GIMatchTreeBuilder::run() {
3591d94fb21SDaniel Sanders unsigned NewInstrID = allocInstrID();
3601d94fb21SDaniel Sanders // Start by recording the root instruction as instr #0 and set up the initial
3611d94fb21SDaniel Sanders // partitioners.
3621d94fb21SDaniel Sanders for (auto &Leaf : Leaves) {
3631d94fb21SDaniel Sanders LLVM_DEBUG(Leaf.getMatchDag().writeDOTGraph(dbgs(), Leaf.getName()));
3641d94fb21SDaniel Sanders GIMatchDagInstr *Root =
3651d94fb21SDaniel Sanders *(Leaf.getMatchDag().roots().begin() + Leaf.getRootIdx());
3661d94fb21SDaniel Sanders Leaf.declareInstr(Root, NewInstrID);
3671d94fb21SDaniel Sanders }
3681d94fb21SDaniel Sanders
3691d94fb21SDaniel Sanders addPartitionersForInstr(NewInstrID);
3701d94fb21SDaniel Sanders
3711d94fb21SDaniel Sanders std::unique_ptr<GIMatchTree> TreeRoot = std::make_unique<GIMatchTree>();
3721d94fb21SDaniel Sanders TreeNode = TreeRoot.get();
3731d94fb21SDaniel Sanders runStep();
3741d94fb21SDaniel Sanders
3751d94fb21SDaniel Sanders return TreeRoot;
3761d94fb21SDaniel Sanders }
3771d94fb21SDaniel Sanders
emitPartitionName(raw_ostream & OS,unsigned Idx) const3781d94fb21SDaniel Sanders void GIMatchTreeOpcodePartitioner::emitPartitionName(raw_ostream &OS, unsigned Idx) const {
3791d94fb21SDaniel Sanders if (PartitionToInstr[Idx] == nullptr) {
3801d94fb21SDaniel Sanders OS << "* or nullptr";
3811d94fb21SDaniel Sanders return;
3821d94fb21SDaniel Sanders }
3831d94fb21SDaniel Sanders OS << PartitionToInstr[Idx]->Namespace
3841d94fb21SDaniel Sanders << "::" << PartitionToInstr[Idx]->TheDef->getName();
3851d94fb21SDaniel Sanders }
3861d94fb21SDaniel Sanders
repartition(GIMatchTreeBuilder::LeafVec & Leaves)3871d94fb21SDaniel Sanders void GIMatchTreeOpcodePartitioner::repartition(
3881d94fb21SDaniel Sanders GIMatchTreeBuilder::LeafVec &Leaves) {
3891d94fb21SDaniel Sanders Partitions.clear();
3901d94fb21SDaniel Sanders InstrToPartition.clear();
3911d94fb21SDaniel Sanders PartitionToInstr.clear();
3921d94fb21SDaniel Sanders TestedPredicates.clear();
3931d94fb21SDaniel Sanders
3941d94fb21SDaniel Sanders for (const auto &Leaf : enumerate(Leaves)) {
3951d94fb21SDaniel Sanders bool AllOpcodes = true;
3961d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID);
3971d94fb21SDaniel Sanders BitVector TestedPredicatesForLeaf(
3981d94fb21SDaniel Sanders Leaf.value().getMatchDag().getNumPredicates());
3991d94fb21SDaniel Sanders
4001d94fb21SDaniel Sanders // If the instruction isn't declared then we don't care about it. Ignore
4011d94fb21SDaniel Sanders // it for now and add it to all partitions later once we know what
4021d94fb21SDaniel Sanders // partitions we have.
4031d94fb21SDaniel Sanders if (!InstrInfo) {
4041d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " " << Leaf.value().getName()
4051d94fb21SDaniel Sanders << " doesn't care about Instr[" << InstrID << "]\n");
4061d94fb21SDaniel Sanders assert(TestedPredicatesForLeaf.size() == Leaf.value().getMatchDag().getNumPredicates());
4071d94fb21SDaniel Sanders TestedPredicates.push_back(TestedPredicatesForLeaf);
4081d94fb21SDaniel Sanders continue;
4091d94fb21SDaniel Sanders }
4101d94fb21SDaniel Sanders
4111d94fb21SDaniel Sanders // If the opcode is available to test then any opcode predicates will have
4121d94fb21SDaniel Sanders // been enabled too.
41313922f3eSDaniel Sanders for (unsigned PIdx : Leaf.value().TestablePredicates.set_bits()) {
4141d94fb21SDaniel Sanders const auto &P = Leaf.value().getPredicate(PIdx);
4151d94fb21SDaniel Sanders SmallVector<const CodeGenInstruction *, 1> OpcodesForThisPredicate;
4161d94fb21SDaniel Sanders if (const auto *OpcodeP = dyn_cast<const GIMatchDagOpcodePredicate>(P)) {
4171d94fb21SDaniel Sanders // We've found _an_ opcode predicate, but we don't know if it's
4181d94fb21SDaniel Sanders // checking this instruction yet.
4191d94fb21SDaniel Sanders bool IsThisPredicate = false;
4201d94fb21SDaniel Sanders for (const auto &PDep : Leaf.value().getMatchDag().predicate_edges()) {
4211d94fb21SDaniel Sanders if (PDep->getRequiredMI() == InstrInfo->getInstrNode() &&
4221d94fb21SDaniel Sanders PDep->getRequiredMO() == nullptr && PDep->getPredicate() == P) {
4231d94fb21SDaniel Sanders IsThisPredicate = true;
4241d94fb21SDaniel Sanders break;
4251d94fb21SDaniel Sanders }
4261d94fb21SDaniel Sanders }
4271d94fb21SDaniel Sanders if (!IsThisPredicate)
4281d94fb21SDaniel Sanders continue;
4291d94fb21SDaniel Sanders
4301d94fb21SDaniel Sanders // If we get here twice then we've somehow ended up with two opcode
4311d94fb21SDaniel Sanders // predicates for one instruction in the same DAG. That should be
4321d94fb21SDaniel Sanders // impossible.
4331d94fb21SDaniel Sanders assert(AllOpcodes && "Conflicting opcode predicates");
4341d94fb21SDaniel Sanders const CodeGenInstruction *Expected = OpcodeP->getInstr();
4351d94fb21SDaniel Sanders OpcodesForThisPredicate.push_back(Expected);
4361d94fb21SDaniel Sanders }
4371d94fb21SDaniel Sanders
4381d94fb21SDaniel Sanders if (const auto *OpcodeP =
4391d94fb21SDaniel Sanders dyn_cast<const GIMatchDagOneOfOpcodesPredicate>(P)) {
4401d94fb21SDaniel Sanders // We've found _an_ oneof(opcodes) predicate, but we don't know if it's
4411d94fb21SDaniel Sanders // checking this instruction yet.
4421d94fb21SDaniel Sanders bool IsThisPredicate = false;
4431d94fb21SDaniel Sanders for (const auto &PDep : Leaf.value().getMatchDag().predicate_edges()) {
4441d94fb21SDaniel Sanders if (PDep->getRequiredMI() == InstrInfo->getInstrNode() &&
4451d94fb21SDaniel Sanders PDep->getRequiredMO() == nullptr && PDep->getPredicate() == P) {
4461d94fb21SDaniel Sanders IsThisPredicate = true;
4471d94fb21SDaniel Sanders break;
4481d94fb21SDaniel Sanders }
4491d94fb21SDaniel Sanders }
4501d94fb21SDaniel Sanders if (!IsThisPredicate)
4511d94fb21SDaniel Sanders continue;
4521d94fb21SDaniel Sanders
4531d94fb21SDaniel Sanders // If we get here twice then we've somehow ended up with two opcode
4541d94fb21SDaniel Sanders // predicates for one instruction in the same DAG. That should be
4551d94fb21SDaniel Sanders // impossible.
4561d94fb21SDaniel Sanders assert(AllOpcodes && "Conflicting opcode predicates");
4575d3f3d3aSKazu Hirata append_range(OpcodesForThisPredicate, OpcodeP->getInstrs());
4581d94fb21SDaniel Sanders }
4591d94fb21SDaniel Sanders
4601d94fb21SDaniel Sanders for (const CodeGenInstruction *Expected : OpcodesForThisPredicate) {
4611d94fb21SDaniel Sanders // Mark this predicate as one we're testing.
4621d94fb21SDaniel Sanders TestedPredicatesForLeaf.set(PIdx);
4631d94fb21SDaniel Sanders
4641d94fb21SDaniel Sanders // Partitions must be numbered 0, 1, .., N but instructions don't meet
4651d94fb21SDaniel Sanders // that requirement. Assign a partition number to each opcode if we
4661d94fb21SDaniel Sanders // lack one ...
4671d94fb21SDaniel Sanders auto Partition = InstrToPartition.find(Expected);
4681d94fb21SDaniel Sanders if (Partition == InstrToPartition.end()) {
4691d94fb21SDaniel Sanders BitVector Contents(Leaves.size());
4701d94fb21SDaniel Sanders Partition = InstrToPartition
4711d94fb21SDaniel Sanders .insert(std::make_pair(Expected, Partitions.size()))
4721d94fb21SDaniel Sanders .first;
4731d94fb21SDaniel Sanders PartitionToInstr.push_back(Expected);
4741d94fb21SDaniel Sanders Partitions.insert(std::make_pair(Partitions.size(), Contents));
4751d94fb21SDaniel Sanders }
4761d94fb21SDaniel Sanders // ... and mark this leaf as being in that partition.
4771d94fb21SDaniel Sanders Partitions.find(Partition->second)->second.set(Leaf.index());
4781d94fb21SDaniel Sanders AllOpcodes = false;
4791d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " " << Leaf.value().getName()
4801d94fb21SDaniel Sanders << " is in partition " << Partition->second << "\n");
4811d94fb21SDaniel Sanders }
4821d94fb21SDaniel Sanders
4831d94fb21SDaniel Sanders // TODO: This is where we would handle multiple choices of opcode
4841d94fb21SDaniel Sanders // the end result will be that this leaf ends up in multiple
4851d94fb21SDaniel Sanders // partitions similarly to AllOpcodes.
4861d94fb21SDaniel Sanders }
4871d94fb21SDaniel Sanders
4881d94fb21SDaniel Sanders // If we never check the opcode, add it to every partition.
4891d94fb21SDaniel Sanders if (AllOpcodes) {
4901d94fb21SDaniel Sanders // Add a partition for the default case if we don't already have one.
4911d94fb21SDaniel Sanders if (InstrToPartition.insert(std::make_pair(nullptr, 0)).second) {
4921d94fb21SDaniel Sanders PartitionToInstr.push_back(nullptr);
4931d94fb21SDaniel Sanders BitVector Contents(Leaves.size());
4941d94fb21SDaniel Sanders Partitions.insert(std::make_pair(Partitions.size(), Contents));
4951d94fb21SDaniel Sanders }
4961d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " " << Leaf.value().getName()
4971d94fb21SDaniel Sanders << " is in all partitions (opcode not checked)\n");
4981d94fb21SDaniel Sanders for (auto &Partition : Partitions)
4991d94fb21SDaniel Sanders Partition.second.set(Leaf.index());
5001d94fb21SDaniel Sanders }
5011d94fb21SDaniel Sanders
5021d94fb21SDaniel Sanders assert(TestedPredicatesForLeaf.size() == Leaf.value().getMatchDag().getNumPredicates());
5031d94fb21SDaniel Sanders TestedPredicates.push_back(TestedPredicatesForLeaf);
5041d94fb21SDaniel Sanders }
5051d94fb21SDaniel Sanders
5061d94fb21SDaniel Sanders if (Partitions.size() == 0) {
5071d94fb21SDaniel Sanders // Add a partition for the default case if we don't already have one.
5081d94fb21SDaniel Sanders if (InstrToPartition.insert(std::make_pair(nullptr, 0)).second) {
5091d94fb21SDaniel Sanders PartitionToInstr.push_back(nullptr);
5101d94fb21SDaniel Sanders BitVector Contents(Leaves.size());
5111d94fb21SDaniel Sanders Partitions.insert(std::make_pair(Partitions.size(), Contents));
5121d94fb21SDaniel Sanders }
5131d94fb21SDaniel Sanders }
5141d94fb21SDaniel Sanders
5151d94fb21SDaniel Sanders // Add any leaves that don't care about this instruction to all partitions.
5161d94fb21SDaniel Sanders for (const auto &Leaf : enumerate(Leaves)) {
5171d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID);
5181d94fb21SDaniel Sanders if (!InstrInfo) {
5191d94fb21SDaniel Sanders // Add a partition for the default case if we don't already have one.
5201d94fb21SDaniel Sanders if (InstrToPartition.insert(std::make_pair(nullptr, 0)).second) {
5211d94fb21SDaniel Sanders PartitionToInstr.push_back(nullptr);
5221d94fb21SDaniel Sanders BitVector Contents(Leaves.size());
5231d94fb21SDaniel Sanders Partitions.insert(std::make_pair(Partitions.size(), Contents));
5241d94fb21SDaniel Sanders }
5251d94fb21SDaniel Sanders for (auto &Partition : Partitions)
5261d94fb21SDaniel Sanders Partition.second.set(Leaf.index());
5271d94fb21SDaniel Sanders }
5281d94fb21SDaniel Sanders }
5291d94fb21SDaniel Sanders
5301d94fb21SDaniel Sanders }
5311d94fb21SDaniel Sanders
applyForPartition(unsigned PartitionIdx,GIMatchTreeBuilder & Builder,GIMatchTreeBuilder & SubBuilder)5321d94fb21SDaniel Sanders void GIMatchTreeOpcodePartitioner::applyForPartition(
5331d94fb21SDaniel Sanders unsigned PartitionIdx, GIMatchTreeBuilder &Builder, GIMatchTreeBuilder &SubBuilder) {
5341d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " Making partition " << PartitionIdx << "\n");
5351d94fb21SDaniel Sanders const CodeGenInstruction *CGI = PartitionToInstr[PartitionIdx];
5361d94fb21SDaniel Sanders
5371d94fb21SDaniel Sanders BitVector PossibleLeaves = getPossibleLeavesForPartition(PartitionIdx);
5381d94fb21SDaniel Sanders // Consume any predicates we handled.
5391d94fb21SDaniel Sanders for (auto &EnumeratedLeaf : enumerate(Builder.getPossibleLeaves())) {
5401d94fb21SDaniel Sanders if (!PossibleLeaves[EnumeratedLeaf.index()])
5411d94fb21SDaniel Sanders continue;
5421d94fb21SDaniel Sanders
5431d94fb21SDaniel Sanders auto &Leaf = EnumeratedLeaf.value();
5441d94fb21SDaniel Sanders const auto &TestedPredicatesForLeaf =
5451d94fb21SDaniel Sanders TestedPredicates[EnumeratedLeaf.index()];
5461d94fb21SDaniel Sanders
5471d94fb21SDaniel Sanders for (unsigned PredIdx : TestedPredicatesForLeaf.set_bits()) {
5481d94fb21SDaniel Sanders LLVM_DEBUG(dbgs() << " " << Leaf.getName() << " tested predicate #"
5491d94fb21SDaniel Sanders << PredIdx << " of " << TestedPredicatesForLeaf.size()
5501d94fb21SDaniel Sanders << " " << *Leaf.getPredicate(PredIdx) << "\n");
5511d94fb21SDaniel Sanders Leaf.RemainingPredicates.reset(PredIdx);
5521d94fb21SDaniel Sanders Leaf.TestablePredicates.reset(PredIdx);
5531d94fb21SDaniel Sanders }
5541d94fb21SDaniel Sanders SubBuilder.addLeaf(Leaf);
5551d94fb21SDaniel Sanders }
5561d94fb21SDaniel Sanders
5571d94fb21SDaniel Sanders // Nothing to do, we don't know anything about this instruction as a result
5581d94fb21SDaniel Sanders // of this partitioner.
5591d94fb21SDaniel Sanders if (CGI == nullptr)
5601d94fb21SDaniel Sanders return;
5611d94fb21SDaniel Sanders
5621d94fb21SDaniel Sanders GIMatchTreeBuilder::LeafVec &NewLeaves = SubBuilder.getPossibleLeaves();
5631d94fb21SDaniel Sanders // Find all the operands we know to exist and are referenced. This will
5641d94fb21SDaniel Sanders // usually be all the referenced operands but there are some cases where
5651d94fb21SDaniel Sanders // instructions are variadic. Such operands must be handled by partitioners
5661d94fb21SDaniel Sanders // that check the number of operands.
5671d94fb21SDaniel Sanders BitVector ReferencedOperands(1);
5681d94fb21SDaniel Sanders for (auto &Leaf : NewLeaves) {
5691d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.getInstrInfo(InstrID);
5701d94fb21SDaniel Sanders // Skip any leaves that don't care about this instruction.
5711d94fb21SDaniel Sanders if (!InstrInfo)
5721d94fb21SDaniel Sanders continue;
5731d94fb21SDaniel Sanders const GIMatchDagInstr *Instr = InstrInfo->getInstrNode();
5741d94fb21SDaniel Sanders for (auto &E : enumerate(Leaf.getMatchDag().edges())) {
5751d94fb21SDaniel Sanders if (E.value()->getFromMI() == Instr &&
5761d94fb21SDaniel Sanders E.value()->getFromMO()->getIdx() < CGI->Operands.size()) {
5771d94fb21SDaniel Sanders ReferencedOperands.resize(E.value()->getFromMO()->getIdx() + 1);
5781d94fb21SDaniel Sanders ReferencedOperands.set(E.value()->getFromMO()->getIdx());
5791d94fb21SDaniel Sanders }
5801d94fb21SDaniel Sanders }
5811d94fb21SDaniel Sanders }
5821d94fb21SDaniel Sanders for (auto &Leaf : NewLeaves) {
5831d94fb21SDaniel Sanders for (unsigned OpIdx : ReferencedOperands.set_bits()) {
5841d94fb21SDaniel Sanders Leaf.declareOperand(InstrID, OpIdx);
5851d94fb21SDaniel Sanders }
5861d94fb21SDaniel Sanders }
5871d94fb21SDaniel Sanders for (unsigned OpIdx : ReferencedOperands.set_bits()) {
5881d94fb21SDaniel Sanders SubBuilder.addPartitionersForOperand(InstrID, OpIdx);
5891d94fb21SDaniel Sanders }
5901d94fb21SDaniel Sanders }
5911d94fb21SDaniel Sanders
emitPartitionResults(raw_ostream & OS) const5921d94fb21SDaniel Sanders void GIMatchTreeOpcodePartitioner::emitPartitionResults(
5931d94fb21SDaniel Sanders raw_ostream &OS) const {
5941d94fb21SDaniel Sanders OS << "Partitioning by opcode would produce " << Partitions.size()
5951d94fb21SDaniel Sanders << " partitions\n";
5961d94fb21SDaniel Sanders for (const auto &Partition : InstrToPartition) {
5971d94fb21SDaniel Sanders if (Partition.first == nullptr)
5981d94fb21SDaniel Sanders OS << "Default: ";
5991d94fb21SDaniel Sanders else
6001d94fb21SDaniel Sanders OS << Partition.first->TheDef->getName() << ": ";
6011d94fb21SDaniel Sanders StringRef Separator = "";
6021d94fb21SDaniel Sanders for (unsigned I : Partitions.find(Partition.second)->second.set_bits()) {
6031d94fb21SDaniel Sanders OS << Separator << I;
6041d94fb21SDaniel Sanders Separator = ", ";
6051d94fb21SDaniel Sanders }
6061d94fb21SDaniel Sanders OS << "\n";
6071d94fb21SDaniel Sanders }
6081d94fb21SDaniel Sanders }
6091d94fb21SDaniel Sanders
generatePartitionSelectorCode(raw_ostream & OS,StringRef Indent) const6101d94fb21SDaniel Sanders void GIMatchTreeOpcodePartitioner::generatePartitionSelectorCode(
6111d94fb21SDaniel Sanders raw_ostream &OS, StringRef Indent) const {
6129244be7bSdstuttar // Make sure not to emit empty switch or switch with just default
6139244be7bSdstuttar if (PartitionToInstr.size() == 1 && PartitionToInstr[0] == nullptr) {
6149244be7bSdstuttar OS << Indent << "Partition = 0;\n";
6159244be7bSdstuttar } else if (PartitionToInstr.size()) {
6161d94fb21SDaniel Sanders OS << Indent << "Partition = -1;\n"
6171d94fb21SDaniel Sanders << Indent << "switch (MIs[" << InstrID << "]->getOpcode()) {\n";
6181d94fb21SDaniel Sanders for (const auto &EnumInstr : enumerate(PartitionToInstr)) {
6191d94fb21SDaniel Sanders if (EnumInstr.value() == nullptr)
6201d94fb21SDaniel Sanders OS << Indent << "default:";
6211d94fb21SDaniel Sanders else
6221d94fb21SDaniel Sanders OS << Indent << "case " << EnumInstr.value()->Namespace
6231d94fb21SDaniel Sanders << "::" << EnumInstr.value()->TheDef->getName() << ":";
6241d94fb21SDaniel Sanders OS << " Partition = " << EnumInstr.index() << "; break;\n";
6251d94fb21SDaniel Sanders }
6269244be7bSdstuttar OS << Indent << "}\n";
6279244be7bSdstuttar }
6289244be7bSdstuttar OS << Indent
6291d94fb21SDaniel Sanders << "// Default case but without conflicting with potential default case "
6301d94fb21SDaniel Sanders "in selection.\n"
6311d94fb21SDaniel Sanders << Indent << "if (Partition == -1) return false;\n";
6321d94fb21SDaniel Sanders }
6331d94fb21SDaniel Sanders
addToPartition(bool Result,unsigned LeafIdx)6341d94fb21SDaniel Sanders void GIMatchTreeVRegDefPartitioner::addToPartition(bool Result,
6351d94fb21SDaniel Sanders unsigned LeafIdx) {
6361d94fb21SDaniel Sanders auto I = ResultToPartition.find(Result);
6371d94fb21SDaniel Sanders if (I == ResultToPartition.end()) {
6381d94fb21SDaniel Sanders ResultToPartition.insert(std::make_pair(Result, PartitionToResult.size()));
6391d94fb21SDaniel Sanders PartitionToResult.push_back(Result);
6401d94fb21SDaniel Sanders }
6411d94fb21SDaniel Sanders I = ResultToPartition.find(Result);
6421d94fb21SDaniel Sanders auto P = Partitions.find(I->second);
6431d94fb21SDaniel Sanders if (P == Partitions.end())
6441d94fb21SDaniel Sanders P = Partitions.insert(std::make_pair(I->second, BitVector())).first;
6451d94fb21SDaniel Sanders P->second.resize(LeafIdx + 1);
6461d94fb21SDaniel Sanders P->second.set(LeafIdx);
647c5877ec9SBill Wendling }
6481d94fb21SDaniel Sanders
repartition(GIMatchTreeBuilder::LeafVec & Leaves)6491d94fb21SDaniel Sanders void GIMatchTreeVRegDefPartitioner::repartition(
6501d94fb21SDaniel Sanders GIMatchTreeBuilder::LeafVec &Leaves) {
6511d94fb21SDaniel Sanders Partitions.clear();
6521d94fb21SDaniel Sanders
6531d94fb21SDaniel Sanders for (const auto &Leaf : enumerate(Leaves)) {
6541d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID);
6551d94fb21SDaniel Sanders BitVector TraversedEdgesForLeaf(Leaf.value().getMatchDag().getNumEdges());
6561d94fb21SDaniel Sanders
6571d94fb21SDaniel Sanders // If the instruction isn't declared then we don't care about it. Ignore
6581d94fb21SDaniel Sanders // it for now and add it to all partitions later once we know what
6591d94fb21SDaniel Sanders // partitions we have.
6601d94fb21SDaniel Sanders if (!InstrInfo) {
6611d94fb21SDaniel Sanders TraversedEdges.push_back(TraversedEdgesForLeaf);
6621d94fb21SDaniel Sanders continue;
6631d94fb21SDaniel Sanders }
6641d94fb21SDaniel Sanders
6651d94fb21SDaniel Sanders // If this node has an use -> def edge from this operand then this
6661d94fb21SDaniel Sanders // instruction must be in partition 1 (isVRegDef()).
6671d94fb21SDaniel Sanders bool WantsEdge = false;
66813922f3eSDaniel Sanders for (unsigned EIdx : Leaf.value().TraversableEdges.set_bits()) {
6691d94fb21SDaniel Sanders const auto &E = Leaf.value().getEdge(EIdx);
6701d94fb21SDaniel Sanders if (E->getFromMI() != InstrInfo->getInstrNode() ||
6711d94fb21SDaniel Sanders E->getFromMO()->getIdx() != OpIdx || E->isDefToUse())
6721d94fb21SDaniel Sanders continue;
6731d94fb21SDaniel Sanders
6741d94fb21SDaniel Sanders // We're looking at the right edge. This leaf wants a vreg def so we'll
6751d94fb21SDaniel Sanders // put it in partition 1.
6761d94fb21SDaniel Sanders addToPartition(true, Leaf.index());
6771d94fb21SDaniel Sanders TraversedEdgesForLeaf.set(EIdx);
6781d94fb21SDaniel Sanders WantsEdge = true;
6791d94fb21SDaniel Sanders }
6801d94fb21SDaniel Sanders
6811d94fb21SDaniel Sanders bool isNotReg = false;
6821d94fb21SDaniel Sanders if (!WantsEdge && isNotReg) {
6831d94fb21SDaniel Sanders // If this leaf doesn't have an edge and we _don't_ want a register,
6841d94fb21SDaniel Sanders // then add it to partition 0.
6851d94fb21SDaniel Sanders addToPartition(false, Leaf.index());
6861d94fb21SDaniel Sanders } else if (!WantsEdge) {
6871d94fb21SDaniel Sanders // If this leaf doesn't have an edge and we don't know what we want,
6881d94fb21SDaniel Sanders // then add it to partition 0 and 1.
6891d94fb21SDaniel Sanders addToPartition(false, Leaf.index());
6901d94fb21SDaniel Sanders addToPartition(true, Leaf.index());
6911d94fb21SDaniel Sanders }
6921d94fb21SDaniel Sanders
6931d94fb21SDaniel Sanders TraversedEdges.push_back(TraversedEdgesForLeaf);
6941d94fb21SDaniel Sanders }
6951d94fb21SDaniel Sanders
6961d94fb21SDaniel Sanders // Add any leaves that don't care about this instruction to all partitions.
6971d94fb21SDaniel Sanders for (const auto &Leaf : enumerate(Leaves)) {
6981d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.value().getInstrInfo(InstrID);
6991d94fb21SDaniel Sanders if (!InstrInfo)
7001d94fb21SDaniel Sanders for (auto &Partition : Partitions)
7011d94fb21SDaniel Sanders Partition.second.set(Leaf.index());
7021d94fb21SDaniel Sanders }
7031d94fb21SDaniel Sanders }
7041d94fb21SDaniel Sanders
applyForPartition(unsigned PartitionIdx,GIMatchTreeBuilder & Builder,GIMatchTreeBuilder & SubBuilder)7051d94fb21SDaniel Sanders void GIMatchTreeVRegDefPartitioner::applyForPartition(
7061d94fb21SDaniel Sanders unsigned PartitionIdx, GIMatchTreeBuilder &Builder,
7071d94fb21SDaniel Sanders GIMatchTreeBuilder &SubBuilder) {
7081d94fb21SDaniel Sanders BitVector PossibleLeaves = getPossibleLeavesForPartition(PartitionIdx);
7091d94fb21SDaniel Sanders
7101d94fb21SDaniel Sanders std::vector<BitVector> TraversedEdgesByNewLeaves;
7111d94fb21SDaniel Sanders // Consume any edges we handled.
7121d94fb21SDaniel Sanders for (auto &EnumeratedLeaf : enumerate(Builder.getPossibleLeaves())) {
7131d94fb21SDaniel Sanders if (!PossibleLeaves[EnumeratedLeaf.index()])
7141d94fb21SDaniel Sanders continue;
7151d94fb21SDaniel Sanders
7161d94fb21SDaniel Sanders auto &Leaf = EnumeratedLeaf.value();
7171d94fb21SDaniel Sanders const auto &TraversedEdgesForLeaf = TraversedEdges[EnumeratedLeaf.index()];
7181d94fb21SDaniel Sanders TraversedEdgesByNewLeaves.push_back(TraversedEdgesForLeaf);
7191d94fb21SDaniel Sanders Leaf.RemainingEdges.reset(TraversedEdgesForLeaf);
7201d94fb21SDaniel Sanders Leaf.TraversableEdges.reset(TraversedEdgesForLeaf);
7211d94fb21SDaniel Sanders SubBuilder.addLeaf(Leaf);
7221d94fb21SDaniel Sanders }
7231d94fb21SDaniel Sanders
7241d94fb21SDaniel Sanders // Nothing to do. The only thing we know is that it isn't a vreg-def.
7251d94fb21SDaniel Sanders if (PartitionToResult[PartitionIdx] == false)
7261d94fb21SDaniel Sanders return;
7271d94fb21SDaniel Sanders
7281d94fb21SDaniel Sanders NewInstrID = SubBuilder.allocInstrID();
7291d94fb21SDaniel Sanders
7301d94fb21SDaniel Sanders GIMatchTreeBuilder::LeafVec &NewLeaves = SubBuilder.getPossibleLeaves();
73113922f3eSDaniel Sanders for (const auto I : zip(NewLeaves, TraversedEdgesByNewLeaves)) {
7321d94fb21SDaniel Sanders auto &Leaf = std::get<0>(I);
7331d94fb21SDaniel Sanders auto &TraversedEdgesForLeaf = std::get<1>(I);
7341d94fb21SDaniel Sanders GIMatchTreeInstrInfo *InstrInfo = Leaf.getInstrInfo(InstrID);
7351d94fb21SDaniel Sanders // Skip any leaves that don't care about this instruction.
7361d94fb21SDaniel Sanders if (!InstrInfo)
7371d94fb21SDaniel Sanders continue;
73813922f3eSDaniel Sanders for (unsigned EIdx : TraversedEdgesForLeaf.set_bits()) {
7391d94fb21SDaniel Sanders const GIMatchDagEdge *E = Leaf.getEdge(EIdx);
7401d94fb21SDaniel Sanders Leaf.declareInstr(E->getToMI(), NewInstrID);
7411d94fb21SDaniel Sanders }
7421d94fb21SDaniel Sanders }
7431d94fb21SDaniel Sanders SubBuilder.addPartitionersForInstr(NewInstrID);
7441d94fb21SDaniel Sanders }
7451d94fb21SDaniel Sanders
emitPartitionResults(raw_ostream & OS) const7461d94fb21SDaniel Sanders void GIMatchTreeVRegDefPartitioner::emitPartitionResults(
7471d94fb21SDaniel Sanders raw_ostream &OS) const {
7481d94fb21SDaniel Sanders OS << "Partitioning by vreg-def would produce " << Partitions.size()
7491d94fb21SDaniel Sanders << " partitions\n";
7501d94fb21SDaniel Sanders for (const auto &Partition : Partitions) {
7511d94fb21SDaniel Sanders OS << Partition.first << " (";
7521d94fb21SDaniel Sanders emitPartitionName(OS, Partition.first);
7531d94fb21SDaniel Sanders OS << "): ";
7541d94fb21SDaniel Sanders StringRef Separator = "";
7551d94fb21SDaniel Sanders for (unsigned I : Partition.second.set_bits()) {
7561d94fb21SDaniel Sanders OS << Separator << I;
7571d94fb21SDaniel Sanders Separator = ", ";
7581d94fb21SDaniel Sanders }
7591d94fb21SDaniel Sanders OS << "\n";
7601d94fb21SDaniel Sanders }
7611d94fb21SDaniel Sanders }
7621d94fb21SDaniel Sanders
generatePartitionSelectorCode(raw_ostream & OS,StringRef Indent) const7631d94fb21SDaniel Sanders void GIMatchTreeVRegDefPartitioner::generatePartitionSelectorCode(
7641d94fb21SDaniel Sanders raw_ostream &OS, StringRef Indent) const {
7651d94fb21SDaniel Sanders OS << Indent << "Partition = -1\n"
7661d94fb21SDaniel Sanders << Indent << "if (MIs.size() <= NewInstrID) MIs.resize(NewInstrID + 1);\n"
7671d94fb21SDaniel Sanders << Indent << "MIs[" << NewInstrID << "] = nullptr;\n"
7681d94fb21SDaniel Sanders << Indent << "if (MIs[" << InstrID << "].getOperand(" << OpIdx
7691d94fb21SDaniel Sanders << ").isReg()))\n"
7701d94fb21SDaniel Sanders << Indent << " MIs[" << NewInstrID << "] = MRI.getVRegDef(MIs[" << InstrID
7711d94fb21SDaniel Sanders << "].getOperand(" << OpIdx << ").getReg()));\n";
7721d94fb21SDaniel Sanders
7731d94fb21SDaniel Sanders for (const auto &Pair : ResultToPartition)
7741d94fb21SDaniel Sanders OS << Indent << "if (MIs[" << NewInstrID << "] "
7751d94fb21SDaniel Sanders << (Pair.first ? "==" : "!=")
7761d94fb21SDaniel Sanders << " nullptr) Partition = " << Pair.second << ";\n";
7771d94fb21SDaniel Sanders
7781d94fb21SDaniel Sanders OS << Indent << "if (Partition == -1) return false;\n";
7791d94fb21SDaniel Sanders }
780