xref: /llvm-project/mlir/lib/TableGen/Predicate.cpp (revision d8399d5dd6a5a7025621eddd97fc0fa1f494bad8)
18f249438SJacques Pienaar //===- Predicate.cpp - Predicate class ------------------------------------===//
28f249438SJacques Pienaar //
330857107SMehdi Amini // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
456222a06SMehdi Amini // See https://llvm.org/LICENSE.txt for license information.
556222a06SMehdi Amini // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
68f249438SJacques Pienaar //
756222a06SMehdi Amini //===----------------------------------------------------------------------===//
88f249438SJacques Pienaar //
98f249438SJacques Pienaar // Wrapper around predicates defined in TableGen.
108f249438SJacques Pienaar //
118f249438SJacques Pienaar //===----------------------------------------------------------------------===//
128f249438SJacques Pienaar 
138f249438SJacques Pienaar #include "mlir/TableGen/Predicate.h"
1405b02bb9SAlex Zinenko #include "llvm/ADT/SmallPtrSet.h"
158f249438SJacques Pienaar #include "llvm/ADT/StringExtras.h"
1675e164f6Sserge-sans-paille #include "llvm/ADT/StringSwitch.h"
178f249438SJacques Pienaar #include "llvm/Support/FormatVariadic.h"
188f249438SJacques Pienaar #include "llvm/TableGen/Error.h"
198f249438SJacques Pienaar #include "llvm/TableGen/Record.h"
208f249438SJacques Pienaar 
218f249438SJacques Pienaar using namespace mlir;
2212d16de5SRahul Joshi using namespace tblgen;
23659192b1SRahul Joshi using llvm::Init;
24659192b1SRahul Joshi using llvm::Record;
25659192b1SRahul Joshi using llvm::SpecificBumpPtrAllocator;
268f249438SJacques Pienaar 
2744e9869fSAlex Zinenko // Construct a Predicate from a record.
28659192b1SRahul Joshi Pred::Pred(const Record *record) : def(record) {
2944e9869fSAlex Zinenko   assert(def->isSubClassOf("Pred") &&
3044e9869fSAlex Zinenko          "must be a subclass of TableGen 'Pred' class");
3144e9869fSAlex Zinenko }
3244e9869fSAlex Zinenko 
3344e9869fSAlex Zinenko // Construct a Predicate from an initializer.
34659192b1SRahul Joshi Pred::Pred(const Init *init) {
3544e9869fSAlex Zinenko   if (const auto *defInit = dyn_cast_or_null<llvm::DefInit>(init))
36b2cc2c34SLei Zhang     def = defInit->getDef();
37b2cc2c34SLei Zhang }
38b2cc2c34SLei Zhang 
3912d16de5SRahul Joshi std::string Pred::getCondition() const {
4005b02bb9SAlex Zinenko   // Static dispatch to subclasses.
4105b02bb9SAlex Zinenko   if (def->isSubClassOf("CombinedPred"))
4205b02bb9SAlex Zinenko     return static_cast<const CombinedPred *>(this)->getConditionImpl();
4305b02bb9SAlex Zinenko   if (def->isSubClassOf("CPred"))
4405b02bb9SAlex Zinenko     return static_cast<const CPred *>(this)->getConditionImpl();
4505b02bb9SAlex Zinenko   llvm_unreachable("Pred::getCondition must be overridden in subclasses");
4605b02bb9SAlex Zinenko }
4705b02bb9SAlex Zinenko 
4812d16de5SRahul Joshi bool Pred::isCombined() const {
4905b02bb9SAlex Zinenko   return def && def->isSubClassOf("CombinedPred");
5005b02bb9SAlex Zinenko }
5105b02bb9SAlex Zinenko 
526842ec42SRiver Riddle ArrayRef<SMLoc> Pred::getLoc() const { return def->getLoc(); }
5305b02bb9SAlex Zinenko 
54659192b1SRahul Joshi CPred::CPred(const Record *record) : Pred(record) {
5505b02bb9SAlex Zinenko   assert(def->isSubClassOf("CPred") &&
5605b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CPred' class");
5705b02bb9SAlex Zinenko }
5805b02bb9SAlex Zinenko 
59659192b1SRahul Joshi CPred::CPred(const Init *init) : Pred(init) {
6005b02bb9SAlex Zinenko   assert((!def || def->isSubClassOf("CPred")) &&
6105b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CPred' class");
6205b02bb9SAlex Zinenko }
6305b02bb9SAlex Zinenko 
6405b02bb9SAlex Zinenko // Get condition of the C Predicate.
6512d16de5SRahul Joshi std::string CPred::getConditionImpl() const {
6644e9869fSAlex Zinenko   assert(!isNull() && "null predicate does not have a condition");
67adcd0268SBenjamin Kramer   return std::string(def->getValueAsString("predExpr"));
688f249438SJacques Pienaar }
6905b02bb9SAlex Zinenko 
70659192b1SRahul Joshi CombinedPred::CombinedPred(const Record *record) : Pred(record) {
7105b02bb9SAlex Zinenko   assert(def->isSubClassOf("CombinedPred") &&
7205b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CombinedPred' class");
7305b02bb9SAlex Zinenko }
7405b02bb9SAlex Zinenko 
75659192b1SRahul Joshi CombinedPred::CombinedPred(const Init *init) : Pred(init) {
7605b02bb9SAlex Zinenko   assert((!def || def->isSubClassOf("CombinedPred")) &&
7705b02bb9SAlex Zinenko          "must be a subclass of Tablegen 'CombinedPred' class");
7805b02bb9SAlex Zinenko }
7905b02bb9SAlex Zinenko 
80659192b1SRahul Joshi const Record *CombinedPred::getCombinerDef() const {
8105b02bb9SAlex Zinenko   assert(def->getValue("kind") && "CombinedPred must have a value 'kind'");
8205b02bb9SAlex Zinenko   return def->getValueAsDef("kind");
8305b02bb9SAlex Zinenko }
8405b02bb9SAlex Zinenko 
85659192b1SRahul Joshi std::vector<const Record *> CombinedPred::getChildren() const {
8605b02bb9SAlex Zinenko   assert(def->getValue("children") &&
8705b02bb9SAlex Zinenko          "CombinedPred must have a value 'children'");
88a140931bSRahul Joshi   return def->getValueAsListOfDefs("children");
8905b02bb9SAlex Zinenko }
9005b02bb9SAlex Zinenko 
9105b02bb9SAlex Zinenko namespace {
9205b02bb9SAlex Zinenko // Kinds of nodes in a logical predicate tree.
9305b02bb9SAlex Zinenko enum class PredCombinerKind {
9405b02bb9SAlex Zinenko   Leaf,
9505b02bb9SAlex Zinenko   And,
9605b02bb9SAlex Zinenko   Or,
9705b02bb9SAlex Zinenko   Not,
9805b02bb9SAlex Zinenko   SubstLeaves,
99b5235d1aSLei Zhang   Concat,
10005b02bb9SAlex Zinenko   // Special kinds that are used in simplification.
10105b02bb9SAlex Zinenko   False,
10205b02bb9SAlex Zinenko   True
10305b02bb9SAlex Zinenko };
10405b02bb9SAlex Zinenko 
10505b02bb9SAlex Zinenko // A node in a logical predicate tree.
10605b02bb9SAlex Zinenko struct PredNode {
10705b02bb9SAlex Zinenko   PredCombinerKind kind;
10812d16de5SRahul Joshi   const Pred *predicate;
10905b02bb9SAlex Zinenko   SmallVector<PredNode *, 4> children;
11005b02bb9SAlex Zinenko   std::string expr;
111b5235d1aSLei Zhang 
112b5235d1aSLei Zhang   // Prefix and suffix are used by ConcatPred.
113b5235d1aSLei Zhang   std::string prefix;
114b5235d1aSLei Zhang   std::string suffix;
11505b02bb9SAlex Zinenko };
116be0a7e9fSMehdi Amini } // namespace
11705b02bb9SAlex Zinenko 
11805b02bb9SAlex Zinenko // Get a predicate tree node kind based on the kind used in the predicate
11905b02bb9SAlex Zinenko // TableGen record.
12012d16de5SRahul Joshi static PredCombinerKind getPredCombinerKind(const Pred &pred) {
12105b02bb9SAlex Zinenko   if (!pred.isCombined())
12205b02bb9SAlex Zinenko     return PredCombinerKind::Leaf;
12305b02bb9SAlex Zinenko 
12412d16de5SRahul Joshi   const auto &combinedPred = static_cast<const CombinedPred &>(pred);
125cc83dc19SChristian Sigg   return StringSwitch<PredCombinerKind>(
12605b02bb9SAlex Zinenko              combinedPred.getCombinerDef()->getName())
12705b02bb9SAlex Zinenko       .Case("PredCombinerAnd", PredCombinerKind::And)
12805b02bb9SAlex Zinenko       .Case("PredCombinerOr", PredCombinerKind::Or)
12905b02bb9SAlex Zinenko       .Case("PredCombinerNot", PredCombinerKind::Not)
130b5235d1aSLei Zhang       .Case("PredCombinerSubstLeaves", PredCombinerKind::SubstLeaves)
131b5235d1aSLei Zhang       .Case("PredCombinerConcat", PredCombinerKind::Concat);
13205b02bb9SAlex Zinenko }
13305b02bb9SAlex Zinenko 
13405b02bb9SAlex Zinenko namespace {
13505b02bb9SAlex Zinenko // Substitution<pattern, replacement>.
13605b02bb9SAlex Zinenko using Subst = std::pair<StringRef, StringRef>;
137be0a7e9fSMehdi Amini } // namespace
13805b02bb9SAlex Zinenko 
1393a833a0eSRiver Riddle /// Perform the given substitutions on 'str' in-place.
1403a833a0eSRiver Riddle static void performSubstitutions(std::string &str,
1413a833a0eSRiver Riddle                                  ArrayRef<Subst> substitutions) {
1423a833a0eSRiver Riddle   // Apply all parent substitutions from innermost to outermost.
1433a833a0eSRiver Riddle   for (const auto &subst : llvm::reverse(substitutions)) {
1443a833a0eSRiver Riddle     auto pos = str.find(std::string(subst.first));
1453a833a0eSRiver Riddle     while (pos != std::string::npos) {
1463a833a0eSRiver Riddle       str.replace(pos, subst.first.size(), std::string(subst.second));
1473a833a0eSRiver Riddle       // Skip the newly inserted substring, which itself may consider the
1483a833a0eSRiver Riddle       // pattern to match.
1493a833a0eSRiver Riddle       pos += subst.second.size();
1503a833a0eSRiver Riddle       // Find the next possible match position.
1513a833a0eSRiver Riddle       pos = str.find(std::string(subst.first), pos);
1523a833a0eSRiver Riddle     }
1533a833a0eSRiver Riddle   }
1543a833a0eSRiver Riddle }
1553a833a0eSRiver Riddle 
15605b02bb9SAlex Zinenko // Build the predicate tree starting from the top-level predicate, which may
15705b02bb9SAlex Zinenko // have children, and perform leaf substitutions inplace.  Note that after
15805b02bb9SAlex Zinenko // substitution, nodes are still pointing to the original TableGen record.
15905b02bb9SAlex Zinenko // All nodes are created within "allocator".
160b68b8be8SBenjamin Kramer static PredNode *
16112d16de5SRahul Joshi buildPredicateTree(const Pred &root,
162659192b1SRahul Joshi                    SpecificBumpPtrAllocator<PredNode> &allocator,
16305b02bb9SAlex Zinenko                    ArrayRef<Subst> substitutions) {
164b68b8be8SBenjamin Kramer   auto *rootNode = allocator.Allocate();
16505b02bb9SAlex Zinenko   new (rootNode) PredNode;
16605b02bb9SAlex Zinenko   rootNode->kind = getPredCombinerKind(root);
16705b02bb9SAlex Zinenko   rootNode->predicate = &root;
16805b02bb9SAlex Zinenko   if (!root.isCombined()) {
16905b02bb9SAlex Zinenko     rootNode->expr = root.getCondition();
1703a833a0eSRiver Riddle     performSubstitutions(rootNode->expr, substitutions);
17105b02bb9SAlex Zinenko     return rootNode;
17205b02bb9SAlex Zinenko   }
17305b02bb9SAlex Zinenko 
17405b02bb9SAlex Zinenko   // If the current combined predicate is a leaf substitution, append it to the
1758bfedb3cSKazuaki Ishizaki   // list before continuing.
17605b02bb9SAlex Zinenko   auto allSubstitutions = llvm::to_vector<4>(substitutions);
17705b02bb9SAlex Zinenko   if (rootNode->kind == PredCombinerKind::SubstLeaves) {
17812d16de5SRahul Joshi     const auto &substPred = static_cast<const SubstLeavesPred &>(root);
17905b02bb9SAlex Zinenko     allSubstitutions.push_back(
18005b02bb9SAlex Zinenko         {substPred.getPattern(), substPred.getReplacement()});
1813a833a0eSRiver Riddle 
182b5235d1aSLei Zhang     // If the current predicate is a ConcatPred, record the prefix and suffix.
1833a833a0eSRiver Riddle   } else if (rootNode->kind == PredCombinerKind::Concat) {
18412d16de5SRahul Joshi     const auto &concatPred = static_cast<const ConcatPred &>(root);
185adcd0268SBenjamin Kramer     rootNode->prefix = std::string(concatPred.getPrefix());
1863a833a0eSRiver Riddle     performSubstitutions(rootNode->prefix, substitutions);
187adcd0268SBenjamin Kramer     rootNode->suffix = std::string(concatPred.getSuffix());
1883a833a0eSRiver Riddle     performSubstitutions(rootNode->suffix, substitutions);
189b5235d1aSLei Zhang   }
19005b02bb9SAlex Zinenko 
19105b02bb9SAlex Zinenko   // Build child subtrees.
19212d16de5SRahul Joshi   auto combined = static_cast<const CombinedPred &>(root);
19305b02bb9SAlex Zinenko   for (const auto *record : combined.getChildren()) {
19402b6fb21SMehdi Amini     auto *childTree =
19512d16de5SRahul Joshi         buildPredicateTree(Pred(record), allocator, allSubstitutions);
19605b02bb9SAlex Zinenko     rootNode->children.push_back(childTree);
19705b02bb9SAlex Zinenko   }
19805b02bb9SAlex Zinenko   return rootNode;
19905b02bb9SAlex Zinenko }
20005b02bb9SAlex Zinenko 
20105b02bb9SAlex Zinenko // Simplify a predicate tree rooted at "node" using the predicates that are
20205b02bb9SAlex Zinenko // known to be true(false).  For AND(OR) combined predicates, if any of the
20305b02bb9SAlex Zinenko // children is known to be false(true), the result is also false(true).
20405b02bb9SAlex Zinenko // Furthermore, for AND(OR) combined predicates, children that are known to be
20505b02bb9SAlex Zinenko // true(false) don't have to be checked dynamically.
20612d16de5SRahul Joshi static PredNode *
20712d16de5SRahul Joshi propagateGroundTruth(PredNode *node,
20812d16de5SRahul Joshi                      const llvm::SmallPtrSetImpl<Pred *> &knownTruePreds,
20912d16de5SRahul Joshi                      const llvm::SmallPtrSetImpl<Pred *> &knownFalsePreds) {
21005b02bb9SAlex Zinenko   // If the current predicate is known to be true or false, change the kind of
21105b02bb9SAlex Zinenko   // the node and return immediately.
21205b02bb9SAlex Zinenko   if (knownTruePreds.count(node->predicate) != 0) {
21305b02bb9SAlex Zinenko     node->kind = PredCombinerKind::True;
21405b02bb9SAlex Zinenko     node->children.clear();
21505b02bb9SAlex Zinenko     return node;
21605b02bb9SAlex Zinenko   }
21705b02bb9SAlex Zinenko   if (knownFalsePreds.count(node->predicate) != 0) {
21805b02bb9SAlex Zinenko     node->kind = PredCombinerKind::False;
21905b02bb9SAlex Zinenko     node->children.clear();
22005b02bb9SAlex Zinenko     return node;
22105b02bb9SAlex Zinenko   }
22205b02bb9SAlex Zinenko 
22305b02bb9SAlex Zinenko   // If the current node is a substitution, stop recursion now.
22405b02bb9SAlex Zinenko   // The expressions in the leaves below this node were rewritten, but the nodes
22505b02bb9SAlex Zinenko   // still point to the original predicate records.  While the original
22605b02bb9SAlex Zinenko   // predicate may be known to be true or false, it is not necessarily the case
22705b02bb9SAlex Zinenko   // after rewriting.
2289db53a18SRiver Riddle   // TODO: we can support ground truth for rewritten
22905b02bb9SAlex Zinenko   // predicates by either (a) having our own unique'ing of the predicates
23005b02bb9SAlex Zinenko   // instead of relying on TableGen record pointers or (b) taking ground truth
2318bfedb3cSKazuaki Ishizaki   // values optionally prefixed with a list of substitutions to apply, e.g.
23205b02bb9SAlex Zinenko   // "predX is true by itself as well as predSubY leaf substitution had been
23305b02bb9SAlex Zinenko   // applied to it".
23405b02bb9SAlex Zinenko   if (node->kind == PredCombinerKind::SubstLeaves) {
23505b02bb9SAlex Zinenko     return node;
23605b02bb9SAlex Zinenko   }
23705b02bb9SAlex Zinenko 
238*d8399d5dSKrzysztof Drewniak   if (node->kind == PredCombinerKind::And && node->children.empty()) {
239*d8399d5dSKrzysztof Drewniak     node->kind = PredCombinerKind::True;
240*d8399d5dSKrzysztof Drewniak     return node;
241*d8399d5dSKrzysztof Drewniak   }
242*d8399d5dSKrzysztof Drewniak 
243*d8399d5dSKrzysztof Drewniak   if (node->kind == PredCombinerKind::Or && node->children.empty()) {
244*d8399d5dSKrzysztof Drewniak     node->kind = PredCombinerKind::False;
245*d8399d5dSKrzysztof Drewniak     return node;
246*d8399d5dSKrzysztof Drewniak   }
247*d8399d5dSKrzysztof Drewniak 
24805b02bb9SAlex Zinenko   // Otherwise, look at child nodes.
24905b02bb9SAlex Zinenko 
25005b02bb9SAlex Zinenko   // Move child nodes into some local variable so that they can be optimized
25105b02bb9SAlex Zinenko   // separately and re-added if necessary.
25205b02bb9SAlex Zinenko   llvm::SmallVector<PredNode *, 4> children;
25305b02bb9SAlex Zinenko   std::swap(node->children, children);
25405b02bb9SAlex Zinenko 
25505b02bb9SAlex Zinenko   for (auto &child : children) {
25605b02bb9SAlex Zinenko     // First, simplify the child.  This maintains the predicate as it was.
25702b6fb21SMehdi Amini     auto *simplifiedChild =
25805b02bb9SAlex Zinenko         propagateGroundTruth(child, knownTruePreds, knownFalsePreds);
25905b02bb9SAlex Zinenko 
26005b02bb9SAlex Zinenko     // Just add the child if we don't know how to simplify the current node.
26105b02bb9SAlex Zinenko     if (node->kind != PredCombinerKind::And &&
26205b02bb9SAlex Zinenko         node->kind != PredCombinerKind::Or) {
26305b02bb9SAlex Zinenko       node->children.push_back(simplifiedChild);
26405b02bb9SAlex Zinenko       continue;
26505b02bb9SAlex Zinenko     }
26605b02bb9SAlex Zinenko 
26705b02bb9SAlex Zinenko     // Second, based on the type define which known values of child predicates
26805b02bb9SAlex Zinenko     // immediately collapse this predicate to a known value, and which others
26905b02bb9SAlex Zinenko     // may be safely ignored.
27005b02bb9SAlex Zinenko     //   OR(..., True, ...) = True
27105b02bb9SAlex Zinenko     //   OR(..., False, ...) = OR(..., ...)
27205b02bb9SAlex Zinenko     //   AND(..., False, ...) = False
27305b02bb9SAlex Zinenko     //   AND(..., True, ...) = AND(..., ...)
27405b02bb9SAlex Zinenko     auto collapseKind = node->kind == PredCombinerKind::And
27505b02bb9SAlex Zinenko                             ? PredCombinerKind::False
27605b02bb9SAlex Zinenko                             : PredCombinerKind::True;
27705b02bb9SAlex Zinenko     auto eraseKind = node->kind == PredCombinerKind::And
27805b02bb9SAlex Zinenko                          ? PredCombinerKind::True
27905b02bb9SAlex Zinenko                          : PredCombinerKind::False;
28005b02bb9SAlex Zinenko     const auto &collapseList =
28105b02bb9SAlex Zinenko         node->kind == PredCombinerKind::And ? knownFalsePreds : knownTruePreds;
28205b02bb9SAlex Zinenko     const auto &eraseList =
28305b02bb9SAlex Zinenko         node->kind == PredCombinerKind::And ? knownTruePreds : knownFalsePreds;
28405b02bb9SAlex Zinenko     if (simplifiedChild->kind == collapseKind ||
28505b02bb9SAlex Zinenko         collapseList.count(simplifiedChild->predicate) != 0) {
28605b02bb9SAlex Zinenko       node->kind = collapseKind;
28705b02bb9SAlex Zinenko       node->children.clear();
28805b02bb9SAlex Zinenko       return node;
28902b6fb21SMehdi Amini     }
29002b6fb21SMehdi Amini     if (simplifiedChild->kind == eraseKind ||
29105b02bb9SAlex Zinenko         eraseList.count(simplifiedChild->predicate) != 0) {
29205b02bb9SAlex Zinenko       continue;
29305b02bb9SAlex Zinenko     }
29405b02bb9SAlex Zinenko     node->children.push_back(simplifiedChild);
29505b02bb9SAlex Zinenko   }
29605b02bb9SAlex Zinenko   return node;
29705b02bb9SAlex Zinenko }
29805b02bb9SAlex Zinenko 
29905b02bb9SAlex Zinenko // Combine a list of predicate expressions using a binary combiner.  If a list
30005b02bb9SAlex Zinenko // is empty, return "init".
30105b02bb9SAlex Zinenko static std::string combineBinary(ArrayRef<std::string> children,
3021fc096afSMehdi Amini                                  const std::string &combiner,
3031fc096afSMehdi Amini                                  std::string init) {
30405b02bb9SAlex Zinenko   if (children.empty())
30505b02bb9SAlex Zinenko     return init;
30605b02bb9SAlex Zinenko 
30705b02bb9SAlex Zinenko   auto size = children.size();
30805b02bb9SAlex Zinenko   if (size == 1)
30905b02bb9SAlex Zinenko     return children.front();
31005b02bb9SAlex Zinenko 
31105b02bb9SAlex Zinenko   std::string str;
31205b02bb9SAlex Zinenko   llvm::raw_string_ostream os(str);
31305b02bb9SAlex Zinenko   os << '(' << children.front() << ')';
31405b02bb9SAlex Zinenko   for (unsigned i = 1; i < size; ++i) {
31505b02bb9SAlex Zinenko     os << ' ' << combiner << " (" << children[i] << ')';
31605b02bb9SAlex Zinenko   }
317095b41c6SJOE1994   return str;
31805b02bb9SAlex Zinenko }
31905b02bb9SAlex Zinenko 
32005b02bb9SAlex Zinenko // Prepend negation to the only condition in the predicate expression list.
32105b02bb9SAlex Zinenko static std::string combineNot(ArrayRef<std::string> children) {
32205b02bb9SAlex Zinenko   assert(children.size() == 1 && "expected exactly one child predicate of Neg");
32305b02bb9SAlex Zinenko   return (Twine("!(") + children.front() + Twine(')')).str();
32405b02bb9SAlex Zinenko }
32505b02bb9SAlex Zinenko 
32605b02bb9SAlex Zinenko // Recursively traverse the predicate tree in depth-first post-order and build
32705b02bb9SAlex Zinenko // the final expression.
32805b02bb9SAlex Zinenko static std::string getCombinedCondition(const PredNode &root) {
32905b02bb9SAlex Zinenko   // Immediately return for non-combiner predicates that don't have children.
33005b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Leaf)
33105b02bb9SAlex Zinenko     return root.expr;
33205b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::True)
33305b02bb9SAlex Zinenko     return "true";
33405b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::False)
33505b02bb9SAlex Zinenko     return "false";
33605b02bb9SAlex Zinenko 
33705b02bb9SAlex Zinenko   // Recurse into children.
33805b02bb9SAlex Zinenko   llvm::SmallVector<std::string, 4> childExpressions;
33905b02bb9SAlex Zinenko   childExpressions.reserve(root.children.size());
34005b02bb9SAlex Zinenko   for (const auto &child : root.children)
34105b02bb9SAlex Zinenko     childExpressions.push_back(getCombinedCondition(*child));
34205b02bb9SAlex Zinenko 
34305b02bb9SAlex Zinenko   // Combine the expressions based on the predicate node kind.
34405b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::And)
34505b02bb9SAlex Zinenko     return combineBinary(childExpressions, "&&", "true");
34605b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Or)
34705b02bb9SAlex Zinenko     return combineBinary(childExpressions, "||", "false");
34805b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::Not)
34905b02bb9SAlex Zinenko     return combineNot(childExpressions);
350b5235d1aSLei Zhang   if (root.kind == PredCombinerKind::Concat) {
351b5235d1aSLei Zhang     assert(childExpressions.size() == 1 &&
352b5235d1aSLei Zhang            "ConcatPred should only have one child");
353b5235d1aSLei Zhang     return root.prefix + childExpressions.front() + root.suffix;
354b5235d1aSLei Zhang   }
35505b02bb9SAlex Zinenko 
35605b02bb9SAlex Zinenko   // Substitutions were applied before so just ignore them.
35705b02bb9SAlex Zinenko   if (root.kind == PredCombinerKind::SubstLeaves) {
35805b02bb9SAlex Zinenko     assert(childExpressions.size() == 1 &&
35905b02bb9SAlex Zinenko            "substitution predicate must have one child");
36005b02bb9SAlex Zinenko     return childExpressions[0];
36105b02bb9SAlex Zinenko   }
36205b02bb9SAlex Zinenko 
36305b02bb9SAlex Zinenko   llvm::PrintFatalError(root.predicate->getLoc(), "unsupported predicate kind");
36405b02bb9SAlex Zinenko }
36505b02bb9SAlex Zinenko 
36612d16de5SRahul Joshi std::string CombinedPred::getConditionImpl() const {
367659192b1SRahul Joshi   SpecificBumpPtrAllocator<PredNode> allocator;
36802b6fb21SMehdi Amini   auto *predicateTree = buildPredicateTree(*this, allocator, {});
36912d16de5SRahul Joshi   predicateTree =
37012d16de5SRahul Joshi       propagateGroundTruth(predicateTree,
37112d16de5SRahul Joshi                            /*knownTruePreds=*/llvm::SmallPtrSet<Pred *, 2>(),
37212d16de5SRahul Joshi                            /*knownFalsePreds=*/llvm::SmallPtrSet<Pred *, 2>());
37305b02bb9SAlex Zinenko 
37405b02bb9SAlex Zinenko   return getCombinedCondition(*predicateTree);
37505b02bb9SAlex Zinenko }
37605b02bb9SAlex Zinenko 
37712d16de5SRahul Joshi StringRef SubstLeavesPred::getPattern() const {
37805b02bb9SAlex Zinenko   return def->getValueAsString("pattern");
37905b02bb9SAlex Zinenko }
38005b02bb9SAlex Zinenko 
38112d16de5SRahul Joshi StringRef SubstLeavesPred::getReplacement() const {
38205b02bb9SAlex Zinenko   return def->getValueAsString("replacement");
38305b02bb9SAlex Zinenko }
384b5235d1aSLei Zhang 
38512d16de5SRahul Joshi StringRef ConcatPred::getPrefix() const {
386b5235d1aSLei Zhang   return def->getValueAsString("prefix");
387b5235d1aSLei Zhang }
388b5235d1aSLei Zhang 
38912d16de5SRahul Joshi StringRef ConcatPred::getSuffix() const {
390b5235d1aSLei Zhang   return def->getValueAsString("suffix");
391b5235d1aSLei Zhang }
392