17 #include "llvm/ADT/MapVector.h"
18 #include "llvm/ADT/TypeSwitch.h"
19 #include "llvm/Support/Debug.h"
22 #define DEBUG_TYPE "pdl-predicate-tree"
43 return llvm::count_if(values.
getTypes(),
44 [](
Type type) { return !isa<pdl::RangeType>(type); });
51 assert(isa<pdl::AttributeType>(val.
getType()) &&
"expected attribute type");
52 pdl::AttributeOp attr = cast<pdl::AttributeOp>(val.
getDefiningOp());
56 if (
Value type = attr.getValueType())
58 else if (
Attribute value = attr.getValueAttr())
68 bool isVariadic = isa<pdl::RangeType>(valueType);
72 .Case<pdl::OperandOp, pdl::OperandsOp>([&](
auto op) {
75 if (std::is_same<pdl::OperandOp, decltype(op)>::value ||
76 cast<OperandGroupPosition>(pos)->getOperandGroupNumber())
79 if (
Value type = op.getValueType())
83 .Case<pdl::ResultOp, pdl::ResultsOp>([&](
auto op) {
84 std::optional<unsigned> index = op.getIndex();
92 predList.emplace_back(parentPos, builder.
getIsNotNull());
97 if (std::is_same<pdl::ResultOp, decltype(op)>::value)
98 resultPos = builder.
getResult(parentPos, *index);
101 predList.emplace_back(resultPos, builder.
getEqualTo(pos));
113 std::optional<unsigned> ignoreOperand = std::nullopt) {
114 assert(isa<pdl::OperationType>(val.
getType()) &&
"expected operation");
115 pdl::OperationOp op = cast<pdl::OperationOp>(val.
getDefiningOp());
123 if (std::optional<StringRef> opName = op.getOpName())
130 if (minOperands != operands.size()) {
141 if (minResults == types.size())
147 for (
auto [attrName, attr] :
148 llvm::zip(op.getAttributeValueNames(), op.getAttributeValues())) {
150 predList, attr, builder, inputs,
160 if (operands.size() == 1 && isa<pdl::RangeType>(operands[0].
getType())) {
167 bool foundVariableLength =
false;
169 bool isVariadic = isa<pdl::RangeType>(operandIt.value().getType());
170 foundVariableLength |= isVariadic;
174 if (ignoreOperand && *ignoreOperand == operandIt.index())
180 : builder.
getOperand(opPos, operandIt.index());
185 if (types.size() == 1 && isa<pdl::RangeType>(types[0].
getType())) {
191 bool foundVariableLength =
false;
193 bool isVariadic = isa<pdl::RangeType>(typeValue.getType());
194 foundVariableLength |= isVariadic;
196 auto *resultPos = foundVariableLength
199 predList.emplace_back(resultPos, builder.
getIsNotNull());
211 if (
Attribute type = typeOp.getConstantTypeAttr())
213 }
else if (pdl::TypesOp typeOp = val.
getDefiningOp<pdl::TypesOp>()) {
214 if (
Attribute typeAttr = typeOp.getConstantTypesAttr())
225 auto it = inputs.try_emplace(val, pos);
229 if (isa<pdl::AttributeOp, pdl::OperandOp, pdl::OperandsOp, pdl::OperationOp,
231 auto minMaxPositions =
233 predList.emplace_back(minMaxPositions.second,
243 .Case<OperandPosition, OperandGroupPosition>([&](
auto *pos) {
246 .Default([](
auto *) { llvm_unreachable(
"unexpected position kind"); });
250 std::vector<PositionalPredicate> &predList,
257 assert(value &&
"expected non-tree `pdl.attribute` to contain a value");
262 std::vector<PositionalPredicate> &predList,
267 std::vector<Position *> allPositions;
268 allPositions.reserve(arguments.size());
269 for (
Value arg : arguments)
270 allPositions.push_back(inputs.lookup(arg));
273 Position *pos = *std::max_element(allPositions.begin(), allPositions.end(),
277 predList.emplace_back(pos, pred);
281 std::vector<PositionalPredicate> &predList,
289 auto *parentPos = cast<OperationPosition>(inputs.lookup(op.getParent()));
290 resultPos = builder.
getResult(parentPos, op.getIndex());
291 predList.emplace_back(resultPos, builder.
getIsNotNull());
295 std::vector<PositionalPredicate> &predList,
303 auto *parentPos = cast<OperationPosition>(inputs.lookup(op.getParent()));
304 bool isVariadic = isa<pdl::RangeType>(op.getType());
305 std::optional<unsigned> index = op.getIndex();
308 predList.emplace_back(resultPos, builder.
getIsNotNull());
315 Position *&typePos = inputs[typeValue];
320 "expected non-tree `pdl.type`/`pdl.types` to contain a value");
327 std::vector<PositionalPredicate> &predList,
330 for (
Operation &op : pattern.getBodyRegion().getOps()) {
332 .Case([&](pdl::AttributeOp attrOp) {
335 .Case<pdl::ApplyNativeConstraintOp>([&](
auto constraintOp) {
338 .Case<pdl::ResultOp, pdl::ResultsOp>([&](
auto resultOp) {
341 .Case([&](pdl::TypeOp typeOp) {
343 typeOp, [&] {
return typeOp.getConstantTypeAttr(); }, builder,
346 .Case([&](pdl::TypesOp typeOp) {
348 typeOp, [&] {
return typeOp.getConstantTypesAttr(); }, builder,
359 std::optional<unsigned> index;
374 for (
auto operationOp : pattern.getBodyRegion().getOps<pdl::OperationOp>()) {
375 for (
Value operand : operationOp.getOperandValues())
377 .Case<pdl::ResultOp, pdl::ResultsOp>(
378 [&used](
auto resultOp) { used.insert(resultOp.getParent()); });
383 if (
Value root = pattern.getRewriter().getRoot())
388 for (
Value operationOp : pattern.getBodyRegion().getOps<pdl::OperationOp>())
389 if (!used.contains(operationOp))
390 roots.push_back(operationOp);
403 ParentMaps &parentMaps) {
411 Entry(
Value value,
Value parent, std::optional<unsigned> index,
413 : value(value), parent(parent), index(index), depth(depth) {}
417 std::optional<unsigned> index;
429 llvm::MapVector<Value, SmallVector<RootDepth, 1>> connectorsRootsDepths;
432 for (
Value root : roots) {
436 std::queue<Entry> toVisit;
437 toVisit.emplace(root,
Value(), 0, 0);
442 while (!toVisit.empty()) {
443 Entry entry = toVisit.front();
446 if (!parentMap.insert({entry.value, {entry.parent, entry.index}}).second)
450 connectorsRootsDepths[entry.value].push_back({root, entry.depth});
456 .Case<pdl::OperationOp>([&](
auto operationOp) {
460 if (operands.size() == 1 &&
461 isa<pdl::RangeType>(operands[0].getType())) {
462 toVisit.emplace(operands[0], entry.value, std::nullopt,
470 toVisit.emplace(p.value(), entry.value, p.index(),
473 .Case<pdl::ResultOp, pdl::ResultsOp>([&](
auto resultOp) {
474 toVisit.emplace(resultOp.getParent(), entry.value,
475 resultOp.getIndex(), entry.depth);
483 for (
const auto &connectorRootsDepths : connectorsRootsDepths) {
484 Value value = connectorRootsDepths.first;
488 if (rootsDepths.size() == 1)
491 for (
const RootDepth &p : rootsDepths) {
492 for (
const RootDepth &q : rootsDepths) {
499 entry.
cost.second = nextID++;
500 entry.
cost.first = q.depth;
507 assert((llvm::hasSingleElement(roots) || graph.size() == roots.size()) &&
508 "the pattern contains a candidate root disconnected from the others");
515 assert(index < operands.size() &&
"operand index out of range");
516 for (
unsigned i = 0; i <= index; ++i)
517 if (isa<pdl::RangeType>(operands[i].getType()))
523 static void visitUpward(std::vector<PositionalPredicate> &predList,
527 Value value = opIndex.parent;
529 .Case<pdl::OperationOp>([&](
auto operationOp) {
530 LLVM_DEBUG(llvm::dbgs() <<
" * Value: " << value <<
"\n");
539 if (!opIndex.index) {
544 Type type = operationOp.getOperandValues()[*opIndex.index].getType();
545 bool variadic = isa<pdl::RangeType>(type);
549 operandPos = builder.
getOperand(opPos, *opIndex.index);
551 predList.emplace_back(operandPos, builder.
getEqualTo(pos));
557 bool inserted = valueToPosition.try_emplace(value, opPos).second;
559 assert(inserted &&
"duplicate upward visit");
568 .Case<pdl::ResultOp>([&](
auto resultOp) {
570 auto *opPos = dyn_cast<OperationPosition>(pos);
571 assert(opPos &&
"operations and results must be interleaved");
572 pos = builder.
getResult(opPos, *opIndex.index);
575 valueToPosition.try_emplace(value, pos);
577 .Case<pdl::ResultsOp>([&](
auto resultOp) {
579 auto *opPos = dyn_cast<OperationPosition>(pos);
580 assert(opPos &&
"operations and results must be interleaved");
581 bool isVariadic = isa<pdl::RangeType>(value.
getType());
588 valueToPosition.try_emplace(value, pos);
596 std::vector<PositionalPredicate> &predList,
602 ParentMaps parentMaps;
605 llvm::dbgs() <<
"Graph:\n";
606 for (
auto &target : graph) {
607 llvm::dbgs() <<
" * " << target.first.getLoc() <<
" " << target.first
609 for (
auto &source : target.second) {
611 llvm::dbgs() <<
" <- " << source.first <<
": " << entry.
cost.first
612 <<
":" << entry.
cost.second <<
" via "
620 Value bestRoot = pattern.getRewriter().getRoot();
623 unsigned bestCost = 0;
624 LLVM_DEBUG(llvm::dbgs() <<
"Candidate roots:\n");
625 for (
Value root : roots) {
627 unsigned cost = solver.
solve();
628 LLVM_DEBUG(llvm::dbgs() <<
" * " << root <<
": " << cost <<
"\n");
629 if (!bestRoot || bestCost > cost) {
643 llvm::dbgs() <<
"Best tree:\n";
644 for (
const std::pair<Value, Value> &edge : bestEdges) {
645 llvm::dbgs() <<
" * " << edge.first;
647 llvm::dbgs() <<
" <- " << edge.second;
648 llvm::dbgs() <<
"\n";
652 LLVM_DEBUG(llvm::dbgs() <<
"Calling key getTreePredicates:\n");
653 LLVM_DEBUG(llvm::dbgs() <<
" * Value: " << bestRoot <<
"\n");
664 Value target = it.value().first;
665 Value source = it.value().second;
671 if (valueToPosition.count(target))
675 Value connector = graph[target][source].connector;
676 assert(connector &&
"invalid edge");
677 LLVM_DEBUG(llvm::dbgs() <<
" * Connector: " << connector.
getLoc() <<
"\n");
679 Position *pos = valueToPosition.lookup(connector);
680 assert(pos &&
"connector has not been traversed yet");
683 for (
Value value = connector; value != target;) {
684 OpIndex opIndex = parentMap.lookup(value);
685 assert(opIndex.parent &&
"missing parent");
686 visitUpward(predList, opIndex, builder, valueToPosition, pos, it.index());
687 value = opIndex.parent;
705 struct OrderedPredicate {
706 OrderedPredicate(
const std::pair<Position *, Qualifier *> &ip)
707 : position(ip.first), question(ip.second) {}
709 : position(ip.position), question(ip.question) {}
720 unsigned primary = 0;
725 unsigned secondary = 0;
738 bool operator<(
const OrderedPredicate &rhs)
const {
745 auto *rhsPos = rhs.position;
746 return std::make_tuple(primary, secondary, rhsPos->getOperationDepth(),
747 rhsPos->getKind(), rhs.question->getKind(), rhs.id) >
748 std::make_tuple(rhs.primary, rhs.secondary,
756 struct OrderedPredicateDenseInfo {
759 static OrderedPredicate getEmptyKey() {
return Base::getEmptyKey(); }
760 static OrderedPredicate getTombstoneKey() {
return Base::getTombstoneKey(); }
761 static bool isEqual(
const OrderedPredicate &lhs,
762 const OrderedPredicate &rhs) {
763 return lhs.position == rhs.position && lhs.question == rhs.question;
765 static unsigned getHashValue(
const OrderedPredicate &p) {
766 return llvm::hash_combine(p.position, p.question);
772 struct OrderedPredicateList {
773 OrderedPredicateList(pdl::PatternOp pattern,
Value root)
774 : pattern(pattern), root(root) {}
776 pdl::PatternOp pattern;
786 return node->
getPosition() == predicate->position &&
793 OrderedPredicate *predicate,
794 pdl::PatternOp pattern) {
796 "expected matcher to equal the given predicate");
798 auto it = predicate->patternToAnswer.find(pattern);
799 assert(it != predicate->patternToAnswer.end() &&
800 "expected pattern to exist in predicate");
801 return node->
getChildren().insert({it->second,
nullptr}).first->second;
809 OrderedPredicateList &list,
810 std::vector<OrderedPredicate *>::iterator current,
811 std::vector<OrderedPredicate *>::iterator end) {
812 if (current == end) {
815 std::make_unique<SuccessNode>(list.pattern, list.root, std::move(node));
818 }
else if (!list.predicates.contains(*current)) {
825 node = std::make_unique<SwitchNode>((*current)->position,
826 (*current)->question);
829 list, std::next(current), end);
836 list, std::next(current), end);
851 if (
SwitchNode *switchNode = dyn_cast<SwitchNode>(&*node)) {
853 for (
auto &it : children)
858 if (children.size() == 1) {
859 auto childIt = children.begin();
860 node = std::make_unique<BoolNode>(
861 node->getPosition(), node->getQuestion(), childIt->first,
862 std::move(childIt->second), std::move(node->getFailureNode()));
864 }
else if (
BoolNode *boolNode = dyn_cast<BoolNode>(&*node)) {
874 root = &(*root)->getFailureNode();
875 *root = std::make_unique<ExitNode>();
880 std::unique_ptr<MatcherNode>
885 struct PatternPredicates {
886 PatternPredicates(pdl::PatternOp pattern,
Value root,
887 std::vector<PositionalPredicate> predicates)
888 : pattern(pattern), root(root), predicates(std::move(predicates)) {}
891 pdl::PatternOp pattern;
897 std::vector<PositionalPredicate> predicates;
901 for (pdl::PatternOp pattern : module.getOps<pdl::PatternOp>()) {
902 std::vector<PositionalPredicate> predicateList;
905 patternsAndPredicates.emplace_back(pattern, root, std::move(predicateList));
910 for (
auto &patternAndPredList : patternsAndPredicates) {
911 for (
auto &predicate : patternAndPredList.predicates) {
912 auto it = uniqued.insert(predicate);
913 it.first->patternToAnswer.try_emplace(patternAndPredList.pattern,
917 it.first->id = uniqued.size() - 1;
922 std::vector<OrderedPredicateList> lists;
923 lists.reserve(patternsAndPredicates.size());
924 for (
auto &patternAndPredList : patternsAndPredicates) {
925 OrderedPredicateList list(patternAndPredList.pattern,
926 patternAndPredList.root);
927 for (
auto &predicate : patternAndPredList.predicates) {
928 OrderedPredicate *orderedPredicate = &*uniqued.find(predicate);
929 list.predicates.insert(orderedPredicate);
932 ++orderedPredicate->primary;
934 lists.push_back(std::move(list));
940 for (
auto &list : lists) {
942 for (
auto *predicate : list.predicates)
943 total += predicate->primary * predicate->primary;
944 for (
auto *predicate : list.predicates)
945 predicate->secondary += total;
950 std::vector<OrderedPredicate *> ordered;
951 ordered.reserve(uniqued.size());
952 for (
auto &ip : uniqued)
953 ordered.push_back(&ip);
954 llvm::sort(ordered, [](OrderedPredicate *lhs, OrderedPredicate *rhs) {
959 std::unique_ptr<MatcherNode> root;
960 for (OrderedPredicateList &list : lists)
974 std::unique_ptr<MatcherNode> failureNode)
975 : position(p), question(q), failureNode(std::move(failureNode)),
976 matcherTypeID(matcherTypeID) {}
983 std::unique_ptr<MatcherNode> successNode,
984 std::unique_ptr<MatcherNode> failureNode)
986 std::move(failureNode)),
987 answer(answer), successNode(std::move(successNode)) {}
994 std::unique_ptr<MatcherNode> failureNode)
996 nullptr, std::move(failureNode)),
997 pattern(pattern), root(root) {}
static Value buildPredicateList(pdl::PatternOp pattern, PredicateBuilder &builder, std::vector< PositionalPredicate > &predList, DenseMap< Value, Position * > &valueToPosition)
Given a pattern operation, build the set of matcher predicates necessary to match this pattern.
static void getConstraintPredicates(pdl::ApplyNativeConstraintOp op, std::vector< PositionalPredicate > &predList, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs)
static void getTypePredicates(Value typeValue, function_ref< Attribute()> typeAttrFn, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs)
static void getNonTreePredicates(pdl::PatternOp pattern, std::vector< PositionalPredicate > &predList, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs)
Collect all of the predicates that cannot be determined via walking the tree.
static bool useOperandGroup(pdl::OperationOp op, unsigned index)
Returns true if the operand at the given index needs to be queried using an operand group,...
static void getTreePredicates(std::vector< PositionalPredicate > &predList, Value val, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs, Position *pos)
Collect the tree predicates anchored at the given value.
static void getResultPredicates(pdl::ResultOp op, std::vector< PositionalPredicate > &predList, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs)
static void getOperandTreePredicates(std::vector< PositionalPredicate > &predList, Value val, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs, Position *pos)
Collect all of the predicates for the given operand position.
std::unique_ptr< MatcherNode > & getOrCreateChild(SwitchNode *node, OrderedPredicate *predicate, pdl::PatternOp pattern)
Get or insert a child matcher for the given parent switch node, given a predicate and parent pattern.
static bool comparePosDepth(Position *lhs, Position *rhs)
Compares the depths of two positions.
static void visitUpward(std::vector< PositionalPredicate > &predList, OpIndex opIndex, PredicateBuilder &builder, DenseMap< Value, Position * > &valueToPosition, Position *&pos, unsigned rootID)
Visit a node during upward traversal.
static unsigned getNumNonRangeValues(ValueRange values)
Returns the number of non-range elements within values.
static SmallVector< Value > detectRoots(pdl::PatternOp pattern)
Given a pattern, determines the set of roots present in this pattern.
static void insertExitNode(std::unique_ptr< MatcherNode > *root)
Insert an exit node at the end of the failure path of the root.
static bool isSamePredicate(MatcherNode *node, OrderedPredicate *predicate)
Returns true if the given matcher refers to the same predicate as the given ordered predicate.
static void foldSwitchToBool(std::unique_ptr< MatcherNode > &node)
Fold any switch nodes nested under node to boolean nodes when possible.
static void buildCostGraph(ArrayRef< Value > roots, RootOrderingGraph &graph, ParentMaps &parentMaps)
Given a list of candidate roots, builds the cost graph for connecting them.
static void getAttributePredicates(pdl::AttributeOp op, std::vector< PositionalPredicate > &predList, PredicateBuilder &builder, DenseMap< Value, Position * > &inputs)
static void propagatePattern(std::unique_ptr< MatcherNode > &node, OrderedPredicateList &list, std::vector< OrderedPredicate * >::iterator current, std::vector< OrderedPredicate * >::iterator end)
Build the matcher CFG by "pushing" patterns through by sorted predicate order.
Attributes are known-constant values of operations.
This class implements the operand iterators for the Operation class.
type_range getType() const
Operation is the basic unit of execution within MLIR.
OperationName getName()
The name of an operation is the key identifier for it.
This class provides an efficient unique identifier for a specific C++ type.
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
This class provides an abstraction over the different types of ranges over Values.
type_range getTypes() const
This class represents an instance of an SSA value in the MLIR system, representing a computable value...
Type getType() const
Return the type of this value.
Location getLoc() const
Return the location of this value.
Operation * getDefiningOp() const
If this value is the result of an operation, return the operation that defines it.
This class represents the base of a predicate matcher node.
Position * getPosition() const
Returns the position on which the question predicate should be checked.
Qualifier * getQuestion() const
Returns the predicate checked on this node.
The optimal branching algorithm solver.
unsigned solve()
Runs the Edmonds' algorithm for the current graph, returning the total cost of the minimum-weight spa...
std::vector< std::pair< Value, Value > > EdgeList
A list of edges (child, parent).
EdgeList preOrderTraversal(ArrayRef< Value > nodes) const
Returns the computed edges as visited in the preorder traversal.
A position describes a value on the input IR on which a predicate may be applied, such as an operatio...
unsigned getOperationDepth() const
Returns the depth of the first ancestor operation position.
Predicates::Kind getKind() const
Returns the kind of this position.
const KeyTy & getValue() const
Return the key value of this predicate.
This class provides utilities for constructing predicates.
Position * getTypeLiteral(Attribute attr)
Returns a type position for the given type value.
Predicate getOperandCount(unsigned count)
Create a predicate comparing the number of operands of an operation to a known value.
OperationPosition * getPassthroughOp(Position *p)
Returns the operation position equivalent to the given position.
Predicate getIsNotNull()
Create a predicate comparing a value with null.
Predicate getOperandCountAtLeast(unsigned count)
Predicate getResultCountAtLeast(unsigned count)
Position * getType(Position *p)
Returns a type position for the given entity.
Position * getAttribute(OperationPosition *p, StringRef name)
Returns an attribute position for an attribute of the given operation.
Position * getOperandGroup(OperationPosition *p, std::optional< unsigned > group, bool isVariadic)
Returns a position for a group of operands of the given operation.
Position * getForEach(Position *p, unsigned id)
Position * getOperand(OperationPosition *p, unsigned operand)
Returns an operand position for an operand of the given operation.
Position * getResult(OperationPosition *p, unsigned result)
Returns a result position for a result of the given operation.
Position * getRoot()
Returns the root operation position.
Predicate getAttributeConstraint(Attribute attr)
Create a predicate comparing an attribute to a known value.
Position * getResultGroup(OperationPosition *p, std::optional< unsigned > group, bool isVariadic)
Returns a position for a group of results of the given operation.
Position * getAllResults(OperationPosition *p)
UsersPosition * getUsers(Position *p, bool useRepresentative)
Returns the users of a position using the value at the given operand.
Predicate getTypeConstraint(Attribute type)
Create a predicate comparing the type of an attribute or value to a known type.
OperationPosition * getOperandDefiningOp(Position *p)
Returns the parent position defining the value held by the given operand.
Predicate getResultCount(unsigned count)
Create a predicate comparing the number of results of an operation to a known value.
std::pair< Qualifier *, Qualifier * > Predicate
An ordinal predicate consists of a "Question" and a set of acceptable "Answers" (later converted to o...
Predicate getEqualTo(Position *pos)
Create a predicate checking if two values are equal.
Position * getAllOperands(OperationPosition *p)
Position * getAttributeLiteral(Attribute attr)
Returns an attribute position for the given attribute.
Predicate getOperationName(StringRef name)
Create a predicate comparing the name of an operation to a known value.
Predicate getConstraint(StringRef name, ArrayRef< Position * > pos, bool isNegated)
Create a predicate that applies a generic constraint.
An ordinal predicate consists of a "Question" and a set of acceptable "Answers" (later converted to o...
Predicates::Kind getKind() const
Returns the kind of this qualifier.
constexpr void enumerate(std::tuple< Tys... > &tuple, CallbackT &&callback)
bool operator<(const Fraction &x, const Fraction &y)
Include the generated interface declarations.
auto get(MLIRContext *context, Ts &&...params)
Helper method that injects context only if needed, this helps unify some of the attribute constructio...
A position describing an attribute of an operation.
A BoolNode denotes a question with a boolean-like result.
BoolNode(Position *position, Qualifier *question, Qualifier *answer, std::unique_ptr< MatcherNode > successNode, std::unique_ptr< MatcherNode > failureNode=nullptr)
An operation position describes an operation node in the IR.
bool isRoot() const
Returns if this operation position corresponds to the root.
bool isOperandDefiningOp() const
Returns if this operation represents an operand defining op.
A PositionalPredicate is a predicate that is associated with a specific positional value.
The information associated with an edge in the cost graph.
Value connector
The connector value in the intersection of the two subtrees rooted at the source and target root that...
std::pair< unsigned, unsigned > cost
The depth of the connector Value w.r.t.
A SuccessNode denotes that a given high level pattern has successfully been matched.
SuccessNode(pdl::PatternOp pattern, Value root, std::unique_ptr< MatcherNode > failureNode)
A SwitchNode denotes a question with multiple potential results.
llvm::MapVector< Qualifier *, std::unique_ptr< MatcherNode > > ChildMapT
Returns the children of this switch node.
ChildMapT & getChildren()
SwitchNode(Position *position, Qualifier *question)
A position describing the result type of an entity, i.e.