xref: /llvm-project/mlir/lib/TableGen/Predicate.cpp (revision b5235d1a9ceccda7b9195fa4da0eef8e48ac4d58)
18f249438SJacques Pienaar //===- Predicate.cpp - Predicate class ------------------------------------===//
28f249438SJacques Pienaar //
38f249438SJacques Pienaar // Copyright 2019 The MLIR Authors.
48f249438SJacques Pienaar //
58f249438SJacques Pienaar // Licensed under the Apache License, Version 2.0 (the "License");
68f249438SJacques Pienaar // you may not use this file except in compliance with the License.
78f249438SJacques Pienaar // You may obtain a copy of the License at
88f249438SJacques Pienaar //
98f249438SJacques Pienaar //   http://www.apache.org/licenses/LICENSE-2.0
108f249438SJacques Pienaar //
118f249438SJacques Pienaar // Unless required by applicable law or agreed to in writing, software
128f249438SJacques Pienaar // distributed under the License is distributed on an "AS IS" BASIS,
138f249438SJacques Pienaar // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
148f249438SJacques Pienaar // See the License for the specific language governing permissions and
158f249438SJacques Pienaar // limitations under the License.
168f249438SJacques Pienaar // =============================================================================
178f249438SJacques Pienaar //
188f249438SJacques Pienaar // Wrapper around predicates defined in TableGen.
198f249438SJacques Pienaar //
208f249438SJacques Pienaar //===----------------------------------------------------------------------===//
218f249438SJacques Pienaar 
228f249438SJacques Pienaar #include "mlir/TableGen/Predicate.h"
234c0faef9SJacques Pienaar #include "llvm/ADT/SetVector.h"
2405b02bb9SAlex Zinenko #include "llvm/ADT/SmallPtrSet.h"
258f249438SJacques Pienaar #include "llvm/ADT/StringExtras.h"
268f249438SJacques Pienaar #include "llvm/Support/FormatVariadic.h"
278f249438SJacques Pienaar #include "llvm/TableGen/Error.h"
288f249438SJacques Pienaar #include "llvm/TableGen/Record.h"
298f249438SJacques Pienaar 
308f249438SJacques Pienaar using namespace mlir;
318f249438SJacques Pienaar 
3244e9869fSAlex Zinenko // Construct a Predicate from a record.
3305b02bb9SAlex Zinenko tblgen::Pred::Pred(const llvm::Record *record) : def(record) {
3444e9869fSAlex Zinenko   assert(def->isSubClassOf("Pred") &&
3544e9869fSAlex Zinenko          "must be a subclass of TableGen 'Pred' class");
3644e9869fSAlex Zinenko }
3744e9869fSAlex Zinenko 
3844e9869fSAlex Zinenko // Construct a Predicate from an initializer.
3944e9869fSAlex Zinenko tblgen::Pred::Pred(const llvm::Init *init) : def(nullptr) {
4044e9869fSAlex Zinenko   if (const auto *defInit = dyn_cast_or_null<llvm::DefInit>(init))
41b2cc2c34SLei Zhang     def = defInit->getDef();
42b2cc2c34SLei Zhang }
43b2cc2c34SLei Zhang 
4405b02bb9SAlex Zinenko std::string tblgen::Pred::getCondition() const {
4505b02bb9SAlex Zinenko   // Static dispatch to subclasses.
4605b02bb9SAlex Zinenko   if (def->isSubClassOf("CombinedPred"))
4705b02bb9SAlex Zinenko     return static_cast<const CombinedPred *>(this)->getConditionImpl();
4805b02bb9SAlex Zinenko   if (def->isSubClassOf("CPred"))
4905b02bb9SAlex Zinenko     return static_cast<const CPred *>(this)->getConditionImpl();
5005b02bb9SAlex Zinenko   llvm_unreachable("Pred::getCondition must be overridden in subclasses");
5105b02bb9SAlex Zinenko }
5205b02bb9SAlex Zinenko 
5305b02bb9SAlex Zinenko bool tblgen::Pred::isCombined() const {
5405b02bb9SAlex Zinenko   return def && def->isSubClassOf("CombinedPred");
5505b02bb9SAlex Zinenko }
5605b02bb9SAlex Zinenko 
5705b02bb9SAlex Zinenko ArrayRef<llvm::SMLoc> tblgen::Pred::getLoc() const { return def->getLoc(); }
5805b02bb9SAlex Zinenko 
5905b02bb9SAlex Zinenko tblgen::CPred::CPred(const llvm::Record *record) : Pred(record) {
6005b02bb9SAlex Zinenko   assert(def->isSubClassOf("CPred") &&
6105b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CPred' class");
6205b02bb9SAlex Zinenko }
6305b02bb9SAlex Zinenko 
6405b02bb9SAlex Zinenko tblgen::CPred::CPred(const llvm::Init *init) : Pred(init) {
6505b02bb9SAlex Zinenko   assert((!def || def->isSubClassOf("CPred")) &&
6605b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CPred' class");
6705b02bb9SAlex Zinenko }
6805b02bb9SAlex Zinenko 
6905b02bb9SAlex Zinenko // Get condition of the C Predicate.
7005b02bb9SAlex Zinenko std::string tblgen::CPred::getConditionImpl() const {
7144e9869fSAlex Zinenko   assert(!isNull() && "null predicate does not have a condition");
728f5fa566SLei Zhang   return def->getValueAsString("predExpr");
738f249438SJacques Pienaar }
7405b02bb9SAlex Zinenko 
7505b02bb9SAlex Zinenko tblgen::CombinedPred::CombinedPred(const llvm::Record *record) : Pred(record) {
7605b02bb9SAlex Zinenko   assert(def->isSubClassOf("CombinedPred") &&
7705b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CombinedPred' class");
7805b02bb9SAlex Zinenko }
7905b02bb9SAlex Zinenko 
8005b02bb9SAlex Zinenko tblgen::CombinedPred::CombinedPred(const llvm::Init *init) : Pred(init) {
8105b02bb9SAlex Zinenko   assert((!def || def->isSubClassOf("CombinedPred")) &&
8205b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CombinedPred' class");
8305b02bb9SAlex Zinenko }
8405b02bb9SAlex Zinenko 
8505b02bb9SAlex Zinenko const llvm::Record *tblgen::CombinedPred::getCombinerDef() const {
8605b02bb9SAlex Zinenko   assert(def->getValue("kind") && "CombinedPred must have a value 'kind'");
8705b02bb9SAlex Zinenko   return def->getValueAsDef("kind");
8805b02bb9SAlex Zinenko }
8905b02bb9SAlex Zinenko 
9005b02bb9SAlex Zinenko const std::vector<llvm::Record *> tblgen::CombinedPred::getChildren() const {
9105b02bb9SAlex Zinenko   assert(def->getValue("children") &&
9205b02bb9SAlex Zinenko          "CombinedPred must have a value 'children'");
9305b02bb9SAlex Zinenko   return def->getValueAsListOfDefs("children");
9405b02bb9SAlex Zinenko }
9505b02bb9SAlex Zinenko 
9605b02bb9SAlex Zinenko namespace {
9705b02bb9SAlex Zinenko // Kinds of nodes in a logical predicate tree.
9805b02bb9SAlex Zinenko enum class PredCombinerKind {
9905b02bb9SAlex Zinenko   Leaf,
10005b02bb9SAlex Zinenko   And,
10105b02bb9SAlex Zinenko   Or,
10205b02bb9SAlex Zinenko   Not,
10305b02bb9SAlex Zinenko   SubstLeaves,
104*b5235d1aSLei Zhang   Concat,
10505b02bb9SAlex Zinenko   // Special kinds that are used in simplification.
10605b02bb9SAlex Zinenko   False,
10705b02bb9SAlex Zinenko   True
10805b02bb9SAlex Zinenko };
10905b02bb9SAlex Zinenko 
11005b02bb9SAlex Zinenko // A node in a logical predicate tree.
11105b02bb9SAlex Zinenko struct PredNode {
11205b02bb9SAlex Zinenko   PredCombinerKind kind;
11305b02bb9SAlex Zinenko   const tblgen::Pred *predicate;
11405b02bb9SAlex Zinenko   SmallVector<PredNode *, 4> children;
11505b02bb9SAlex Zinenko   std::string expr;
116*b5235d1aSLei Zhang 
117*b5235d1aSLei Zhang   // Prefix and suffix are used by ConcatPred.
118*b5235d1aSLei Zhang   std::string prefix;
119*b5235d1aSLei Zhang   std::string suffix;
12005b02bb9SAlex Zinenko };
12105b02bb9SAlex Zinenko } // end anonymous namespace
12205b02bb9SAlex Zinenko 
12305b02bb9SAlex Zinenko // Get a predicate tree node kind based on the kind used in the predicate
12405b02bb9SAlex Zinenko // TableGen record.
12505b02bb9SAlex Zinenko static PredCombinerKind getPredCombinerKind(const tblgen::Pred &pred) {
12605b02bb9SAlex Zinenko   if (!pred.isCombined())
12705b02bb9SAlex Zinenko     return PredCombinerKind::Leaf;
12805b02bb9SAlex Zinenko 
12905b02bb9SAlex Zinenko   const auto &combinedPred = static_cast<const tblgen::CombinedPred &>(pred);
13005b02bb9SAlex Zinenko   return llvm::StringSwitch<PredCombinerKind>(
13105b02bb9SAlex Zinenko              combinedPred.getCombinerDef()->getName())
13205b02bb9SAlex Zinenko       .Case("PredCombinerAnd", PredCombinerKind::And)
13305b02bb9SAlex Zinenko       .Case("PredCombinerOr", PredCombinerKind::Or)
13405b02bb9SAlex Zinenko       .Case("PredCombinerNot", PredCombinerKind::Not)
135*b5235d1aSLei Zhang       .Case("PredCombinerSubstLeaves", PredCombinerKind::SubstLeaves)
136*b5235d1aSLei Zhang       .Case("PredCombinerConcat", PredCombinerKind::Concat);
13705b02bb9SAlex Zinenko }
13805b02bb9SAlex Zinenko 
13905b02bb9SAlex Zinenko namespace {
14005b02bb9SAlex Zinenko // Substitution<pattern, replacement>.
14105b02bb9SAlex Zinenko using Subst = std::pair<StringRef, StringRef>;
14205b02bb9SAlex Zinenko } // end anonymous namespace
14305b02bb9SAlex Zinenko 
14405b02bb9SAlex Zinenko // Build the predicate tree starting from the top-level predicate, which may
14505b02bb9SAlex Zinenko // have children, and perform leaf substitutions inplace.  Note that after
14605b02bb9SAlex Zinenko // substitution, nodes are still pointing to the original TableGen record.
14705b02bb9SAlex Zinenko // All nodes are created within "allocator".
14805b02bb9SAlex Zinenko static PredNode *buildPredicateTree(const tblgen::Pred &root,
14905b02bb9SAlex Zinenko                                     llvm::BumpPtrAllocator &allocator,
15005b02bb9SAlex Zinenko                                     ArrayRef<Subst> substitutions) {
15105b02bb9SAlex Zinenko   auto *rootNode = allocator.Allocate<PredNode>();
15205b02bb9SAlex Zinenko   new (rootNode) PredNode;
15305b02bb9SAlex Zinenko   rootNode->kind = getPredCombinerKind(root);
15405b02bb9SAlex Zinenko   rootNode->predicate = &root;
15505b02bb9SAlex Zinenko   if (!root.isCombined()) {
15605b02bb9SAlex Zinenko     rootNode->expr = root.getCondition();
15705b02bb9SAlex Zinenko     // Apply all parent substitutions from innermost to outermost.
15805b02bb9SAlex Zinenko     for (const auto &subst : llvm::reverse(substitutions)) {
1594887e455SLei Zhang       auto pos = rootNode->expr.find(subst.first);
1604887e455SLei Zhang       while (pos != std::string::npos) {
16105b02bb9SAlex Zinenko         rootNode->expr.replace(pos, subst.first.size(), subst.second);
1624887e455SLei Zhang         // Skip the newly inserted substring, which itself may consider the
1634887e455SLei Zhang         // pattern to match.
1644887e455SLei Zhang         pos += subst.second.size();
1654887e455SLei Zhang         // Find the next possible match position.
1664887e455SLei Zhang         pos = rootNode->expr.find(subst.first, pos);
16705b02bb9SAlex Zinenko       }
16805b02bb9SAlex Zinenko     }
16905b02bb9SAlex Zinenko     return rootNode;
17005b02bb9SAlex Zinenko   }
17105b02bb9SAlex Zinenko 
17205b02bb9SAlex Zinenko   // If the current combined predicate is a leaf substitution, append it to the
17305b02bb9SAlex Zinenko   // list before contiuing.
17405b02bb9SAlex Zinenko   auto allSubstitutions = llvm::to_vector<4>(substitutions);
17505b02bb9SAlex Zinenko   if (rootNode->kind == PredCombinerKind::SubstLeaves) {
17605b02bb9SAlex Zinenko     const auto &substPred = static_cast<const tblgen::SubstLeavesPred &>(root);
17705b02bb9SAlex Zinenko     allSubstitutions.push_back(
17805b02bb9SAlex Zinenko         {substPred.getPattern(), substPred.getReplacement()});
17905b02bb9SAlex Zinenko   }
180*b5235d1aSLei Zhang   // If the current predicate is a ConcatPred, record the prefix and suffix.
181*b5235d1aSLei Zhang   else if (rootNode->kind == PredCombinerKind::Concat) {
182*b5235d1aSLei Zhang     const auto &concatPred = static_cast<const tblgen::ConcatPred &>(root);
183*b5235d1aSLei Zhang     rootNode->prefix = concatPred.getPrefix();
184*b5235d1aSLei Zhang     rootNode->suffix = concatPred.getSuffix();
185*b5235d1aSLei Zhang   }
18605b02bb9SAlex Zinenko 
18705b02bb9SAlex Zinenko   // Build child subtrees.
18805b02bb9SAlex Zinenko   auto combined = static_cast<const tblgen::CombinedPred &>(root);
18905b02bb9SAlex Zinenko   for (const auto *record : combined.getChildren()) {
19005b02bb9SAlex Zinenko     auto childTree =
19105b02bb9SAlex Zinenko         buildPredicateTree(tblgen::Pred(record), allocator, allSubstitutions);
19205b02bb9SAlex Zinenko     rootNode->children.push_back(childTree);
19305b02bb9SAlex Zinenko   }
19405b02bb9SAlex Zinenko   return rootNode;
19505b02bb9SAlex Zinenko }
19605b02bb9SAlex Zinenko 
19705b02bb9SAlex Zinenko // Simplify a predicate tree rooted at "node" using the predicates that are
19805b02bb9SAlex Zinenko // known to be true(false).  For AND(OR) combined predicates, if any of the
19905b02bb9SAlex Zinenko // children is known to be false(true), the result is also false(true).
20005b02bb9SAlex Zinenko // Furthermore, for AND(OR) combined predicates, children that are known to be
20105b02bb9SAlex Zinenko // true(false) don't have to be checked dynamically.
20205b02bb9SAlex Zinenko static PredNode *propagateGroundTruth(
20305b02bb9SAlex Zinenko     PredNode *node, const llvm::SmallPtrSetImpl<tblgen::Pred *> &knownTruePreds,
20405b02bb9SAlex Zinenko     const llvm::SmallPtrSetImpl<tblgen::Pred *> &knownFalsePreds) {
20505b02bb9SAlex Zinenko   // If the current predicate is known to be true or false, change the kind of
20605b02bb9SAlex Zinenko   // the node and return immediately.
20705b02bb9SAlex Zinenko   if (knownTruePreds.count(node->predicate) != 0) {
20805b02bb9SAlex Zinenko     node->kind = PredCombinerKind::True;
20905b02bb9SAlex Zinenko     node->children.clear();
21005b02bb9SAlex Zinenko     return node;
21105b02bb9SAlex Zinenko   }
21205b02bb9SAlex Zinenko   if (knownFalsePreds.count(node->predicate) != 0) {
21305b02bb9SAlex Zinenko     node->kind = PredCombinerKind::False;
21405b02bb9SAlex Zinenko     node->children.clear();
21505b02bb9SAlex Zinenko     return node;
21605b02bb9SAlex Zinenko   }
21705b02bb9SAlex Zinenko 
21805b02bb9SAlex Zinenko   // If the current node is a substitution, stop recursion now.
21905b02bb9SAlex Zinenko   // The expressions in the leaves below this node were rewritten, but the nodes
22005b02bb9SAlex Zinenko   // still point to the original predicate records.  While the original
22105b02bb9SAlex Zinenko   // predicate may be known to be true or false, it is not necessarily the case
22205b02bb9SAlex Zinenko   // after rewriting.
22305b02bb9SAlex Zinenko   // TODO(zinenko,jpienaar): we can support ground truth for rewritten
22405b02bb9SAlex Zinenko   // predicates by either (a) having our own unique'ing of the predicates
22505b02bb9SAlex Zinenko   // instead of relying on TableGen record pointers or (b) taking ground truth
22605b02bb9SAlex Zinenko   // values optinally prefixed with a list of substitutions to apply, e.g.
22705b02bb9SAlex Zinenko   // "predX is true by itself as well as predSubY leaf substitution had been
22805b02bb9SAlex Zinenko   // applied to it".
22905b02bb9SAlex Zinenko   if (node->kind == PredCombinerKind::SubstLeaves) {
23005b02bb9SAlex Zinenko     return node;
23105b02bb9SAlex Zinenko   }
23205b02bb9SAlex Zinenko 
23305b02bb9SAlex Zinenko   // Otherwise, look at child nodes.
23405b02bb9SAlex Zinenko 
23505b02bb9SAlex Zinenko   // Move child nodes into some local variable so that they can be optimized
23605b02bb9SAlex Zinenko   // separately and re-added if necessary.
23705b02bb9SAlex Zinenko   llvm::SmallVector<PredNode *, 4> children;
23805b02bb9SAlex Zinenko   std::swap(node->children, children);
23905b02bb9SAlex Zinenko 
24005b02bb9SAlex Zinenko   for (auto &child : children) {
24105b02bb9SAlex Zinenko     // First, simplify the child.  This maintains the predicate as it was.
24205b02bb9SAlex Zinenko     auto simplifiedChild =
24305b02bb9SAlex Zinenko         propagateGroundTruth(child, knownTruePreds, knownFalsePreds);
24405b02bb9SAlex Zinenko 
24505b02bb9SAlex Zinenko     // Just add the child if we don't know how to simplify the current node.
24605b02bb9SAlex Zinenko     if (node->kind != PredCombinerKind::And &&
24705b02bb9SAlex Zinenko         node->kind != PredCombinerKind::Or) {
24805b02bb9SAlex Zinenko       node->children.push_back(simplifiedChild);
24905b02bb9SAlex Zinenko       continue;
25005b02bb9SAlex Zinenko     }
25105b02bb9SAlex Zinenko 
25205b02bb9SAlex Zinenko     // Second, based on the type define which known values of child predicates
25305b02bb9SAlex Zinenko     // immediately collapse this predicate to a known value, and which others
25405b02bb9SAlex Zinenko     // may be safely ignored.
25505b02bb9SAlex Zinenko     //   OR(..., True, ...) = True
25605b02bb9SAlex Zinenko     //   OR(..., False, ...) = OR(..., ...)
25705b02bb9SAlex Zinenko     //   AND(..., False, ...) = False
25805b02bb9SAlex Zinenko     //   AND(..., True, ...) = AND(..., ...)
25905b02bb9SAlex Zinenko     auto collapseKind = node->kind == PredCombinerKind::And
26005b02bb9SAlex Zinenko                             ? PredCombinerKind::False
26105b02bb9SAlex Zinenko                             : PredCombinerKind::True;
26205b02bb9SAlex Zinenko     auto eraseKind = node->kind == PredCombinerKind::And
26305b02bb9SAlex Zinenko                          ? PredCombinerKind::True
26405b02bb9SAlex Zinenko                          : PredCombinerKind::False;
26505b02bb9SAlex Zinenko     const auto &collapseList =
26605b02bb9SAlex Zinenko         node->kind == PredCombinerKind::And ? knownFalsePreds : knownTruePreds;
26705b02bb9SAlex Zinenko     const auto &eraseList =
26805b02bb9SAlex Zinenko         node->kind == PredCombinerKind::And ? knownTruePreds : knownFalsePreds;
26905b02bb9SAlex Zinenko     if (simplifiedChild->kind == collapseKind ||
27005b02bb9SAlex Zinenko         collapseList.count(simplifiedChild->predicate) != 0) {
27105b02bb9SAlex Zinenko       node->kind = collapseKind;
27205b02bb9SAlex Zinenko       node->children.clear();
27305b02bb9SAlex Zinenko       return node;
27405b02bb9SAlex Zinenko     } else if (simplifiedChild->kind == eraseKind ||
27505b02bb9SAlex Zinenko                eraseList.count(simplifiedChild->predicate) != 0) {
27605b02bb9SAlex Zinenko       continue;
27705b02bb9SAlex Zinenko     }
27805b02bb9SAlex Zinenko     node->children.push_back(simplifiedChild);
27905b02bb9SAlex Zinenko   }
28005b02bb9SAlex Zinenko   return node;
28105b02bb9SAlex Zinenko }
28205b02bb9SAlex Zinenko 
28305b02bb9SAlex Zinenko // Combine a list of predicate expressions using a binary combiner.  If a list
28405b02bb9SAlex Zinenko // is empty, return "init".
28505b02bb9SAlex Zinenko static std::string combineBinary(ArrayRef<std::string> children,
28605b02bb9SAlex Zinenko                                  std::string combiner, std::string init) {
28705b02bb9SAlex Zinenko   if (children.empty())
28805b02bb9SAlex Zinenko     return init;
28905b02bb9SAlex Zinenko 
29005b02bb9SAlex Zinenko   auto size = children.size();
29105b02bb9SAlex Zinenko   if (size == 1)
29205b02bb9SAlex Zinenko     return children.front();
29305b02bb9SAlex Zinenko 
29405b02bb9SAlex Zinenko   std::string str;
29505b02bb9SAlex Zinenko   llvm::raw_string_ostream os(str);
29605b02bb9SAlex Zinenko   os << '(' << children.front() << ')';
29705b02bb9SAlex Zinenko   for (unsigned i = 1; i < size; ++i) {
29805b02bb9SAlex Zinenko     os << ' ' << combiner << " (" << children[i] << ')';
29905b02bb9SAlex Zinenko   }
30005b02bb9SAlex Zinenko   return os.str();
30105b02bb9SAlex Zinenko }
30205b02bb9SAlex Zinenko 
30305b02bb9SAlex Zinenko // Prepend negation to the only condition in the predicate expression list.
30405b02bb9SAlex Zinenko static std::string combineNot(ArrayRef<std::string> children) {
30505b02bb9SAlex Zinenko   assert(children.size() == 1 && "expected exactly one child predicate of Neg");
30605b02bb9SAlex Zinenko   return (Twine("!(") + children.front() + Twine(')')).str();
30705b02bb9SAlex Zinenko }
30805b02bb9SAlex Zinenko 
30905b02bb9SAlex Zinenko // Recursively traverse the predicate tree in depth-first post-order and build
31005b02bb9SAlex Zinenko // the final expression.
31105b02bb9SAlex Zinenko static std::string getCombinedCondition(const PredNode &root) {
31205b02bb9SAlex Zinenko   // Immediately return for non-combiner predicates that don't have children.
31305b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Leaf)
31405b02bb9SAlex Zinenko     return root.expr;
31505b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::True)
31605b02bb9SAlex Zinenko     return "true";
31705b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::False)
31805b02bb9SAlex Zinenko     return "false";
31905b02bb9SAlex Zinenko 
32005b02bb9SAlex Zinenko   // Recurse into children.
32105b02bb9SAlex Zinenko   llvm::SmallVector<std::string, 4> childExpressions;
32205b02bb9SAlex Zinenko   childExpressions.reserve(root.children.size());
32305b02bb9SAlex Zinenko   for (const auto &child : root.children)
32405b02bb9SAlex Zinenko     childExpressions.push_back(getCombinedCondition(*child));
32505b02bb9SAlex Zinenko 
32605b02bb9SAlex Zinenko   // Combine the expressions based on the predicate node kind.
32705b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::And)
32805b02bb9SAlex Zinenko     return combineBinary(childExpressions, "&&", "true");
32905b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Or)
33005b02bb9SAlex Zinenko     return combineBinary(childExpressions, "||", "false");
33105b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Not)
33205b02bb9SAlex Zinenko     return combineNot(childExpressions);
333*b5235d1aSLei Zhang   if (root.kind == PredCombinerKind::Concat) {
334*b5235d1aSLei Zhang     assert(childExpressions.size() == 1 &&
335*b5235d1aSLei Zhang            "ConcatPred should only have one child");
336*b5235d1aSLei Zhang     return root.prefix + childExpressions.front() + root.suffix;
337*b5235d1aSLei Zhang   }
33805b02bb9SAlex Zinenko 
33905b02bb9SAlex Zinenko   // Substitutions were applied before so just ignore them.
34005b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::SubstLeaves) {
34105b02bb9SAlex Zinenko     assert(childExpressions.size() == 1 &&
34205b02bb9SAlex Zinenko            "substitution predicate must have one child");
34305b02bb9SAlex Zinenko     return childExpressions[0];
34405b02bb9SAlex Zinenko   }
34505b02bb9SAlex Zinenko 
34605b02bb9SAlex Zinenko   llvm::PrintFatalError(root.predicate->getLoc(), "unsupported predicate kind");
34705b02bb9SAlex Zinenko }
34805b02bb9SAlex Zinenko 
34905b02bb9SAlex Zinenko std::string tblgen::CombinedPred::getConditionImpl() const {
35005b02bb9SAlex Zinenko   llvm::BumpPtrAllocator allocator;
35105b02bb9SAlex Zinenko   auto predicateTree = buildPredicateTree(*this, allocator, {});
35205b02bb9SAlex Zinenko   predicateTree = propagateGroundTruth(
35305b02bb9SAlex Zinenko       predicateTree,
35405b02bb9SAlex Zinenko       /*knownTruePreds=*/llvm::SmallPtrSet<tblgen::Pred *, 2>(),
35505b02bb9SAlex Zinenko       /*knownFalsePreds=*/llvm::SmallPtrSet<tblgen::Pred *, 2>());
35605b02bb9SAlex Zinenko 
35705b02bb9SAlex Zinenko   return getCombinedCondition(*predicateTree);
35805b02bb9SAlex Zinenko }
35905b02bb9SAlex Zinenko 
36005b02bb9SAlex Zinenko StringRef tblgen::SubstLeavesPred::getPattern() const {
36105b02bb9SAlex Zinenko   return def->getValueAsString("pattern");
36205b02bb9SAlex Zinenko }
36305b02bb9SAlex Zinenko 
36405b02bb9SAlex Zinenko StringRef tblgen::SubstLeavesPred::getReplacement() const {
36505b02bb9SAlex Zinenko   return def->getValueAsString("replacement");
36605b02bb9SAlex Zinenko }
367*b5235d1aSLei Zhang 
368*b5235d1aSLei Zhang StringRef tblgen::ConcatPred::getPrefix() const {
369*b5235d1aSLei Zhang   return def->getValueAsString("prefix");
370*b5235d1aSLei Zhang }
371*b5235d1aSLei Zhang 
372*b5235d1aSLei Zhang StringRef tblgen::ConcatPred::getSuffix() const {
373*b5235d1aSLei Zhang   return def->getValueAsString("suffix");
374*b5235d1aSLei Zhang }
375