1fec6c5acSUday Bondhugula //===- TestPatterns.cpp - Test dialect pattern driver ---------------------===//
2fec6c5acSUday Bondhugula //
3fec6c5acSUday Bondhugula // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4fec6c5acSUday Bondhugula // See https://llvm.org/LICENSE.txt for license information.
5fec6c5acSUday Bondhugula // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6fec6c5acSUday Bondhugula //
7fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
8fec6c5acSUday Bondhugula 
9fec6c5acSUday Bondhugula #include "TestDialect.h"
10fec6c5acSUday Bondhugula #include "mlir/Conversion/StandardToStandard/StandardToStandard.h"
11fec6c5acSUday Bondhugula #include "mlir/IR/PatternMatch.h"
12fec6c5acSUday Bondhugula #include "mlir/Pass/Pass.h"
13fec6c5acSUday Bondhugula #include "mlir/Transforms/DialectConversion.h"
14fec6c5acSUday Bondhugula using namespace mlir;
15fec6c5acSUday Bondhugula 
16fec6c5acSUday Bondhugula // Native function for testing NativeCodeCall
17fec6c5acSUday Bondhugula static Value chooseOperand(Value input1, Value input2, BoolAttr choice) {
18fec6c5acSUday Bondhugula   return choice.getValue() ? input1 : input2;
19fec6c5acSUday Bondhugula }
20fec6c5acSUday Bondhugula 
21fec6c5acSUday Bondhugula static void createOpI(PatternRewriter &rewriter, Value input) {
22fec6c5acSUday Bondhugula   rewriter.create<OpI>(rewriter.getUnknownLoc(), input);
23fec6c5acSUday Bondhugula }
24fec6c5acSUday Bondhugula 
25fec6c5acSUday Bondhugula static void handleNoResultOp(PatternRewriter &rewriter,
26fec6c5acSUday Bondhugula                              OpSymbolBindingNoResult op) {
27fec6c5acSUday Bondhugula   // Turn the no result op to a one-result op.
28fec6c5acSUday Bondhugula   rewriter.create<OpSymbolBindingB>(op.getLoc(), op.operand().getType(),
29fec6c5acSUday Bondhugula                                     op.operand());
30fec6c5acSUday Bondhugula }
31fec6c5acSUday Bondhugula 
32fec6c5acSUday Bondhugula namespace {
33fec6c5acSUday Bondhugula #include "TestPatterns.inc"
34fec6c5acSUday Bondhugula } // end anonymous namespace
35fec6c5acSUday Bondhugula 
36fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
37fec6c5acSUday Bondhugula // Canonicalizer Driver.
38fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
39fec6c5acSUday Bondhugula 
40fec6c5acSUday Bondhugula namespace {
4180aca1eaSRiver Riddle struct TestPatternDriver : public PassWrapper<TestPatternDriver, FunctionPass> {
42fec6c5acSUday Bondhugula   void runOnFunction() override {
43fec6c5acSUday Bondhugula     mlir::OwningRewritePatternList patterns;
44fec6c5acSUday Bondhugula     populateWithGenerated(&getContext(), &patterns);
45fec6c5acSUday Bondhugula 
46fec6c5acSUday Bondhugula     // Verify named pattern is generated with expected name.
47fec6c5acSUday Bondhugula     patterns.insert<TestNamedPatternRule>(&getContext());
48fec6c5acSUday Bondhugula 
49*a5b9316bSUday Bondhugula     applyPatternsAndFoldGreedily(getFunction(), patterns);
50fec6c5acSUday Bondhugula   }
51fec6c5acSUday Bondhugula };
52fec6c5acSUday Bondhugula } // end anonymous namespace
53fec6c5acSUday Bondhugula 
54fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
55fec6c5acSUday Bondhugula // ReturnType Driver.
56fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
57fec6c5acSUday Bondhugula 
58fec6c5acSUday Bondhugula namespace {
59fec6c5acSUday Bondhugula // Generate ops for each instance where the type can be successfully inferred.
60fec6c5acSUday Bondhugula template <typename OpTy>
61fec6c5acSUday Bondhugula static void invokeCreateWithInferredReturnType(Operation *op) {
62fec6c5acSUday Bondhugula   auto *context = op->getContext();
63fec6c5acSUday Bondhugula   auto fop = op->getParentOfType<FuncOp>();
64fec6c5acSUday Bondhugula   auto location = UnknownLoc::get(context);
65fec6c5acSUday Bondhugula   OpBuilder b(op);
66fec6c5acSUday Bondhugula   b.setInsertionPointAfter(op);
67fec6c5acSUday Bondhugula 
68fec6c5acSUday Bondhugula   // Use permutations of 2 args as operands.
69fec6c5acSUday Bondhugula   assert(fop.getNumArguments() >= 2);
70fec6c5acSUday Bondhugula   for (int i = 0, e = fop.getNumArguments(); i < e; ++i) {
71fec6c5acSUday Bondhugula     for (int j = 0; j < e; ++j) {
72fec6c5acSUday Bondhugula       std::array<Value, 2> values = {{fop.getArgument(i), fop.getArgument(j)}};
73fec6c5acSUday Bondhugula       SmallVector<Type, 2> inferredReturnTypes;
74fec6c5acSUday Bondhugula       if (succeeded(OpTy::inferReturnTypes(context, llvm::None, values,
75fec6c5acSUday Bondhugula                                            op->getAttrs(), op->getRegions(),
76fec6c5acSUday Bondhugula                                            inferredReturnTypes))) {
77fec6c5acSUday Bondhugula         OperationState state(location, OpTy::getOperationName());
78fec6c5acSUday Bondhugula         // TODO(jpienaar): Expand to regions.
79fec6c5acSUday Bondhugula         OpTy::build(&b, state, values, op->getAttrs());
80fec6c5acSUday Bondhugula         (void)b.createOperation(state);
81fec6c5acSUday Bondhugula       }
82fec6c5acSUday Bondhugula     }
83fec6c5acSUday Bondhugula   }
84fec6c5acSUday Bondhugula }
85fec6c5acSUday Bondhugula 
86fec6c5acSUday Bondhugula static void reifyReturnShape(Operation *op) {
87fec6c5acSUday Bondhugula   OpBuilder b(op);
88fec6c5acSUday Bondhugula 
89fec6c5acSUday Bondhugula   // Use permutations of 2 args as operands.
90fec6c5acSUday Bondhugula   auto shapedOp = cast<OpWithShapedTypeInferTypeInterfaceOp>(op);
91fec6c5acSUday Bondhugula   SmallVector<Value, 2> shapes;
92fec6c5acSUday Bondhugula   if (failed(shapedOp.reifyReturnTypeShapes(b, shapes)))
93fec6c5acSUday Bondhugula     return;
94fec6c5acSUday Bondhugula   for (auto it : llvm::enumerate(shapes))
95fec6c5acSUday Bondhugula     op->emitRemark() << "value " << it.index() << ": "
96fec6c5acSUday Bondhugula                      << it.value().getDefiningOp();
97fec6c5acSUday Bondhugula }
98fec6c5acSUday Bondhugula 
9980aca1eaSRiver Riddle struct TestReturnTypeDriver
10080aca1eaSRiver Riddle     : public PassWrapper<TestReturnTypeDriver, FunctionPass> {
101fec6c5acSUday Bondhugula   void runOnFunction() override {
102fec6c5acSUday Bondhugula     if (getFunction().getName() == "testCreateFunctions") {
103fec6c5acSUday Bondhugula       std::vector<Operation *> ops;
104fec6c5acSUday Bondhugula       // Collect ops to avoid triggering on inserted ops.
105fec6c5acSUday Bondhugula       for (auto &op : getFunction().getBody().front())
106fec6c5acSUday Bondhugula         ops.push_back(&op);
107fec6c5acSUday Bondhugula       // Generate test patterns for each, but skip terminator.
108fec6c5acSUday Bondhugula       for (auto *op : llvm::makeArrayRef(ops).drop_back()) {
109fec6c5acSUday Bondhugula         // Test create method of each of the Op classes below. The resultant
110fec6c5acSUday Bondhugula         // output would be in reverse order underneath `op` from which
111fec6c5acSUday Bondhugula         // the attributes and regions are used.
112fec6c5acSUday Bondhugula         invokeCreateWithInferredReturnType<OpWithInferTypeInterfaceOp>(op);
113fec6c5acSUday Bondhugula         invokeCreateWithInferredReturnType<
114fec6c5acSUday Bondhugula             OpWithShapedTypeInferTypeInterfaceOp>(op);
115fec6c5acSUday Bondhugula       };
116fec6c5acSUday Bondhugula       return;
117fec6c5acSUday Bondhugula     }
118fec6c5acSUday Bondhugula     if (getFunction().getName() == "testReifyFunctions") {
119fec6c5acSUday Bondhugula       std::vector<Operation *> ops;
120fec6c5acSUday Bondhugula       // Collect ops to avoid triggering on inserted ops.
121fec6c5acSUday Bondhugula       for (auto &op : getFunction().getBody().front())
122fec6c5acSUday Bondhugula         if (isa<OpWithShapedTypeInferTypeInterfaceOp>(op))
123fec6c5acSUday Bondhugula           ops.push_back(&op);
124fec6c5acSUday Bondhugula       // Generate test patterns for each, but skip terminator.
125fec6c5acSUday Bondhugula       for (auto *op : ops)
126fec6c5acSUday Bondhugula         reifyReturnShape(op);
127fec6c5acSUday Bondhugula     }
128fec6c5acSUday Bondhugula   }
129fec6c5acSUday Bondhugula };
130fec6c5acSUday Bondhugula } // end anonymous namespace
131fec6c5acSUday Bondhugula 
132fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
133fec6c5acSUday Bondhugula // Legalization Driver.
134fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
135fec6c5acSUday Bondhugula 
136fec6c5acSUday Bondhugula namespace {
137fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
138fec6c5acSUday Bondhugula // Region-Block Rewrite Testing
139fec6c5acSUday Bondhugula 
140fec6c5acSUday Bondhugula /// This pattern is a simple pattern that inlines the first region of a given
141fec6c5acSUday Bondhugula /// operation into the parent region.
142fec6c5acSUday Bondhugula struct TestRegionRewriteBlockMovement : public ConversionPattern {
143fec6c5acSUday Bondhugula   TestRegionRewriteBlockMovement(MLIRContext *ctx)
144fec6c5acSUday Bondhugula       : ConversionPattern("test.region", 1, ctx) {}
145fec6c5acSUday Bondhugula 
146fec6c5acSUday Bondhugula   LogicalResult
147fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
148fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
149fec6c5acSUday Bondhugula     // Inline this region into the parent region.
150fec6c5acSUday Bondhugula     auto &parentRegion = *op->getParentRegion();
151fec6c5acSUday Bondhugula     if (op->getAttr("legalizer.should_clone"))
152fec6c5acSUday Bondhugula       rewriter.cloneRegionBefore(op->getRegion(0), parentRegion,
153fec6c5acSUday Bondhugula                                  parentRegion.end());
154fec6c5acSUday Bondhugula     else
155fec6c5acSUday Bondhugula       rewriter.inlineRegionBefore(op->getRegion(0), parentRegion,
156fec6c5acSUday Bondhugula                                   parentRegion.end());
157fec6c5acSUday Bondhugula 
158fec6c5acSUday Bondhugula     // Drop this operation.
159fec6c5acSUday Bondhugula     rewriter.eraseOp(op);
160fec6c5acSUday Bondhugula     return success();
161fec6c5acSUday Bondhugula   }
162fec6c5acSUday Bondhugula };
163fec6c5acSUday Bondhugula /// This pattern is a simple pattern that generates a region containing an
164fec6c5acSUday Bondhugula /// illegal operation.
165fec6c5acSUday Bondhugula struct TestRegionRewriteUndo : public RewritePattern {
166fec6c5acSUday Bondhugula   TestRegionRewriteUndo(MLIRContext *ctx)
167fec6c5acSUday Bondhugula       : RewritePattern("test.region_builder", 1, ctx) {}
168fec6c5acSUday Bondhugula 
169fec6c5acSUday Bondhugula   LogicalResult matchAndRewrite(Operation *op,
170fec6c5acSUday Bondhugula                                 PatternRewriter &rewriter) const final {
171fec6c5acSUday Bondhugula     // Create the region operation with an entry block containing arguments.
172fec6c5acSUday Bondhugula     OperationState newRegion(op->getLoc(), "test.region");
173fec6c5acSUday Bondhugula     newRegion.addRegion();
174fec6c5acSUday Bondhugula     auto *regionOp = rewriter.createOperation(newRegion);
175fec6c5acSUday Bondhugula     auto *entryBlock = rewriter.createBlock(&regionOp->getRegion(0));
176fec6c5acSUday Bondhugula     entryBlock->addArgument(rewriter.getIntegerType(64));
177fec6c5acSUday Bondhugula 
178fec6c5acSUday Bondhugula     // Add an explicitly illegal operation to ensure the conversion fails.
179fec6c5acSUday Bondhugula     rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getIntegerType(32));
180fec6c5acSUday Bondhugula     rewriter.create<TestValidOp>(op->getLoc(), ArrayRef<Value>());
181fec6c5acSUday Bondhugula 
182fec6c5acSUday Bondhugula     // Drop this operation.
183fec6c5acSUday Bondhugula     rewriter.eraseOp(op);
184fec6c5acSUday Bondhugula     return success();
185fec6c5acSUday Bondhugula   }
186fec6c5acSUday Bondhugula };
187f27f1e8cSAlex Zinenko /// A simple pattern that creates a block at the end of the parent region of the
188f27f1e8cSAlex Zinenko /// matched operation.
189f27f1e8cSAlex Zinenko struct TestCreateBlock : public RewritePattern {
190f27f1e8cSAlex Zinenko   TestCreateBlock(MLIRContext *ctx)
191f27f1e8cSAlex Zinenko       : RewritePattern("test.create_block", /*benefit=*/1, ctx) {}
192f27f1e8cSAlex Zinenko 
193f27f1e8cSAlex Zinenko   LogicalResult matchAndRewrite(Operation *op,
194f27f1e8cSAlex Zinenko                                 PatternRewriter &rewriter) const final {
195f27f1e8cSAlex Zinenko     Region &region = *op->getParentRegion();
196f27f1e8cSAlex Zinenko     Type i32Type = rewriter.getIntegerType(32);
197f27f1e8cSAlex Zinenko     rewriter.createBlock(&region, region.end(), {i32Type, i32Type});
198f27f1e8cSAlex Zinenko     rewriter.create<TerminatorOp>(op->getLoc());
199f27f1e8cSAlex Zinenko     rewriter.replaceOp(op, {});
200f27f1e8cSAlex Zinenko     return success();
201f27f1e8cSAlex Zinenko   }
202f27f1e8cSAlex Zinenko };
203f27f1e8cSAlex Zinenko 
204f27f1e8cSAlex Zinenko /// A simple pattern that creates a block containing an invalid operaiton in
205f27f1e8cSAlex Zinenko /// order to trigger the block creation undo mechanism.
206f27f1e8cSAlex Zinenko struct TestCreateIllegalBlock : public RewritePattern {
207f27f1e8cSAlex Zinenko   TestCreateIllegalBlock(MLIRContext *ctx)
208f27f1e8cSAlex Zinenko       : RewritePattern("test.create_illegal_block", /*benefit=*/1, ctx) {}
209f27f1e8cSAlex Zinenko 
210f27f1e8cSAlex Zinenko   LogicalResult matchAndRewrite(Operation *op,
211f27f1e8cSAlex Zinenko                                 PatternRewriter &rewriter) const final {
212f27f1e8cSAlex Zinenko     Region &region = *op->getParentRegion();
213f27f1e8cSAlex Zinenko     Type i32Type = rewriter.getIntegerType(32);
214f27f1e8cSAlex Zinenko     rewriter.createBlock(&region, region.end(), {i32Type, i32Type});
215f27f1e8cSAlex Zinenko     // Create an illegal op to ensure the conversion fails.
216f27f1e8cSAlex Zinenko     rewriter.create<ILLegalOpF>(op->getLoc(), i32Type);
217f27f1e8cSAlex Zinenko     rewriter.create<TerminatorOp>(op->getLoc());
218f27f1e8cSAlex Zinenko     rewriter.replaceOp(op, {});
219f27f1e8cSAlex Zinenko     return success();
220f27f1e8cSAlex Zinenko   }
221f27f1e8cSAlex Zinenko };
222fec6c5acSUday Bondhugula 
223fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
224fec6c5acSUday Bondhugula // Type-Conversion Rewrite Testing
225fec6c5acSUday Bondhugula 
226fec6c5acSUday Bondhugula /// This patterns erases a region operation that has had a type conversion.
227fec6c5acSUday Bondhugula struct TestDropOpSignatureConversion : public ConversionPattern {
228fec6c5acSUday Bondhugula   TestDropOpSignatureConversion(MLIRContext *ctx, TypeConverter &converter)
229fec6c5acSUday Bondhugula       : ConversionPattern("test.drop_region_op", 1, ctx), converter(converter) {
230fec6c5acSUday Bondhugula   }
231fec6c5acSUday Bondhugula   LogicalResult
232fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
233fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const override {
234fec6c5acSUday Bondhugula     Region &region = op->getRegion(0);
235fec6c5acSUday Bondhugula     Block *entry = &region.front();
236fec6c5acSUday Bondhugula 
237fec6c5acSUday Bondhugula     // Convert the original entry arguments.
238fec6c5acSUday Bondhugula     TypeConverter::SignatureConversion result(entry->getNumArguments());
239fec6c5acSUday Bondhugula     for (unsigned i = 0, e = entry->getNumArguments(); i != e; ++i)
240fec6c5acSUday Bondhugula       if (failed(converter.convertSignatureArg(
241fec6c5acSUday Bondhugula               i, entry->getArgument(i).getType(), result)))
242fec6c5acSUday Bondhugula         return failure();
243fec6c5acSUday Bondhugula 
244fec6c5acSUday Bondhugula     // Convert the region signature and just drop the operation.
245fec6c5acSUday Bondhugula     rewriter.applySignatureConversion(&region, result);
246fec6c5acSUday Bondhugula     rewriter.eraseOp(op);
247fec6c5acSUday Bondhugula     return success();
248fec6c5acSUday Bondhugula   }
249fec6c5acSUday Bondhugula 
250fec6c5acSUday Bondhugula   /// The type converter to use when rewriting the signature.
251fec6c5acSUday Bondhugula   TypeConverter &converter;
252fec6c5acSUday Bondhugula };
253fec6c5acSUday Bondhugula /// This pattern simply updates the operands of the given operation.
254fec6c5acSUday Bondhugula struct TestPassthroughInvalidOp : public ConversionPattern {
255fec6c5acSUday Bondhugula   TestPassthroughInvalidOp(MLIRContext *ctx)
256fec6c5acSUday Bondhugula       : ConversionPattern("test.invalid", 1, ctx) {}
257fec6c5acSUday Bondhugula   LogicalResult
258fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
259fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
260fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<TestValidOp>(op, llvm::None, operands,
261fec6c5acSUday Bondhugula                                              llvm::None);
262fec6c5acSUday Bondhugula     return success();
263fec6c5acSUday Bondhugula   }
264fec6c5acSUday Bondhugula };
265fec6c5acSUday Bondhugula /// This pattern handles the case of a split return value.
266fec6c5acSUday Bondhugula struct TestSplitReturnType : public ConversionPattern {
267fec6c5acSUday Bondhugula   TestSplitReturnType(MLIRContext *ctx)
268fec6c5acSUday Bondhugula       : ConversionPattern("test.return", 1, ctx) {}
269fec6c5acSUday Bondhugula   LogicalResult
270fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
271fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
272fec6c5acSUday Bondhugula     // Check for a return of F32.
273fec6c5acSUday Bondhugula     if (op->getNumOperands() != 1 || !op->getOperand(0).getType().isF32())
274fec6c5acSUday Bondhugula       return failure();
275fec6c5acSUday Bondhugula 
276fec6c5acSUday Bondhugula     // Check if the first operation is a cast operation, if it is we use the
277fec6c5acSUday Bondhugula     // results directly.
278fec6c5acSUday Bondhugula     auto *defOp = operands[0].getDefiningOp();
279fec6c5acSUday Bondhugula     if (auto packerOp = llvm::dyn_cast_or_null<TestCastOp>(defOp)) {
280fec6c5acSUday Bondhugula       rewriter.replaceOpWithNewOp<TestReturnOp>(op, packerOp.getOperands());
281fec6c5acSUday Bondhugula       return success();
282fec6c5acSUday Bondhugula     }
283fec6c5acSUday Bondhugula 
284fec6c5acSUday Bondhugula     // Otherwise, fail to match.
285fec6c5acSUday Bondhugula     return failure();
286fec6c5acSUday Bondhugula   }
287fec6c5acSUday Bondhugula };
288fec6c5acSUday Bondhugula 
289fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
290fec6c5acSUday Bondhugula // Multi-Level Type-Conversion Rewrite Testing
291fec6c5acSUday Bondhugula struct TestChangeProducerTypeI32ToF32 : public ConversionPattern {
292fec6c5acSUday Bondhugula   TestChangeProducerTypeI32ToF32(MLIRContext *ctx)
293fec6c5acSUday Bondhugula       : ConversionPattern("test.type_producer", 1, ctx) {}
294fec6c5acSUday Bondhugula   LogicalResult
295fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
296fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
297fec6c5acSUday Bondhugula     // If the type is I32, change the type to F32.
298fec6c5acSUday Bondhugula     if (!Type(*op->result_type_begin()).isSignlessInteger(32))
299fec6c5acSUday Bondhugula       return failure();
300fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getF32Type());
301fec6c5acSUday Bondhugula     return success();
302fec6c5acSUday Bondhugula   }
303fec6c5acSUday Bondhugula };
304fec6c5acSUday Bondhugula struct TestChangeProducerTypeF32ToF64 : public ConversionPattern {
305fec6c5acSUday Bondhugula   TestChangeProducerTypeF32ToF64(MLIRContext *ctx)
306fec6c5acSUday Bondhugula       : ConversionPattern("test.type_producer", 1, ctx) {}
307fec6c5acSUday Bondhugula   LogicalResult
308fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
309fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
310fec6c5acSUday Bondhugula     // If the type is F32, change the type to F64.
311fec6c5acSUday Bondhugula     if (!Type(*op->result_type_begin()).isF32())
312fec6c5acSUday Bondhugula       return rewriter.notifyMatchFailure(op, "expected single f32 operand");
313fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getF64Type());
314fec6c5acSUday Bondhugula     return success();
315fec6c5acSUday Bondhugula   }
316fec6c5acSUday Bondhugula };
317fec6c5acSUday Bondhugula struct TestChangeProducerTypeF32ToInvalid : public ConversionPattern {
318fec6c5acSUday Bondhugula   TestChangeProducerTypeF32ToInvalid(MLIRContext *ctx)
319fec6c5acSUday Bondhugula       : ConversionPattern("test.type_producer", 10, ctx) {}
320fec6c5acSUday Bondhugula   LogicalResult
321fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
322fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
323fec6c5acSUday Bondhugula     // Always convert to B16, even though it is not a legal type. This tests
324fec6c5acSUday Bondhugula     // that values are unmapped correctly.
325fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getBF16Type());
326fec6c5acSUday Bondhugula     return success();
327fec6c5acSUday Bondhugula   }
328fec6c5acSUday Bondhugula };
329fec6c5acSUday Bondhugula struct TestUpdateConsumerType : public ConversionPattern {
330fec6c5acSUday Bondhugula   TestUpdateConsumerType(MLIRContext *ctx)
331fec6c5acSUday Bondhugula       : ConversionPattern("test.type_consumer", 1, ctx) {}
332fec6c5acSUday Bondhugula   LogicalResult
333fec6c5acSUday Bondhugula   matchAndRewrite(Operation *op, ArrayRef<Value> operands,
334fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const final {
335fec6c5acSUday Bondhugula     // Verify that the incoming operand has been successfully remapped to F64.
336fec6c5acSUday Bondhugula     if (!operands[0].getType().isF64())
337fec6c5acSUday Bondhugula       return failure();
338fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<TestTypeConsumerOp>(op, operands[0]);
339fec6c5acSUday Bondhugula     return success();
340fec6c5acSUday Bondhugula   }
341fec6c5acSUday Bondhugula };
342fec6c5acSUday Bondhugula 
343fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
344fec6c5acSUday Bondhugula // Non-Root Replacement Rewrite Testing
345fec6c5acSUday Bondhugula /// This pattern generates an invalid operation, but replaces it before the
346fec6c5acSUday Bondhugula /// pattern is finished. This checks that we don't need to legalize the
347fec6c5acSUday Bondhugula /// temporary op.
348fec6c5acSUday Bondhugula struct TestNonRootReplacement : public RewritePattern {
349fec6c5acSUday Bondhugula   TestNonRootReplacement(MLIRContext *ctx)
350fec6c5acSUday Bondhugula       : RewritePattern("test.replace_non_root", 1, ctx) {}
351fec6c5acSUday Bondhugula 
352fec6c5acSUday Bondhugula   LogicalResult matchAndRewrite(Operation *op,
353fec6c5acSUday Bondhugula                                 PatternRewriter &rewriter) const final {
354fec6c5acSUday Bondhugula     auto resultType = *op->result_type_begin();
355fec6c5acSUday Bondhugula     auto illegalOp = rewriter.create<ILLegalOpF>(op->getLoc(), resultType);
356fec6c5acSUday Bondhugula     auto legalOp = rewriter.create<LegalOpB>(op->getLoc(), resultType);
357fec6c5acSUday Bondhugula 
358fec6c5acSUday Bondhugula     rewriter.replaceOp(illegalOp, {legalOp});
359fec6c5acSUday Bondhugula     rewriter.replaceOp(op, {illegalOp});
360fec6c5acSUday Bondhugula     return success();
361fec6c5acSUday Bondhugula   }
362fec6c5acSUday Bondhugula };
363bd1ccfe6SRiver Riddle 
364bd1ccfe6SRiver Riddle //===----------------------------------------------------------------------===//
365bd1ccfe6SRiver Riddle // Recursive Rewrite Testing
366bd1ccfe6SRiver Riddle /// This pattern is applied to the same operation multiple times, but has a
367bd1ccfe6SRiver Riddle /// bounded recursion.
368bd1ccfe6SRiver Riddle struct TestBoundedRecursiveRewrite
369bd1ccfe6SRiver Riddle     : public OpRewritePattern<TestRecursiveRewriteOp> {
370bd1ccfe6SRiver Riddle   using OpRewritePattern<TestRecursiveRewriteOp>::OpRewritePattern;
371bd1ccfe6SRiver Riddle 
372bd1ccfe6SRiver Riddle   LogicalResult matchAndRewrite(TestRecursiveRewriteOp op,
373bd1ccfe6SRiver Riddle                                 PatternRewriter &rewriter) const final {
374bd1ccfe6SRiver Riddle     // Decrement the depth of the op in-place.
375bd1ccfe6SRiver Riddle     rewriter.updateRootInPlace(op, [&] {
376bd1ccfe6SRiver Riddle       op.setAttr("depth",
377bd1ccfe6SRiver Riddle                  rewriter.getI64IntegerAttr(op.depth().getSExtValue() - 1));
378bd1ccfe6SRiver Riddle     });
379bd1ccfe6SRiver Riddle     return success();
380bd1ccfe6SRiver Riddle   }
381bd1ccfe6SRiver Riddle 
382bd1ccfe6SRiver Riddle   /// The conversion target handles bounding the recursion of this pattern.
383bd1ccfe6SRiver Riddle   bool hasBoundedRewriteRecursion() const final { return true; }
384bd1ccfe6SRiver Riddle };
385fec6c5acSUday Bondhugula } // namespace
386fec6c5acSUday Bondhugula 
387fec6c5acSUday Bondhugula namespace {
388fec6c5acSUday Bondhugula struct TestTypeConverter : public TypeConverter {
389fec6c5acSUday Bondhugula   using TypeConverter::TypeConverter;
390fec6c5acSUday Bondhugula   TestTypeConverter() { addConversion(convertType); }
391fec6c5acSUday Bondhugula 
392fec6c5acSUday Bondhugula   static LogicalResult convertType(Type t, SmallVectorImpl<Type> &results) {
393fec6c5acSUday Bondhugula     // Drop I16 types.
394fec6c5acSUday Bondhugula     if (t.isSignlessInteger(16))
395fec6c5acSUday Bondhugula       return success();
396fec6c5acSUday Bondhugula 
397fec6c5acSUday Bondhugula     // Convert I64 to F64.
398fec6c5acSUday Bondhugula     if (t.isSignlessInteger(64)) {
399fec6c5acSUday Bondhugula       results.push_back(FloatType::getF64(t.getContext()));
400fec6c5acSUday Bondhugula       return success();
401fec6c5acSUday Bondhugula     }
402fec6c5acSUday Bondhugula 
403fec6c5acSUday Bondhugula     // Split F32 into F16,F16.
404fec6c5acSUday Bondhugula     if (t.isF32()) {
405fec6c5acSUday Bondhugula       results.assign(2, FloatType::getF16(t.getContext()));
406fec6c5acSUday Bondhugula       return success();
407fec6c5acSUday Bondhugula     }
408fec6c5acSUday Bondhugula 
409fec6c5acSUday Bondhugula     // Otherwise, convert the type directly.
410fec6c5acSUday Bondhugula     results.push_back(t);
411fec6c5acSUday Bondhugula     return success();
412fec6c5acSUday Bondhugula   }
413fec6c5acSUday Bondhugula 
414fec6c5acSUday Bondhugula   /// Override the hook to materialize a conversion. This is necessary because
415fec6c5acSUday Bondhugula   /// we generate 1->N type mappings.
416fec6c5acSUday Bondhugula   Operation *materializeConversion(PatternRewriter &rewriter, Type resultType,
417fec6c5acSUday Bondhugula                                    ArrayRef<Value> inputs,
418fec6c5acSUday Bondhugula                                    Location loc) override {
419fec6c5acSUday Bondhugula     return rewriter.create<TestCastOp>(loc, resultType, inputs);
420fec6c5acSUday Bondhugula   }
421fec6c5acSUday Bondhugula };
422fec6c5acSUday Bondhugula 
423fec6c5acSUday Bondhugula struct TestLegalizePatternDriver
42480aca1eaSRiver Riddle     : public PassWrapper<TestLegalizePatternDriver, OperationPass<ModuleOp>> {
425fec6c5acSUday Bondhugula   /// The mode of conversion to use with the driver.
426fec6c5acSUday Bondhugula   enum class ConversionMode { Analysis, Full, Partial };
427fec6c5acSUday Bondhugula 
428fec6c5acSUday Bondhugula   TestLegalizePatternDriver(ConversionMode mode) : mode(mode) {}
429fec6c5acSUday Bondhugula 
430722f909fSRiver Riddle   void runOnOperation() override {
431fec6c5acSUday Bondhugula     TestTypeConverter converter;
432fec6c5acSUday Bondhugula     mlir::OwningRewritePatternList patterns;
433fec6c5acSUday Bondhugula     populateWithGenerated(&getContext(), &patterns);
434f27f1e8cSAlex Zinenko     patterns.insert<
435f27f1e8cSAlex Zinenko         TestRegionRewriteBlockMovement, TestRegionRewriteUndo, TestCreateBlock,
436f27f1e8cSAlex Zinenko         TestCreateIllegalBlock, TestPassthroughInvalidOp, TestSplitReturnType,
437fec6c5acSUday Bondhugula         TestChangeProducerTypeI32ToF32, TestChangeProducerTypeF32ToF64,
438fec6c5acSUday Bondhugula         TestChangeProducerTypeF32ToInvalid, TestUpdateConsumerType,
439bd1ccfe6SRiver Riddle         TestNonRootReplacement, TestBoundedRecursiveRewrite>(&getContext());
440fec6c5acSUday Bondhugula     patterns.insert<TestDropOpSignatureConversion>(&getContext(), converter);
441fec6c5acSUday Bondhugula     mlir::populateFuncOpTypeConversionPattern(patterns, &getContext(),
442fec6c5acSUday Bondhugula                                               converter);
443fec6c5acSUday Bondhugula     mlir::populateCallOpTypeConversionPattern(patterns, &getContext(),
444fec6c5acSUday Bondhugula                                               converter);
445fec6c5acSUday Bondhugula 
446fec6c5acSUday Bondhugula     // Define the conversion target used for the test.
447fec6c5acSUday Bondhugula     ConversionTarget target(getContext());
448fec6c5acSUday Bondhugula     target.addLegalOp<ModuleOp, ModuleTerminatorOp>();
449f27f1e8cSAlex Zinenko     target.addLegalOp<LegalOpA, LegalOpB, TestCastOp, TestValidOp,
450f27f1e8cSAlex Zinenko                       TerminatorOp>();
451fec6c5acSUday Bondhugula     target
452fec6c5acSUday Bondhugula         .addIllegalOp<ILLegalOpF, TestRegionBuilderOp, TestOpWithRegionFold>();
453fec6c5acSUday Bondhugula     target.addDynamicallyLegalOp<TestReturnOp>([](TestReturnOp op) {
454fec6c5acSUday Bondhugula       // Don't allow F32 operands.
455fec6c5acSUday Bondhugula       return llvm::none_of(op.getOperandTypes(),
456fec6c5acSUday Bondhugula                            [](Type type) { return type.isF32(); });
457fec6c5acSUday Bondhugula     });
458fec6c5acSUday Bondhugula     target.addDynamicallyLegalOp<FuncOp>(
459fec6c5acSUday Bondhugula         [&](FuncOp op) { return converter.isSignatureLegal(op.getType()); });
460fec6c5acSUday Bondhugula 
461fec6c5acSUday Bondhugula     // Expect the type_producer/type_consumer operations to only operate on f64.
462fec6c5acSUday Bondhugula     target.addDynamicallyLegalOp<TestTypeProducerOp>(
463fec6c5acSUday Bondhugula         [](TestTypeProducerOp op) { return op.getType().isF64(); });
464fec6c5acSUday Bondhugula     target.addDynamicallyLegalOp<TestTypeConsumerOp>([](TestTypeConsumerOp op) {
465fec6c5acSUday Bondhugula       return op.getOperand().getType().isF64();
466fec6c5acSUday Bondhugula     });
467fec6c5acSUday Bondhugula 
468fec6c5acSUday Bondhugula     // Check support for marking certain operations as recursively legal.
469fec6c5acSUday Bondhugula     target.markOpRecursivelyLegal<FuncOp, ModuleOp>([](Operation *op) {
470fec6c5acSUday Bondhugula       return static_cast<bool>(
471fec6c5acSUday Bondhugula           op->getAttrOfType<UnitAttr>("test.recursively_legal"));
472fec6c5acSUday Bondhugula     });
473fec6c5acSUday Bondhugula 
474bd1ccfe6SRiver Riddle     // Mark the bound recursion operation as dynamically legal.
475bd1ccfe6SRiver Riddle     target.addDynamicallyLegalOp<TestRecursiveRewriteOp>(
476bd1ccfe6SRiver Riddle         [](TestRecursiveRewriteOp op) { return op.depth() == 0; });
477bd1ccfe6SRiver Riddle 
478fec6c5acSUday Bondhugula     // Handle a partial conversion.
479fec6c5acSUday Bondhugula     if (mode == ConversionMode::Partial) {
480722f909fSRiver Riddle       (void)applyPartialConversion(getOperation(), target, patterns,
481722f909fSRiver Riddle                                    &converter);
482fec6c5acSUday Bondhugula       return;
483fec6c5acSUday Bondhugula     }
484fec6c5acSUday Bondhugula 
485fec6c5acSUday Bondhugula     // Handle a full conversion.
486fec6c5acSUday Bondhugula     if (mode == ConversionMode::Full) {
487fec6c5acSUday Bondhugula       // Check support for marking unknown operations as dynamically legal.
488fec6c5acSUday Bondhugula       target.markUnknownOpDynamicallyLegal([](Operation *op) {
489fec6c5acSUday Bondhugula         return (bool)op->getAttrOfType<UnitAttr>("test.dynamically_legal");
490fec6c5acSUday Bondhugula       });
491fec6c5acSUday Bondhugula 
492722f909fSRiver Riddle       (void)applyFullConversion(getOperation(), target, patterns, &converter);
493fec6c5acSUday Bondhugula       return;
494fec6c5acSUday Bondhugula     }
495fec6c5acSUday Bondhugula 
496fec6c5acSUday Bondhugula     // Otherwise, handle an analysis conversion.
497fec6c5acSUday Bondhugula     assert(mode == ConversionMode::Analysis);
498fec6c5acSUday Bondhugula 
499fec6c5acSUday Bondhugula     // Analyze the convertible operations.
500fec6c5acSUday Bondhugula     DenseSet<Operation *> legalizedOps;
501722f909fSRiver Riddle     if (failed(applyAnalysisConversion(getOperation(), target, patterns,
502fec6c5acSUday Bondhugula                                        legalizedOps, &converter)))
503fec6c5acSUday Bondhugula       return signalPassFailure();
504fec6c5acSUday Bondhugula 
505fec6c5acSUday Bondhugula     // Emit remarks for each legalizable operation.
506fec6c5acSUday Bondhugula     for (auto *op : legalizedOps)
507fec6c5acSUday Bondhugula       op->emitRemark() << "op '" << op->getName() << "' is legalizable";
508fec6c5acSUday Bondhugula   }
509fec6c5acSUday Bondhugula 
510fec6c5acSUday Bondhugula   /// The mode of conversion to use.
511fec6c5acSUday Bondhugula   ConversionMode mode;
512fec6c5acSUday Bondhugula };
513fec6c5acSUday Bondhugula } // end anonymous namespace
514fec6c5acSUday Bondhugula 
515fec6c5acSUday Bondhugula static llvm::cl::opt<TestLegalizePatternDriver::ConversionMode>
516fec6c5acSUday Bondhugula     legalizerConversionMode(
517fec6c5acSUday Bondhugula         "test-legalize-mode",
518fec6c5acSUday Bondhugula         llvm::cl::desc("The legalization mode to use with the test driver"),
519fec6c5acSUday Bondhugula         llvm::cl::init(TestLegalizePatternDriver::ConversionMode::Partial),
520fec6c5acSUday Bondhugula         llvm::cl::values(
521fec6c5acSUday Bondhugula             clEnumValN(TestLegalizePatternDriver::ConversionMode::Analysis,
522fec6c5acSUday Bondhugula                        "analysis", "Perform an analysis conversion"),
523fec6c5acSUday Bondhugula             clEnumValN(TestLegalizePatternDriver::ConversionMode::Full, "full",
524fec6c5acSUday Bondhugula                        "Perform a full conversion"),
525fec6c5acSUday Bondhugula             clEnumValN(TestLegalizePatternDriver::ConversionMode::Partial,
526fec6c5acSUday Bondhugula                        "partial", "Perform a partial conversion")));
527fec6c5acSUday Bondhugula 
528fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===//
529fec6c5acSUday Bondhugula // ConversionPatternRewriter::getRemappedValue testing. This method is used
5305aacce3dSKazuaki Ishizaki // to get the remapped value of an original value that was replaced using
531fec6c5acSUday Bondhugula // ConversionPatternRewriter.
532fec6c5acSUday Bondhugula namespace {
533fec6c5acSUday Bondhugula /// Converter that replaces a one-result one-operand OneVResOneVOperandOp1 with
534fec6c5acSUday Bondhugula /// a one-operand two-result OneVResOneVOperandOp1 by replicating its original
535fec6c5acSUday Bondhugula /// operand twice.
536fec6c5acSUday Bondhugula ///
537fec6c5acSUday Bondhugula /// Example:
538fec6c5acSUday Bondhugula ///   %1 = test.one_variadic_out_one_variadic_in1"(%0)
539fec6c5acSUday Bondhugula /// is replaced with:
540fec6c5acSUday Bondhugula ///   %1 = test.one_variadic_out_one_variadic_in1"(%0, %0)
541fec6c5acSUday Bondhugula struct OneVResOneVOperandOp1Converter
542fec6c5acSUday Bondhugula     : public OpConversionPattern<OneVResOneVOperandOp1> {
543fec6c5acSUday Bondhugula   using OpConversionPattern<OneVResOneVOperandOp1>::OpConversionPattern;
544fec6c5acSUday Bondhugula 
545fec6c5acSUday Bondhugula   LogicalResult
546fec6c5acSUday Bondhugula   matchAndRewrite(OneVResOneVOperandOp1 op, ArrayRef<Value> operands,
547fec6c5acSUday Bondhugula                   ConversionPatternRewriter &rewriter) const override {
548fec6c5acSUday Bondhugula     auto origOps = op.getOperands();
549fec6c5acSUday Bondhugula     assert(std::distance(origOps.begin(), origOps.end()) == 1 &&
550fec6c5acSUday Bondhugula            "One operand expected");
551fec6c5acSUday Bondhugula     Value origOp = *origOps.begin();
552fec6c5acSUday Bondhugula     SmallVector<Value, 2> remappedOperands;
553fec6c5acSUday Bondhugula     // Replicate the remapped original operand twice. Note that we don't used
554fec6c5acSUday Bondhugula     // the remapped 'operand' since the goal is testing 'getRemappedValue'.
555fec6c5acSUday Bondhugula     remappedOperands.push_back(rewriter.getRemappedValue(origOp));
556fec6c5acSUday Bondhugula     remappedOperands.push_back(rewriter.getRemappedValue(origOp));
557fec6c5acSUday Bondhugula 
558fec6c5acSUday Bondhugula     rewriter.replaceOpWithNewOp<OneVResOneVOperandOp1>(op, op.getResultTypes(),
559fec6c5acSUday Bondhugula                                                        remappedOperands);
560fec6c5acSUday Bondhugula     return success();
561fec6c5acSUday Bondhugula   }
562fec6c5acSUday Bondhugula };
563fec6c5acSUday Bondhugula 
56480aca1eaSRiver Riddle struct TestRemappedValue
56580aca1eaSRiver Riddle     : public mlir::PassWrapper<TestRemappedValue, FunctionPass> {
566fec6c5acSUday Bondhugula   void runOnFunction() override {
567fec6c5acSUday Bondhugula     mlir::OwningRewritePatternList patterns;
568fec6c5acSUday Bondhugula     patterns.insert<OneVResOneVOperandOp1Converter>(&getContext());
569fec6c5acSUday Bondhugula 
570fec6c5acSUday Bondhugula     mlir::ConversionTarget target(getContext());
571fec6c5acSUday Bondhugula     target.addLegalOp<ModuleOp, ModuleTerminatorOp, FuncOp, TestReturnOp>();
572fec6c5acSUday Bondhugula     // We make OneVResOneVOperandOp1 legal only when it has more that one
573fec6c5acSUday Bondhugula     // operand. This will trigger the conversion that will replace one-operand
574fec6c5acSUday Bondhugula     // OneVResOneVOperandOp1 with two-operand OneVResOneVOperandOp1.
575fec6c5acSUday Bondhugula     target.addDynamicallyLegalOp<OneVResOneVOperandOp1>(
576fec6c5acSUday Bondhugula         [](Operation *op) -> bool {
577fec6c5acSUday Bondhugula           return std::distance(op->operand_begin(), op->operand_end()) > 1;
578fec6c5acSUday Bondhugula         });
579fec6c5acSUday Bondhugula 
580fec6c5acSUday Bondhugula     if (failed(mlir::applyFullConversion(getFunction(), target, patterns))) {
581fec6c5acSUday Bondhugula       signalPassFailure();
582fec6c5acSUday Bondhugula     }
583fec6c5acSUday Bondhugula   }
584fec6c5acSUday Bondhugula };
585fec6c5acSUday Bondhugula } // end anonymous namespace
586fec6c5acSUday Bondhugula 
587fec6c5acSUday Bondhugula namespace mlir {
588fec6c5acSUday Bondhugula void registerPatternsTestPass() {
589fec6c5acSUday Bondhugula   mlir::PassRegistration<TestReturnTypeDriver>("test-return-type",
590fec6c5acSUday Bondhugula                                                "Run return type functions");
591fec6c5acSUday Bondhugula 
592fec6c5acSUday Bondhugula   mlir::PassRegistration<TestPatternDriver>("test-patterns",
593fec6c5acSUday Bondhugula                                             "Run test dialect patterns");
594fec6c5acSUday Bondhugula 
595fec6c5acSUday Bondhugula   mlir::PassRegistration<TestLegalizePatternDriver>(
596fec6c5acSUday Bondhugula       "test-legalize-patterns", "Run test dialect legalization patterns", [] {
597fec6c5acSUday Bondhugula         return std::make_unique<TestLegalizePatternDriver>(
598fec6c5acSUday Bondhugula             legalizerConversionMode);
599fec6c5acSUday Bondhugula       });
600fec6c5acSUday Bondhugula 
601fec6c5acSUday Bondhugula   PassRegistration<TestRemappedValue>(
602fec6c5acSUday Bondhugula       "test-remapped-value",
603fec6c5acSUday Bondhugula       "Test public remapped value mechanism in ConversionPatternRewriter");
604fec6c5acSUday Bondhugula }
605fec6c5acSUday Bondhugula } // namespace mlir
606