1abfd1a8bSRiver Riddle //===- TestPDLByteCode.cpp - Test rewriter bytecode functionality ---------===//
2abfd1a8bSRiver Riddle //
3abfd1a8bSRiver Riddle // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4abfd1a8bSRiver Riddle // See https://llvm.org/LICENSE.txt for license information.
5abfd1a8bSRiver Riddle // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6abfd1a8bSRiver Riddle //
7abfd1a8bSRiver Riddle //===----------------------------------------------------------------------===//
8abfd1a8bSRiver Riddle 
9*b4130e9eSStanislav Funiak #include "mlir/Dialect/PDLInterp/IR/PDLInterp.h"
10abfd1a8bSRiver Riddle #include "mlir/Pass/Pass.h"
11abfd1a8bSRiver Riddle #include "mlir/Pass/PassManager.h"
12abfd1a8bSRiver Riddle #include "mlir/Transforms/GreedyPatternRewriteDriver.h"
13abfd1a8bSRiver Riddle 
14abfd1a8bSRiver Riddle using namespace mlir;
15abfd1a8bSRiver Riddle 
16abfd1a8bSRiver Riddle /// Custom constraint invoked from PDL.
17abfd1a8bSRiver Riddle static LogicalResult customSingleEntityConstraint(PDLValue value,
18abfd1a8bSRiver Riddle                                                   ArrayAttr constantParams,
19abfd1a8bSRiver Riddle                                                   PatternRewriter &rewriter) {
20abfd1a8bSRiver Riddle   Operation *rootOp = value.cast<Operation *>();
21abfd1a8bSRiver Riddle   return success(rootOp->getName().getStringRef() == "test.op");
22abfd1a8bSRiver Riddle }
23abfd1a8bSRiver Riddle static LogicalResult customMultiEntityConstraint(ArrayRef<PDLValue> values,
24abfd1a8bSRiver Riddle                                                  ArrayAttr constantParams,
25abfd1a8bSRiver Riddle                                                  PatternRewriter &rewriter) {
26abfd1a8bSRiver Riddle   return customSingleEntityConstraint(values[1], constantParams, rewriter);
27abfd1a8bSRiver Riddle }
2885ab413bSRiver Riddle static LogicalResult
2985ab413bSRiver Riddle customMultiEntityVariadicConstraint(ArrayRef<PDLValue> values,
3085ab413bSRiver Riddle                                     ArrayAttr constantParams,
3185ab413bSRiver Riddle                                     PatternRewriter &rewriter) {
3285ab413bSRiver Riddle   if (llvm::any_of(values, [](const PDLValue &value) { return !value; }))
3385ab413bSRiver Riddle     return failure();
3485ab413bSRiver Riddle   ValueRange operandValues = values[0].cast<ValueRange>();
3585ab413bSRiver Riddle   TypeRange typeValues = values[1].cast<TypeRange>();
3685ab413bSRiver Riddle   if (operandValues.size() != 2 || typeValues.size() != 2)
3785ab413bSRiver Riddle     return failure();
3885ab413bSRiver Riddle   return success();
3985ab413bSRiver Riddle }
40abfd1a8bSRiver Riddle 
41abfd1a8bSRiver Riddle // Custom creator invoked from PDL.
4202c4c0d5SRiver Riddle static void customCreate(ArrayRef<PDLValue> args, ArrayAttr constantParams,
4302c4c0d5SRiver Riddle                          PatternRewriter &rewriter, PDLResultList &results) {
4402c4c0d5SRiver Riddle   results.push_back(rewriter.createOperation(
4502c4c0d5SRiver Riddle       OperationState(args[0].cast<Operation *>()->getLoc(), "test.success")));
46abfd1a8bSRiver Riddle }
4785ab413bSRiver Riddle static void customVariadicResultCreate(ArrayRef<PDLValue> args,
4885ab413bSRiver Riddle                                        ArrayAttr constantParams,
4985ab413bSRiver Riddle                                        PatternRewriter &rewriter,
5085ab413bSRiver Riddle                                        PDLResultList &results) {
5185ab413bSRiver Riddle   Operation *root = args[0].cast<Operation *>();
5285ab413bSRiver Riddle   results.push_back(root->getOperands());
5385ab413bSRiver Riddle   results.push_back(root->getOperands().getTypes());
5485ab413bSRiver Riddle }
5585ab413bSRiver Riddle static void customCreateType(ArrayRef<PDLValue> args, ArrayAttr constantParams,
5685ab413bSRiver Riddle                              PatternRewriter &rewriter,
5785ab413bSRiver Riddle                              PDLResultList &results) {
5885ab413bSRiver Riddle   results.push_back(rewriter.getF32Type());
5985ab413bSRiver Riddle }
60abfd1a8bSRiver Riddle 
61abfd1a8bSRiver Riddle /// Custom rewriter invoked from PDL.
6202c4c0d5SRiver Riddle static void customRewriter(ArrayRef<PDLValue> args, ArrayAttr constantParams,
6302c4c0d5SRiver Riddle                            PatternRewriter &rewriter, PDLResultList &results) {
6402c4c0d5SRiver Riddle   Operation *root = args[0].cast<Operation *>();
65abfd1a8bSRiver Riddle   OperationState successOpState(root->getLoc(), "test.success");
6602c4c0d5SRiver Riddle   successOpState.addOperands(args[1].cast<Value>());
67abfd1a8bSRiver Riddle   successOpState.addAttribute("constantParams", constantParams);
68abfd1a8bSRiver Riddle   rewriter.createOperation(successOpState);
69abfd1a8bSRiver Riddle   rewriter.eraseOp(root);
70abfd1a8bSRiver Riddle }
71abfd1a8bSRiver Riddle 
72abfd1a8bSRiver Riddle namespace {
73abfd1a8bSRiver Riddle struct TestPDLByteCodePass
74abfd1a8bSRiver Riddle     : public PassWrapper<TestPDLByteCodePass, OperationPass<ModuleOp>> {
75b5e22e6dSMehdi Amini   StringRef getArgument() const final { return "test-pdl-bytecode-pass"; }
76b5e22e6dSMehdi Amini   StringRef getDescription() const final {
77b5e22e6dSMehdi Amini     return "Test PDL ByteCode functionality";
78b5e22e6dSMehdi Amini   }
79*b4130e9eSStanislav Funiak   void getDependentDialects(DialectRegistry &registry) const override {
80*b4130e9eSStanislav Funiak     // Mark the pdl_interp dialect as a dependent. This is needed, because we
81*b4130e9eSStanislav Funiak     // create ops from that dialect as a part of the PDL-to-PDLInterp lowering.
82*b4130e9eSStanislav Funiak     registry.insert<pdl_interp::PDLInterpDialect>();
83*b4130e9eSStanislav Funiak   }
84abfd1a8bSRiver Riddle   void runOnOperation() final {
85abfd1a8bSRiver Riddle     ModuleOp module = getOperation();
86abfd1a8bSRiver Riddle 
87abfd1a8bSRiver Riddle     // The test cases are encompassed via two modules, one containing the
88abfd1a8bSRiver Riddle     // patterns and one containing the operations to rewrite.
8941d4aa7dSChris Lattner     ModuleOp patternModule = module.lookupSymbol<ModuleOp>(
9041d4aa7dSChris Lattner         StringAttr::get(module->getContext(), "patterns"));
9141d4aa7dSChris Lattner     ModuleOp irModule = module.lookupSymbol<ModuleOp>(
9241d4aa7dSChris Lattner         StringAttr::get(module->getContext(), "ir"));
93abfd1a8bSRiver Riddle     if (!patternModule || !irModule)
94abfd1a8bSRiver Riddle       return;
95abfd1a8bSRiver Riddle 
9606c3b9c7SRiver Riddle     RewritePatternSet patternList(module->getContext());
9706c3b9c7SRiver Riddle 
9806c3b9c7SRiver Riddle     // Register ahead of time to test when functions are registered without a
9906c3b9c7SRiver Riddle     // pattern.
10006c3b9c7SRiver Riddle     patternList.getPDLPatterns().registerConstraintFunction(
10106c3b9c7SRiver Riddle         "multi_entity_constraint", customMultiEntityConstraint);
10206c3b9c7SRiver Riddle     patternList.getPDLPatterns().registerConstraintFunction(
10306c3b9c7SRiver Riddle         "single_entity_constraint", customSingleEntityConstraint);
10406c3b9c7SRiver Riddle 
105abfd1a8bSRiver Riddle     // Process the pattern module.
106abfd1a8bSRiver Riddle     patternModule.getOperation()->remove();
107abfd1a8bSRiver Riddle     PDLPatternModule pdlPattern(patternModule);
10806c3b9c7SRiver Riddle 
10906c3b9c7SRiver Riddle     // Note: This constraint was already registered, but we re-register here to
11006c3b9c7SRiver Riddle     // ensure that duplication registration is allowed (the duplicate mapping
11106c3b9c7SRiver Riddle     // will be ignored). This tests that we support separating the registration
11206c3b9c7SRiver Riddle     // of library functions from the construction of patterns, and also that we
11306c3b9c7SRiver Riddle     // allow multiple patterns to depend on the same library functions (without
11406c3b9c7SRiver Riddle     // asserting/crashing).
115abfd1a8bSRiver Riddle     pdlPattern.registerConstraintFunction("multi_entity_constraint",
116abfd1a8bSRiver Riddle                                           customMultiEntityConstraint);
11785ab413bSRiver Riddle     pdlPattern.registerConstraintFunction("multi_entity_var_constraint",
11885ab413bSRiver Riddle                                           customMultiEntityVariadicConstraint);
11902c4c0d5SRiver Riddle     pdlPattern.registerRewriteFunction("creator", customCreate);
12085ab413bSRiver Riddle     pdlPattern.registerRewriteFunction("var_creator",
12185ab413bSRiver Riddle                                        customVariadicResultCreate);
12285ab413bSRiver Riddle     pdlPattern.registerRewriteFunction("type_creator", customCreateType);
123abfd1a8bSRiver Riddle     pdlPattern.registerRewriteFunction("rewriter", customRewriter);
12406c3b9c7SRiver Riddle     patternList.add(std::move(pdlPattern));
125abfd1a8bSRiver Riddle 
126abfd1a8bSRiver Riddle     // Invoke the pattern driver with the provided patterns.
127abfd1a8bSRiver Riddle     (void)applyPatternsAndFoldGreedily(irModule.getBodyRegion(),
128abfd1a8bSRiver Riddle                                        std::move(patternList));
129abfd1a8bSRiver Riddle   }
130abfd1a8bSRiver Riddle };
131be0a7e9fSMehdi Amini } // namespace
132abfd1a8bSRiver Riddle 
133abfd1a8bSRiver Riddle namespace mlir {
134abfd1a8bSRiver Riddle namespace test {
135b5e22e6dSMehdi Amini void registerTestPDLByteCodePass() { PassRegistration<TestPDLByteCodePass>(); }
136abfd1a8bSRiver Riddle } // namespace test
137abfd1a8bSRiver Riddle } // namespace mlir
138