summaryrefslogtreecommitdiff
path: root/mlir/lib/Conversion/PDLToPDLInterp/PredicateTree.cpp
AgeCommit message (Collapse)Author
2025-10-06[mlir] Simplify unreachable type switch cases. NFC. (#162032)Jakub Kuderski
Use `DefaultUnreachable` from https://github.com/llvm/llvm-project/pull/161970.
2025-08-27[MLIR] Apply clang-tidy fixes for misc-use-internal-linkage in ↵Mehdi Amini
PredicateTree.cpp (NFC)
2025-08-23[MLIR] Adopt LDBG() macro in PDLToPDLInterp/PredicateTree.cpp (NFC)Mehdi Amini
2025-07-25[mlir][NFC] Use `getDefiningOp<OpTy>()` instead of ↵Longsheng Mou
`dyn_cast<OpTy>(getDefiningOp())` (#150428) This PR uses `val.getDefiningOp<OpTy>()` to replace `dyn_cast<OpTy>(val.getDefiningOp())` , `dyn_cast_or_null<OpTy>(val.getDefiningOp())` and `dyn_cast_if_present<OpTy>(val.getDefiningOp())`.
2025-07-04[mlir] Remove unused includes (NFC) (#147101)Kazu Hirata
These are identified by misc-include-cleaner. I've filtered out those that break builds. Also, I'm staying away from llvm-config.h, config.h, and Compiler.h, which likely cause platform- or compiler-specific build failures.
2025-06-14[mlir] Compare std::optional<T> to values directly (NFC) (#144241)Kazu Hirata
This patch transforms: X && *X == Y to: X == Y where X is of std::optional<T>, and Y is of T or similar.
2024-11-04[mlir] Simplify code with MapVector::operator[] (NFC) (#113407)Kazu Hirata
2024-03-10Add llvm::min/max_element and use it in llvm/ and mlir/ directories. (#84678)Justin Lebar
For some reason this was missing from STLExtras.
2024-03-02Reapply "[mlir][PDL] Add support for native constraints with results (#82760)"Matthias Gehre
with a small stack-use-after-scope fix in getConstraintPredicates() This reverts commit c80e6edba4a9593f0587e27fa0ac825ebe174afd.
2024-03-01Revert "[mlir][PDL] Add support for native constraints with results (#82760)"Matthias Gehre
Due to buildbot failure https://lab.llvm.org/buildbot/#/builders/88/builds/72130 This reverts commit dca32a3b594b3c91f9766a9312b5d82534910fa1.
2024-03-01[mlir][PDL] Add support for native constraints with results (#82760)Matthias Gehre
From https://reviews.llvm.org/D153245 This adds support for native PDL (and PDLL) C++ constraints to return results. This is useful for situations where a pattern checks for certain constraints of multiple interdependent attributes and computes a new attribute value based on them. Currently, for such an example it is required to escape to C++ during matching to perform the check and after a successful match again escape to native C++ to perform the computation during the rewriting part of the pattern. With this work we can do the computation in C++ during matching and use the result in the rewriting part of the pattern. Effectively this enables a choice in the trade-off of memory consumption during matching vs recomputation of values. This is an example of a situation where this is useful: We have two operations with certain attributes that have interdependent constraints. For instance `attr_foo: one_of [0, 2, 4, 8], attr_bar: one_of [0, 2, 4, 8]` and `attr_foo == attr_bar`. The pattern should only match if all conditions are true. The new operation should be created with a new attribute which is computed from the two matched attributes e.g. `attr_baz = attr_foo * attr_bar`. For the check we already escape to native C++ and have all values at hand so it makes sense to directly compute the new attribute value as well: ``` Constraint checkAndCompute(attr0: Attr, attr1: Attr) -> Attr; Pattern example with benefit(1) { let foo = op<test.foo>() {attr = attr_foo : Attr}; let bar = op<test.bar>(foo) {attr = attr_bar : Attr}; let attr_baz = checkAndCompute(attr_foo, attr_bar); rewrite bar with { let baz = op<test.baz> {attr=attr_baz}; replace bar with baz; }; } ``` To achieve this the following notable changes were necessary: PDLL: - Remove check in PDLL parser that prevented native constraints from returning results PDL: - Change PDL definition of pdl.apply_native_constraint to allow variadic results PDL_interp: - Change PDL_interp definition of pdl_interp.apply_constraint to allow variadic results PDLToPDLInterp Pass: The input to the pass is an arbitrary number of PDL patterns. The pass collects the predicates that are required to match all of the pdl patterns and establishes an ordering that allows creation of a single efficient matcher function to match all of them. Values that are matched and possibly used in the rewriting part of a pattern are represented as positions. This allows fusion and thus reusing a single position for multiple matching patterns. Accordingly, we introduce ConstraintPosition, which records the type and index of the result of the constraint. The problem is for the corresponding value to be used in the rewriting part of a pattern it has to be an input to the pdl_interp.record_match operation, which is generated early during the pass such that its surrounding block can be referred to by branching operations. In consequence the value has to be materialized after the original pdl.apply_native_constraint has been deleted but before we get the chance to generate the corresponding pdl_interp.apply_constraint operation. We solve this by emitting a placeholder value when a ConstraintPosition is evaluated. These placeholder values (due to fusion there may be multiple for one constraint result) are replaced later when the actual pdl_interp.apply_constraint operation is created. Changes since the phabricator review: - Addressed all comments - In particular, removed registerConstraintFunctionWithResults and instead changed registerConstraintFunction so that contraint functions always have results (empty by default) - Thus we don't need to reuse `rewriteFunctions` to store constraint functions with results anymore, and can instead use `constraintFunctions` - Perform a stable sort of ConstraintQuestion, so that ConstraintQuestion appear before other ConstraintQuestion that use their results. - Don't create placeholders for pdl_interp::ApplyConstraintOp. Instead generate the `pdl_interp::ApplyConstraintOp` before generating the successor block. - Fixed a test failure in the pdl python bindings Original code by @martin-luecke Co-authored-by: martin-luecke <martinpaul.luecke@amd.com>
2023-12-07Apply clang-tidy fixes for llvm-qualified-auto in PredicateTree.cpp (NFC)Mehdi Amini
2023-08-24[MLIR][PDL] Add support for representing and lowering negated constraintsMogball
This commit enables modelling negation of native constraints. This is accomplished through an attribute `isNegated` on the operations `pdl.apply_native_constraint` and `pdl_interp.apply_constraint` and according adjustments to the conversion in the ConvertPDLToPDLInterpPass. Reviewed By: Mogball Differential Revision: https://reviews.llvm.org/D153871
2023-05-12[mlir] Move casting calls from methods to function callsTres Popp
The MLIR classes Type/Attribute/Operation/Op/Value support cast/dyn_cast/isa/dyn_cast_or_null functionality through llvm's doCast functionality in addition to defining methods with the same name. This change begins the migration of uses of the method to the corresponding function call as has been decided as more consistent. Note that there still exist classes that only define methods directly, such as AffineExpr, and this does not include work currently to support a functional cast/isa call. Caveats include: - This clang-tidy script probably has more problems. - This only touches C++ code, so nothing that is being generated. Context: - https://mlir.llvm.org/deprecation/ at "Use the free function variants for dyn_cast/cast/isa/…" - Original discussion at https://discourse.llvm.org/t/preferred-casting-style-going-forward/68443 Implementation: This first patch was created with the following steps. The intention is to only do automated changes at first, so I waste less time if it's reverted, and so the first mass change is more clear as an example to other teams that will need to follow similar steps. Steps are described per line, as comments are removed by git: 0. Retrieve the change from the following to build clang-tidy with an additional check: https://github.com/llvm/llvm-project/compare/main...tpopp:llvm-project:tidy-cast-check 1. Build clang-tidy 2. Run clang-tidy over your entire codebase while disabling all checks and enabling the one relevant one. Run on all header files also. 3. Delete .inc files that were also modified, so the next build rebuilds them to a pure state. 4. Some changes have been deleted for the following reasons: - Some files had a variable also named cast - Some files had not included a header file that defines the cast functions - Some files are definitions of the classes that have the casting methods, so the code still refers to the method instead of the function without adding a prefix or removing the method declaration at the same time. ``` ninja -C $BUILD_DIR clang-tidy run-clang-tidy -clang-tidy-binary=$BUILD_DIR/bin/clang-tidy -checks='-*,misc-cast-functions'\ -header-filter=mlir/ mlir/* -fix rm -rf $BUILD_DIR/tools/mlir/**/*.inc git restore mlir/lib/IR mlir/lib/Dialect/DLTI/DLTI.cpp\ mlir/lib/Dialect/Complex/IR/ComplexDialect.cpp\ mlir/lib/**/IR/\ mlir/lib/Dialect/SparseTensor/Transforms/SparseVectorization.cpp\ mlir/lib/Dialect/Vector/Transforms/LowerVectorMultiReduction.cpp\ mlir/test/lib/Dialect/Test/TestTypes.cpp\ mlir/test/lib/Dialect/Transform/TestTransformDialectExtension.cpp\ mlir/test/lib/Dialect/Test/TestAttributes.cpp\ mlir/unittests/TableGen/EnumsGenTest.cpp\ mlir/test/python/lib/PythonTestCAPI.cpp\ mlir/include/mlir/IR/ ``` Differential Revision: https://reviews.llvm.org/D150123
2023-03-15[ADT][mlir][NFCI] Do not use non-const lvalue-refs with enumerateJakub Kuderski
Replace references to enumerate results with either result_pairs (reference wrapper type) or structured bindings. I did not use structured bindings everywhere as it wasn't clear to me it would improve readability. This is in preparation to the switch to zip semantics which won't support non-const lvalue reference to elements: https://reviews.llvm.org/D144503. I chose to use values instead of const lvalue-refs because MLIR is biased towards avoiding `const` local variables. This won't degrade performance because currently `result_pair` is cheap to copy (size_t + iterator), and in the future, the enumerator iterator dereference will return temporaries anyway. Reviewed By: dblaikie Differential Revision: https://reviews.llvm.org/D146006
2023-03-14[mlir] Use Use *{Set,Map}::contains (NFC)Kazu Hirata
2022-12-17mlir/tblgen: use std::optional in generationRamkumar Ramachandra
This is part of an effort to migrate from llvm::Optional to std::optional. This patch changes the way mlir-tblgen generates .inc files, and modifies tests and documentation appropriately. It is a "no compromises" patch, and doesn't leave the user with an unpleasant mix of llvm::Optional and std::optional. A non-trivial change has been made to ControlFlowInterfaces to split one constructor into two, relating to a build failure on Windows. See also: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716 Signed-off-by: Ramkumar Ramachandra <r@artagnon.com> Differential Revision: https://reviews.llvm.org/D138934
2022-12-03[mlir] Use std::nullopt instead of None (NFC)Kazu Hirata
This patch mechanically replaces None with std::nullopt where the compiler would warn if None were deprecated. The intent is to reduce the amount of manual work required in migrating from Optional to std::optional. This is part of an effort to migrate from llvm::Optional to std::optional: https://discourse.llvm.org/t/deprecating-llvm-optional-x-hasvalue-getvalue-getvalueor/63716
2022-09-30[mlir:PDL][NFC] Update PDL API to use prefixed accessorsRiver Riddle
This doesn't flip the switch for prefix generation yet, that'll be done in a followup.
2022-09-21[mlir] Flip PDL to use Both accessorsRiver Riddle
This allows for incrementally updating the old API usages without needing to update everything at once. PDL will be left on Both for a little bit and then flipped to prefixed when all APIs have been updated. Differential Revision: https://reviews.llvm.org/D134387
2022-03-19[mlir:PDL] Remove the ConstantParams support from native Constraints/RewritesRiver Riddle
This support has never really worked well, and is incredibly clunky to use (it effectively creates two argument APIs), and clunky to generate (it isn't clear how we should actually expose this from PDL frontends). Treating these as just attribute arguments is much much cleaner in every aspect of the stack. If we need to optimize lots of constant parameters, it would be better to investigate internal representation optimizations (e.g. batch attribute creation), that do not affect the user (we want a clean external API). Differential Revision: https://reviews.llvm.org/D121569
2022-01-07[mlir] Use const reference for loop iteration variable.Adrian Kuegel
2022-01-04[MLIR][PDL] Make predicate order deterministic.Stanislav Funiak
The tree merging of pattern predicates places the predicates in an unordered set. When the predicates are sorted, they are taken in the set order, not the insertion order. This results in nondeterministic behavior. One solution to this problem would be to use `SetVector`. However, the value `SetVector` does not provide a `find` function for fast O(1) lookups and stores the predicates twice -- once in the set and once in the vector, which is undesirable, because we store patternToAnswer in each predicate. A simpler solution is to store the tie breaking ID (which follows the insertion order), and use this ID to break any ties when comparing predicates. Reviewed By: Mogball Differential Revision: https://reviews.llvm.org/D116081
2022-01-04[MLIR][PDL] Refactor the positions for multi-root patterns.Stanislav Funiak
When the original version of multi-root patterns was reviewed, several improvements were made to the pdl_interp operations during the review process. Specifically, the "get users of a value at the specified operand index" was split up into "get users" and "compare the users' operands with that value". The iterative execution was also cleaned up to `pdl_interp.foreach`. However, the positions in the pdl-to-pdl_interp lowering were not similarly refactored. This introduced several problems, including hard-to-detect bugs in the lowering and duplicate evaluation of `pdl_interp.get_users`. This diff cleans up the positions. The "upward" `OperationPosition` was split-out into `UsersPosition` and `ForEachPosition`, and the operand comparison was replaced with a simple predicate. In the process, I fixed three bugs: 1. When multiple roots were had the same connector (i.e., a node that they shared with a subtree at the previously visited root), we would generate a single foreach loop rather than one foreach loop for each such root. The reason for this is that such connectors shared the position. The solution for this is to add root index as an id to the newly introduced `ForEachPosition`. 2. Previously, we would use `pdl_interp.get_operands` indiscriminately, whether or not the operand was variadic. We now correctly detect variadic operands and insert `pdl_interp.get_operand` when needed. 3. In certain corner cases, we would trigger the "connector has not been traversed yet" assertion. This was caused by not inserting the values during the upward traversal correctly. This has now been fixed. Reviewed By: Mogball Differential Revision: https://reviews.llvm.org/D116080
2022-01-02Apply clang-tidy fixes for performance-move-const-arg to MLIR (NFC)Mehdi Amini
2022-01-02Apply clang-tidy fixes for performance-for-range-copy to MLIR (NFC)Mehdi Amini
2021-12-22[MLIR][PDL] Clear up the terminology in the root ordering graph.Stanislav Funiak
Previously, we defined a struct named `RootOrderingCost`, which stored the cost (a pair consisting of the depth of the connector and a tie breaking ID), as well as the connector itself. This created some confusion, because we would sometimes write, e.g., `cost.cost.first` (the first `cost` referring to the struct, the second one referring to the `cost` field, and `first` referring to the depth). In order to address this confusion, here we rename `RootOrderingCost` to `RootOrderingEntry` (keeping the fields and their names as-is). This clarification exposed non-determinism in the optimal branching algorithm. When choosing the best local parent, we were previuosly only considering its depth (`cost.first`) and not the tie-breaking ID (`cost.second`). This led to non-deterministic choice of the parent when multiple potential parents had the same depth. The solution is to compare both the depth and the tie-breaking ID. Testing: Rely on existing unit tests. Non-detgerminism is hard to unit-test. Reviewed By: rriddle, Mogball Differential Revision: https://reviews.llvm.org/D116079
2021-12-10[mlir:PDL] Allow non-bound pdl.attribute/pdl.type operations that create ↵River Riddle
constants This allows for passing in these attributes/types to constraints/rewrites as arguments. Differential Revision: https://reviews.llvm.org/D114817
2021-12-08Adjust "end namespace" comment in MLIR to match new agree'd coding styleMehdi Amini
See D115115 and this mailing list discussion: https://lists.llvm.org/pipermail/llvm-dev/2021-December/154199.html Differential Revision: https://reviews.llvm.org/D115309
2021-11-26[PDL] fix unused variable warning in Release buildsBenjamin Kramer
2021-11-26Multi-root PDL matching using upward traversals.Stanislav Funiak
This is commit 4 of 4 for the multi-root matching in PDL, discussed in https://llvm.discourse.group/t/rfc-multi-root-pdl-patterns-for-kernel-matching/4148 (topic flagged for review). This PR integrates the various components (root ordering algorithm, nondeterministic execution of PDL bytecode) to implement multi-root PDL matching. The main idea is for the pattern to specify mulitple candidate roots. The PDL-to-PDLInterp lowering selects one of these roots and "hangs" the pattern from this root, traversing the edges downwards (from operation to its operands) when possible and upwards (from values to its uses) when needed. The root is selected by invoking the optimal matching multiple times, once for each candidate root, and the connectors are determined form the optimal matching. The costs in the directed graph are equal to the number of upward edges that need to be traversed when connecting the given two candidate roots. It can be shown that, for this choice of the cost function, "hanging" the pattern an inner node is no better than from the optimal root. The following three main additions were implemented as a part of this PR: 1. OperationPos predicate has been extended to allow tracing the operation accepting a value (the opposite of operation defining a value). 2. Predicate checking if two values are not equal - this is useful to ensure that we do not traverse the edge back downwards after we traversed it upwards. 3. Function for for building the cost graph among the candidate roots. 4. Updated buildPredicateList, building the predicates optimal branching has been determined. Testing: unit tests (an integration test to follow once the stack of commits has landed) Reviewed By: rriddle Differential Revision: https://reviews.llvm.org/D108550
2021-03-16[mlir][pdl] Cast the OperationPosition to Position to fix MSVC miscompileRiver Riddle
If we don't cast, MSVC picks an overload that hasn't been defined yet(not sure why) and miscompiles.
2021-03-16[mlir][PDL] Add support for variadic operands and results in the PDL InterpreterRiver Riddle
This revision extends the PDL Interpreter dialect to add support for variadic operands and results, with ranges of these values represented via the recently added !pdl.range type. To support this extension, three new operations have been added that closely match the single variant: * pdl_interp.check_types : Compare a range of types with a known range. * pdl_interp.create_types : Create a constant range of types. * pdl_interp.get_operands : Get a range of operands from an operation. * pdl_interp.get_results : Get a range of results from an operation. * pdl_interp.switch_types : Switch on a range of types. This revision handles adding support in the interpreter dialect and the conversion from PDL to PDLInterp. Support for variadic operands and results in the bytecode will be added in a followup revision. Differential Revision: https://reviews.llvm.org/D95722
2021-03-16[mlir][pdl] Remove CreateNativeOp in favor of a more general ↵River Riddle
ApplyNativeRewriteOp. This has a numerous amount of benefits, given the overly clunky nature of CreateNativeOp: * Users can now call into arbitrary rewrite functions from inside of PDL, allowing for more natural interleaving of PDL/C++ and enabling for more of the pattern to be in PDL. * Removes the need for an additional set of C++ functions/registry/etc. The new ApplyNativeRewriteOp will use the same PDLRewriteFunction as the existing RewriteOp. This reduces the API surface area exposed to users. This revision also introduces a new PDLResultList class. This class is used to provide results of native rewrite functions back to PDL. We introduce a new class instead of using a SmallVector to simplify the work necessary for variadics, given that ranges will require some changes to the structure of PDLValue. Differential Revision: https://reviews.llvm.org/D95720
2021-03-16[mlir][pdl] Restructure how results are represented.River Riddle
Up until now, results have been represented as additional results to a pdl.operation. This is fairly clunky, as it mismatches the representation of the rest of the IR constructs(e.g. pdl.operand) and also isn't a viable representation for operations returned by pdl.create_native. This representation also creates much more difficult problems when factoring in support for variadic result groups, optional results, etc. To resolve some of these problems, and simplify adding support for variable length results, this revision extracts the representation for results out of pdl.operation in the form of a new `pdl.result` operation. This operation returns the result of an operation at a given index, e.g.: ``` %root = pdl.operation ... %result = pdl.result 0 of %root ``` Differential Revision: https://reviews.llvm.org/D95719
2021-03-03[mlir][pdl][NFC] Rename InputOp to OperandOpRiver Riddle
This better matches the actual IR concept that is being modeled, and is consistent with how the rest of PDL is structured. Differential Revision: https://reviews.llvm.org/D95718
2021-02-22[mlir][pdl] Fix bug when ordering predicatesRiver Riddle
We should be ordering predicates with higher primary/secondary sums first, but we are currently ordering them last. This allows for predicates more frequently encountered to be checked first. Differential Revision: https://reviews.llvm.org/D95715
2020-11-19[mlir][BuiltinDialect] Resolve comments from D91571River Riddle
* Move ops to a BuiltinOps.h * Add file comments
2020-11-17[mlir][NFC] Remove references to Module.h and Function.hRiver Riddle
These includes have been deprecated in favor of BuiltinDialect.h, which contains the definitions of ModuleOp and FuncOp. Differential Revision: https://reviews.llvm.org/D91572
2020-10-26[mlir] Add a conversion pass between PDL and the PDL Interpreter DialectRiver Riddle
The conversion between PDL and the interpreter is split into several different parts. ** The Matcher: The matching section of all incoming pdl.pattern operations is converted into a predicate tree and merged. Each pattern is first converted into an ordered list of predicates starting from the root operation. A predicate is composed of three distinct parts: * Position - A position refers to a specific location on the input DAG, i.e. an existing MLIR entity being matched. These can be attributes, operands, operations, results, and types. Each position also defines a relation to its parent. For example, the operand `[0] -> 1` has a parent operation position `[0]` (the root). * Question - A question refers to a query on a specific positional value. For example, an operation name question checks the name of an operation position. * Answer - An answer is the expected result of a question. For example, when matching an operation with the name "foo.op". The question would be an operation name question, with an expected answer of "foo.op". After the predicate lists have been created and ordered(based on occurrence of common predicates and other factors), they are formed into a tree of nodes that represent the branching flow of a pattern match. This structure allows for efficient construction and merging of the input patterns. There are currently only 4 simple nodes in the tree: * ExitNode: Represents the termination of a match * SuccessNode: Represents a successful match of a specific pattern * BoolNode/SwitchNode: Branch to a specific child node based on the expected answer to a predicate question. Once the matcher tree has been generated, this tree is walked to generate the corresponding interpreter operations. ** The Rewriter: The rewriter portion of a pattern is generated in a very straightforward manor, similarly to lowerings in other dialects. Each PDL operation that may exist within a rewrite has a mapping into the interpreter dialect. The code for the rewriter is generated within a FuncOp, that is invoked by the interpreter on a successful pattern match. Referenced values defined in the matcher become inputs the generated rewriter function. An example lowering is shown below: ```mlir // The following high level PDL pattern: pdl.pattern : benefit(1) { %resultType = pdl.type %inputOperand = pdl.input %root, %results = pdl.operation "foo.op"(%inputOperand) -> %resultType pdl.rewrite %root { pdl.replace %root with (%inputOperand) } } // is lowered to the following: module { // The matcher function takes the root operation as an input. func @matcher(%arg0: !pdl.operation) { pdl_interp.check_operation_name of %arg0 is "foo.op" -> ^bb2, ^bb1 ^bb1: pdl_interp.return ^bb2: pdl_interp.check_operand_count of %arg0 is 1 -> ^bb3, ^bb1 ^bb3: pdl_interp.check_result_count of %arg0 is 1 -> ^bb4, ^bb1 ^bb4: %0 = pdl_interp.get_operand 0 of %arg0 pdl_interp.is_not_null %0 : !pdl.value -> ^bb5, ^bb1 ^bb5: %1 = pdl_interp.get_result 0 of %arg0 pdl_interp.is_not_null %1 : !pdl.value -> ^bb6, ^bb1 ^bb6: // This operation corresponds to a successful pattern match. pdl_interp.record_match @rewriters::@rewriter(%0, %arg0 : !pdl.value, !pdl.operation) : benefit(1), loc([%arg0]), root("foo.op") -> ^bb1 } module @rewriters { // The inputs to the rewriter from the matcher are passed as arguments. func @rewriter(%arg0: !pdl.value, %arg1: !pdl.operation) { pdl_interp.replace %arg1 with(%arg0) pdl_interp.return } } } ``` Differential Revision: https://reviews.llvm.org/D84580