123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626 |
- //===- GIMatchTree.h - A decision tree to match GIMatchDag's --------------===//
- //
- // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
- // See https://llvm.org/LICENSE.txt for license information.
- // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
- //
- //===----------------------------------------------------------------------===//
- #ifndef LLVM_UTILS_TABLEGEN_GIMATCHTREE_H
- #define LLVM_UTILS_TABLEGEN_GIMATCHTREE_H
- #include "GIMatchDag.h"
- #include "llvm/ADT/BitVector.h"
- namespace llvm {
- class raw_ostream;
- class GIMatchTreeBuilder;
- class GIMatchTreePartitioner;
- /// Describes the binding of a variable to the matched MIR
- class GIMatchTreeVariableBinding {
- /// The name of the variable described by this binding.
- StringRef Name;
- // The matched instruction it is bound to.
- unsigned InstrID;
- // The matched operand (if appropriate) it is bound to.
- Optional<unsigned> OpIdx;
- public:
- GIMatchTreeVariableBinding(StringRef Name, unsigned InstrID,
- Optional<unsigned> OpIdx = None)
- : Name(Name), InstrID(InstrID), OpIdx(OpIdx) {}
- bool isInstr() const { return !OpIdx.hasValue(); }
- StringRef getName() const { return Name; }
- unsigned getInstrID() const { return InstrID; }
- unsigned getOpIdx() const {
- assert(OpIdx.hasValue() && "Is not an operand binding");
- return *OpIdx;
- }
- };
- /// Associates a matchable with a leaf of the decision tree.
- class GIMatchTreeLeafInfo {
- public:
- using const_var_binding_iterator =
- std::vector<GIMatchTreeVariableBinding>::const_iterator;
- using UntestedPredicatesTy = SmallVector<const GIMatchDagPredicate *, 1>;
- using const_untested_predicates_iterator = UntestedPredicatesTy::const_iterator;
- protected:
- /// A name for the matchable. This is primarily for debugging.
- StringRef Name;
- /// Where rules have multiple roots, this is which root we're starting from.
- unsigned RootIdx;
- /// Opaque data the caller of the tree building code understands.
- void *Data;
- /// Has the decision tree covered every edge traversal? If it hasn't then this
- /// is an unrecoverable error indicating there's something wrong with the
- /// partitioners.
- bool IsFullyTraversed;
- /// Has the decision tree covered every predicate test? If it has, then
- /// subsequent matchables on the same leaf are unreachable. If it hasn't, the
- /// code that requested the GIMatchTree is responsible for finishing off any
- /// remaining predicates.
- bool IsFullyTested;
- /// The variable bindings associated with this leaf so far.
- std::vector<GIMatchTreeVariableBinding> VarBindings;
- /// Any predicates left untested by the time we reach this leaf.
- UntestedPredicatesTy UntestedPredicates;
- public:
- GIMatchTreeLeafInfo() { llvm_unreachable("Cannot default-construct"); }
- GIMatchTreeLeafInfo(StringRef Name, unsigned RootIdx, void *Data)
- : Name(Name), RootIdx(RootIdx), Data(Data), IsFullyTraversed(false),
- IsFullyTested(false) {}
- StringRef getName() const { return Name; }
- unsigned getRootIdx() const { return RootIdx; }
- template <class Ty> Ty *getTargetData() const {
- return static_cast<Ty *>(Data);
- }
- bool isFullyTraversed() const { return IsFullyTraversed; }
- void setIsFullyTraversed(bool V) { IsFullyTraversed = V; }
- bool isFullyTested() const { return IsFullyTested; }
- void setIsFullyTested(bool V) { IsFullyTested = V; }
- void bindInstrVariable(StringRef Name, unsigned InstrID) {
- VarBindings.emplace_back(Name, InstrID);
- }
- void bindOperandVariable(StringRef Name, unsigned InstrID, unsigned OpIdx) {
- VarBindings.emplace_back(Name, InstrID, OpIdx);
- }
- const_var_binding_iterator var_bindings_begin() const {
- return VarBindings.begin();
- }
- const_var_binding_iterator var_bindings_end() const {
- return VarBindings.end();
- }
- iterator_range<const_var_binding_iterator> var_bindings() const {
- return make_range(VarBindings.begin(), VarBindings.end());
- }
- iterator_range<const_untested_predicates_iterator> untested_predicates() const {
- return make_range(UntestedPredicates.begin(), UntestedPredicates.end());
- }
- void addUntestedPredicate(const GIMatchDagPredicate *P) {
- UntestedPredicates.push_back(P);
- }
- };
- /// The nodes of a decision tree used to perform the match.
- /// This will be used to generate the C++ code or state machine equivalent.
- ///
- /// It should be noted that some nodes of this tree (most notably nodes handling
- /// def -> use edges) will need to iterate over several possible matches. As
- /// such, code generated from this will sometimes need to support backtracking.
- class GIMatchTree {
- using LeafVector = std::vector<GIMatchTreeLeafInfo>;
- /// The partitioner that has been chosen for this node. This may be nullptr if
- /// a partitioner hasn't been chosen yet or if the node is a leaf.
- std::unique_ptr<GIMatchTreePartitioner> Partitioner;
- /// All the leaves that are possible for this node of the tree.
- /// Note: This should be emptied after the tree is built when there are
- /// children but this currently isn't done to aid debuggability of the DOT
- /// graph for the decision tree.
- LeafVector PossibleLeaves;
- /// The children of this node. The index into this array must match the index
- /// chosen by the partitioner.
- std::vector<GIMatchTree> Children;
- void writeDOTGraphNode(raw_ostream &OS) const;
- void writeDOTGraphEdges(raw_ostream &OS) const;
- public:
- void writeDOTGraph(raw_ostream &OS) const;
- void setNumChildren(unsigned Num) { Children.resize(Num); }
- void addPossibleLeaf(const GIMatchTreeLeafInfo &V, bool IsFullyTraversed,
- bool IsFullyTested) {
- PossibleLeaves.push_back(V);
- PossibleLeaves.back().setIsFullyTraversed(IsFullyTraversed);
- PossibleLeaves.back().setIsFullyTested(IsFullyTested);
- }
- void dropLeavesAfter(size_t Length) {
- if (PossibleLeaves.size() > Length)
- PossibleLeaves.resize(Length);
- }
- void setPartitioner(std::unique_ptr<GIMatchTreePartitioner> &&V) {
- Partitioner = std::move(V);
- }
- GIMatchTreePartitioner *getPartitioner() const { return Partitioner.get(); }
- std::vector<GIMatchTree>::iterator children_begin() {
- return Children.begin();
- }
- std::vector<GIMatchTree>::iterator children_end() { return Children.end(); }
- iterator_range<std::vector<GIMatchTree>::iterator> children() {
- return make_range(children_begin(), children_end());
- }
- std::vector<GIMatchTree>::const_iterator children_begin() const {
- return Children.begin();
- }
- std::vector<GIMatchTree>::const_iterator children_end() const {
- return Children.end();
- }
- iterator_range<std::vector<GIMatchTree>::const_iterator> children() const {
- return make_range(children_begin(), children_end());
- }
- LeafVector::const_iterator possible_leaves_begin() const {
- return PossibleLeaves.begin();
- }
- LeafVector::const_iterator possible_leaves_end() const {
- return PossibleLeaves.end();
- }
- iterator_range<LeafVector::const_iterator>
- possible_leaves() const {
- return make_range(possible_leaves_begin(), possible_leaves_end());
- }
- LeafVector::iterator possible_leaves_begin() {
- return PossibleLeaves.begin();
- }
- LeafVector::iterator possible_leaves_end() {
- return PossibleLeaves.end();
- }
- iterator_range<LeafVector::iterator> possible_leaves() {
- return make_range(possible_leaves_begin(), possible_leaves_end());
- }
- };
- /// Record information that is known about the instruction bound to this ID and
- /// GIMatchDagInstrNode. Every rule gets its own set of
- /// GIMatchTreeInstrInfo to bind the shared IDs to an instr node in its
- /// DAG.
- ///
- /// For example, if we know that there are 3 operands. We can record it here to
- /// elide duplicate checks.
- class GIMatchTreeInstrInfo {
- /// The instruction ID for the matched instruction.
- unsigned ID;
- /// The corresponding instruction node in the MatchDAG.
- const GIMatchDagInstr *InstrNode;
- public:
- GIMatchTreeInstrInfo(unsigned ID, const GIMatchDagInstr *InstrNode)
- : ID(ID), InstrNode(InstrNode) {}
- unsigned getID() const { return ID; }
- const GIMatchDagInstr *getInstrNode() const { return InstrNode; }
- };
- /// Record information that is known about the operand bound to this ID, OpIdx,
- /// and GIMatchDagInstrNode. Every rule gets its own set of
- /// GIMatchTreeOperandInfo to bind the shared IDs to an operand of an
- /// instr node from its DAG.
- ///
- /// For example, if we know that there the operand is a register. We can record
- /// it here to elide duplicate checks.
- class GIMatchTreeOperandInfo {
- /// The corresponding instruction node in the MatchDAG that the operand
- /// belongs to.
- const GIMatchDagInstr *InstrNode;
- unsigned OpIdx;
- public:
- GIMatchTreeOperandInfo(const GIMatchDagInstr *InstrNode, unsigned OpIdx)
- : InstrNode(InstrNode), OpIdx(OpIdx) {}
- const GIMatchDagInstr *getInstrNode() const { return InstrNode; }
- unsigned getOpIdx() const { return OpIdx; }
- };
- /// Represent a leaf of the match tree and any working data we need to build the
- /// tree.
- ///
- /// It's important to note that each rule can have multiple
- /// GIMatchTreeBuilderLeafInfo's since the partitioners do not always partition
- /// into mutually-exclusive partitions. For example:
- /// R1: (FOO ..., ...)
- /// R2: (oneof(FOO, BAR) ..., ...)
- /// will partition by opcode into two partitions FOO=>[R1, R2], and BAR=>[R2]
- ///
- /// As an optimization, all instructions, edges, and predicates in the DAGs are
- /// numbered and tracked in BitVectors. As such, the GIMatchDAG must not be
- /// modified once construction of the tree has begun.
- class GIMatchTreeBuilderLeafInfo {
- protected:
- GIMatchTreeBuilder &Builder;
- GIMatchTreeLeafInfo Info;
- const GIMatchDag &MatchDag;
- /// The association between GIMatchDagInstr* and GIMatchTreeInstrInfo.
- /// The primary reason for this members existence is to allow the use of
- /// InstrIDToInfo.lookup() since that requires that the value is
- /// default-constructible.
- DenseMap<const GIMatchDagInstr *, GIMatchTreeInstrInfo> InstrNodeToInfo;
- /// The instruction information for a given ID in the context of this
- /// particular leaf.
- DenseMap<unsigned, GIMatchTreeInstrInfo *> InstrIDToInfo;
- /// The operand information for a given ID and OpIdx in the context of this
- /// particular leaf.
- DenseMap<std::pair<unsigned, unsigned>, GIMatchTreeOperandInfo>
- OperandIDToInfo;
- public:
- /// The remaining instrs/edges/predicates to visit
- BitVector RemainingInstrNodes;
- BitVector RemainingEdges;
- BitVector RemainingPredicates;
- // The remaining predicate dependencies for each predicate
- std::vector<BitVector> UnsatisfiedPredDepsForPred;
- /// The edges/predicates we can visit as a result of the declare*() calls we
- /// have already made. We don't need an instrs version since edges imply the
- /// instr.
- BitVector TraversableEdges;
- BitVector TestablePredicates;
- /// Map predicates from the DAG to their position in the DAG predicate
- /// iterators.
- DenseMap<GIMatchDagPredicate *, unsigned> PredicateIDs;
- /// Map predicate dependency edges from the DAG to their position in the DAG
- /// predicate dependency iterators.
- DenseMap<GIMatchDagPredicateDependencyEdge *, unsigned> PredicateDepIDs;
- public:
- GIMatchTreeBuilderLeafInfo(GIMatchTreeBuilder &Builder, StringRef Name,
- unsigned RootIdx, const GIMatchDag &MatchDag,
- void *Data);
- StringRef getName() const { return Info.getName(); }
- GIMatchTreeLeafInfo &getInfo() { return Info; }
- const GIMatchTreeLeafInfo &getInfo() const { return Info; }
- const GIMatchDag &getMatchDag() const { return MatchDag; }
- unsigned getRootIdx() const { return Info.getRootIdx(); }
- /// Has this DAG been fully traversed. This must be true by the time the tree
- /// builder finishes.
- bool isFullyTraversed() const {
- // We don't need UnsatisfiedPredDepsForPred because RemainingPredicates
- // can't be all-zero without satisfying all the dependencies. The same is
- // almost true for Edges and Instrs but it's possible to have Instrs without
- // Edges.
- return RemainingInstrNodes.none() && RemainingEdges.none();
- }
- /// Has this DAG been fully tested. This hould be true by the time the tree
- /// builder finishes but clients can finish any untested predicates left over
- /// if it's not true.
- bool isFullyTested() const {
- // We don't need UnsatisfiedPredDepsForPred because RemainingPredicates
- // can't be all-zero without satisfying all the dependencies. The same is
- // almost true for Edges and Instrs but it's possible to have Instrs without
- // Edges.
- return RemainingInstrNodes.none() && RemainingEdges.none() &&
- RemainingPredicates.none();
- }
- const GIMatchDagInstr *getInstr(unsigned Idx) const {
- return *(MatchDag.instr_nodes_begin() + Idx);
- }
- const GIMatchDagEdge *getEdge(unsigned Idx) const {
- return *(MatchDag.edges_begin() + Idx);
- }
- GIMatchDagEdge *getEdge(unsigned Idx) {
- return *(MatchDag.edges_begin() + Idx);
- }
- const GIMatchDagPredicate *getPredicate(unsigned Idx) const {
- return *(MatchDag.predicates_begin() + Idx);
- }
- iterator_range<llvm::BitVector::const_set_bits_iterator>
- untested_instrs() const {
- return RemainingInstrNodes.set_bits();
- }
- iterator_range<llvm::BitVector::const_set_bits_iterator>
- untested_edges() const {
- return RemainingEdges.set_bits();
- }
- iterator_range<llvm::BitVector::const_set_bits_iterator>
- untested_predicates() const {
- return RemainingPredicates.set_bits();
- }
- /// Bind an instr node to the given ID and clear any blocking dependencies
- /// that were waiting for it.
- void declareInstr(const GIMatchDagInstr *Instr, unsigned ID);
- /// Bind an operand to the given ID and OpIdx and clear any blocking
- /// dependencies that were waiting for it.
- void declareOperand(unsigned InstrID, unsigned OpIdx);
- GIMatchTreeInstrInfo *getInstrInfo(unsigned ID) const {
- return InstrIDToInfo.lookup(ID);
- }
- void dump(raw_ostream &OS) const {
- OS << "Leaf " << getName() << " for root #" << getRootIdx() << "\n";
- MatchDag.print(OS);
- for (const auto &I : InstrIDToInfo)
- OS << "Declared Instr #" << I.first << "\n";
- for (const auto &I : OperandIDToInfo)
- OS << "Declared Instr #" << I.first.first << ", Op #" << I.first.second
- << "\n";
- OS << RemainingInstrNodes.count() << " untested instrs of "
- << RemainingInstrNodes.size() << "\n";
- OS << RemainingEdges.count() << " untested edges of "
- << RemainingEdges.size() << "\n";
- OS << RemainingPredicates.count() << " untested predicates of "
- << RemainingPredicates.size() << "\n";
- OS << TraversableEdges.count() << " edges could be traversed\n";
- OS << TestablePredicates.count() << " predicates could be tested\n";
- }
- };
- /// The tree builder has a fairly tough job. It's purpose is to merge all the
- /// DAGs from the ruleset into a decision tree that walks all of them
- /// simultaneously and identifies the rule that was matched. In addition to
- /// that, it also needs to find the most efficient order to make decisions
- /// without violating any dependencies and ensure that every DAG covers every
- /// instr/edge/predicate.
- class GIMatchTreeBuilder {
- public:
- using LeafVec = std::vector<GIMatchTreeBuilderLeafInfo>;
- protected:
- /// The leaves that the resulting decision tree will distinguish.
- LeafVec Leaves;
- /// The tree node being constructed.
- GIMatchTree *TreeNode;
- /// The builders for each subtree resulting from the current decision.
- std::vector<GIMatchTreeBuilder> SubtreeBuilders;
- /// The possible partitioners we could apply right now.
- std::vector<std::unique_ptr<GIMatchTreePartitioner>> Partitioners;
- /// The next instruction ID to allocate when requested by the chosen
- /// Partitioner.
- unsigned NextInstrID;
- /// Use any context we have stored to cull partitioners that only test things
- /// we already know. At the time of writing, there's no need to do anything
- /// here but it will become important once, for example, there is a
- /// num-operands and an opcode partitioner. This is because applying an opcode
- /// partitioner (usually) makes the number of operands known which makes
- /// additional checking pointless.
- void filterRedundantPartitioners();
- /// Evaluate the available partioners and select the best one at the moment.
- void evaluatePartitioners();
- /// Construct the current tree node.
- void runStep();
- public:
- GIMatchTreeBuilder(unsigned NextInstrID) : NextInstrID(NextInstrID) {}
- GIMatchTreeBuilder(GIMatchTree *TreeNode, unsigned NextInstrID)
- : TreeNode(TreeNode), NextInstrID(NextInstrID) {}
- void addLeaf(StringRef Name, unsigned RootIdx, const GIMatchDag &MatchDag,
- void *Data) {
- Leaves.emplace_back(*this, Name, RootIdx, MatchDag, Data);
- }
- void addLeaf(const GIMatchTreeBuilderLeafInfo &L) { Leaves.push_back(L); }
- void addPartitioner(std::unique_ptr<GIMatchTreePartitioner> P) {
- Partitioners.push_back(std::move(P));
- }
- void addPartitionersForInstr(unsigned InstrIdx);
- void addPartitionersForOperand(unsigned InstrID, unsigned OpIdx);
- LeafVec &getPossibleLeaves() { return Leaves; }
- unsigned allocInstrID() { return NextInstrID++; }
- /// Construct the decision tree.
- std::unique_ptr<GIMatchTree> run();
- };
- /// Partitioners are the core of the tree builder and are unfortunately rather
- /// tricky to write.
- class GIMatchTreePartitioner {
- protected:
- /// The partitions resulting from applying the partitioner to the possible
- /// leaves. The keys must be consecutive integers starting from 0. This can
- /// lead to some unfortunate situations where partitioners test a predicate
- /// and use 0 for success and 1 for failure if the ruleset encounters a
- /// success case first but is necessary to assign the partition to one of the
- /// tree nodes children. As a result, you usually need some kind of
- /// indirection to map the natural keys (e.g. ptrs/bools) to this linear
- /// sequence. The values are a bitvector indicating which leaves belong to
- /// this partition.
- DenseMap<unsigned, BitVector> Partitions;
- public:
- virtual ~GIMatchTreePartitioner() {}
- virtual std::unique_ptr<GIMatchTreePartitioner> clone() const = 0;
- /// Determines which partitions the given leaves belong to. A leaf may belong
- /// to multiple partitions in which case it will be duplicated during
- /// applyForPartition().
- ///
- /// This function can be rather complicated. A few particular things to be
- /// aware of include:
- /// * One leaf can be assigned to multiple partitions when there's some
- /// ambiguity.
- /// * Not all DAG's for the leaves may be able to perform the test. For
- /// example, the opcode partitiioner must account for one DAG being a
- /// superset of another such as [(ADD ..., ..., ...)], and [(MUL t, ...,
- /// ...), (ADD ..., t, ...)]
- /// * Attaching meaning to a particular partition index will generally not
- /// work due to the '0, 1, ..., n' requirement. You might encounter cases
- /// where only partition 1 is seen, leaving a missing 0.
- /// * Finding a specific predicate such as the opcode predicate for a specific
- /// instruction is non-trivial. It's often O(NumPredicates), leading to
- /// O(NumPredicates*NumRules) when applied to the whole ruleset. The good
- /// news there is that n is typically small thanks to predicate dependencies
- /// limiting how many are testable at once. Also, with opcode and type
- /// predicates being so frequent the value of m drops very fast too. It
- /// wouldn't be terribly surprising to see a 10k ruleset drop down to an
- /// average of 100 leaves per partition after a single opcode partitioner.
- /// * The same goes for finding specific edges. The need to traverse them in
- /// dependency order dramatically limits the search space at any given
- /// moment.
- /// * If you need to add a leaf to all partitions, make sure you don't forget
- /// them when adding partitions later.
- virtual void repartition(GIMatchTreeBuilder::LeafVec &Leaves) = 0;
- /// Delegate the leaves for a given partition to the corresponding subbuilder,
- /// update any recorded context for this partition (e.g. allocate instr id's
- /// for instrs recorder by the current node), and clear any blocking
- /// dependencies this partitioner resolved.
- virtual void applyForPartition(unsigned PartitionIdx,
- GIMatchTreeBuilder &Builder,
- GIMatchTreeBuilder &SubBuilder) = 0;
- /// Return a BitVector indicating which leaves should be transferred to the
- /// specified partition. Note that the same leaf can be indicated for multiple
- /// partitions.
- BitVector getPossibleLeavesForPartition(unsigned Idx) {
- const auto &I = Partitions.find(Idx);
- assert(I != Partitions.end() && "Requested non-existant partition");
- return I->second;
- }
- size_t getNumPartitions() const { return Partitions.size(); }
- size_t getNumLeavesWithDupes() const {
- size_t S = 0;
- for (const auto &P : Partitions)
- S += P.second.size();
- return S;
- }
- /// Emit a brief description of the partitioner suitable for debug printing or
- /// use in a DOT graph.
- virtual void emitDescription(raw_ostream &OS) const = 0;
- /// Emit a label for the given partition suitable for debug printing or use in
- /// a DOT graph.
- virtual void emitPartitionName(raw_ostream &OS, unsigned Idx) const = 0;
- /// Emit a long description of how the partitioner partitions the leaves.
- virtual void emitPartitionResults(raw_ostream &OS) const = 0;
- /// Generate code to select between partitions based on the MIR being matched.
- /// This is typically a switch statement that picks a partition index.
- virtual void generatePartitionSelectorCode(raw_ostream &OS,
- StringRef Indent) const = 0;
- };
- /// Partition according to the opcode of the instruction.
- ///
- /// Numbers CodeGenInstr ptrs for use as partition ID's. One special partition,
- /// nullptr, represents the case where the instruction isn't known.
- ///
- /// * If the opcode can be tested and is a single opcode, create the partition
- /// for that opcode and assign the leaf to it. This partition no longer needs
- /// to test the opcode, and many details about the instruction will usually
- /// become known (e.g. number of operands for non-variadic instrs) via the
- /// CodeGenInstr ptr.
- /// * (not implemented yet) If the opcode can be tested and is a choice of
- /// opcodes, then the leaf can be treated like the single-opcode case but must
- /// be added to all relevant partitions and not quite as much becomes known as
- /// a result. That said, multiple-choice opcodes are likely similar enough
- /// (because if they aren't then handling them together makes little sense)
- /// that plenty still becomes known. The main implementation issue with this
- /// is having a description to represent the commonality between instructions.
- /// * If the opcode is not tested, the leaf must be added to all partitions
- /// including the wildcard nullptr partition. What becomes known as a result
- /// varies between partitions.
- /// * If the instruction to be tested is not declared then add the leaf to all
- /// partitions. This occurs when we encounter one rule that is a superset of
- /// the other and we are still matching the remainder of the superset. The
- /// result is that the cases that don't match the superset will match the
- /// subset rule, while the ones that do match the superset will match either
- /// (which one is algorithm dependent but will usually be the superset).
- class GIMatchTreeOpcodePartitioner : public GIMatchTreePartitioner {
- unsigned InstrID;
- DenseMap<const CodeGenInstruction *, unsigned> InstrToPartition;
- std::vector<const CodeGenInstruction *> PartitionToInstr;
- std::vector<BitVector> TestedPredicates;
- public:
- GIMatchTreeOpcodePartitioner(unsigned InstrID) : InstrID(InstrID) {}
- std::unique_ptr<GIMatchTreePartitioner> clone() const override {
- return std::make_unique<GIMatchTreeOpcodePartitioner>(*this);
- }
- void emitDescription(raw_ostream &OS) const override {
- OS << "MI[" << InstrID << "].getOpcode()";
- }
- void emitPartitionName(raw_ostream &OS, unsigned Idx) const override;
- void repartition(GIMatchTreeBuilder::LeafVec &Leaves) override;
- void applyForPartition(unsigned Idx, GIMatchTreeBuilder &SubBuilder,
- GIMatchTreeBuilder &Builder) override;
- void emitPartitionResults(raw_ostream &OS) const override;
- void generatePartitionSelectorCode(raw_ostream &OS,
- StringRef Indent) const override;
- };
- class GIMatchTreeVRegDefPartitioner : public GIMatchTreePartitioner {
- unsigned NewInstrID = -1;
- unsigned InstrID;
- unsigned OpIdx;
- std::vector<BitVector> TraversedEdges;
- DenseMap<unsigned, unsigned> ResultToPartition;
- BitVector PartitionToResult;
- void addToPartition(bool Result, unsigned LeafIdx);
- public:
- GIMatchTreeVRegDefPartitioner(unsigned InstrID, unsigned OpIdx)
- : InstrID(InstrID), OpIdx(OpIdx) {}
- std::unique_ptr<GIMatchTreePartitioner> clone() const override {
- return std::make_unique<GIMatchTreeVRegDefPartitioner>(*this);
- }
- void emitDescription(raw_ostream &OS) const override {
- OS << "MI[" << NewInstrID << "] = getVRegDef(MI[" << InstrID
- << "].getOperand(" << OpIdx << "))";
- }
- void emitPartitionName(raw_ostream &OS, unsigned Idx) const override {
- bool Result = PartitionToResult[Idx];
- if (Result)
- OS << "true";
- else
- OS << "false";
- }
- void repartition(GIMatchTreeBuilder::LeafVec &Leaves) override;
- void applyForPartition(unsigned PartitionIdx, GIMatchTreeBuilder &Builder,
- GIMatchTreeBuilder &SubBuilder) override;
- void emitPartitionResults(raw_ostream &OS) const override;
- void generatePartitionSelectorCode(raw_ostream &OS,
- StringRef Indent) const override;
- };
- } // end namespace llvm
- #endif // ifndef LLVM_UTILS_TABLEGEN_GIMATCHTREE_H
|