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" 10*a54f4eaeSMogball #include "mlir/Dialect/Arithmetic/IR/Arithmetic.h" 1126f93d9fSAlex Zinenko #include "mlir/Dialect/StandardOps/IR/Ops.h" 12473bdaf2SAlex Zinenko #include "mlir/Dialect/StandardOps/Transforms/FuncConversions.h" 13c0a6318dSMatthias Springer #include "mlir/Dialect/Tensor/IR/Tensor.h" 142bf423b0SRob Suderman #include "mlir/IR/Matchers.h" 15fec6c5acSUday Bondhugula #include "mlir/Pass/Pass.h" 16fec6c5acSUday Bondhugula #include "mlir/Transforms/DialectConversion.h" 1726f93d9fSAlex Zinenko #include "mlir/Transforms/FoldUtils.h" 18b6eb26fdSRiver Riddle #include "mlir/Transforms/GreedyPatternRewriteDriver.h" 199ba37b3bSJacques Pienaar 20fec6c5acSUday Bondhugula using namespace mlir; 217776b19eSStephen Neuendorffer using namespace test; 22fec6c5acSUday Bondhugula 23fec6c5acSUday Bondhugula // Native function for testing NativeCodeCall 24fec6c5acSUday Bondhugula static Value chooseOperand(Value input1, Value input2, BoolAttr choice) { 25fec6c5acSUday Bondhugula return choice.getValue() ? input1 : input2; 26fec6c5acSUday Bondhugula } 27fec6c5acSUday Bondhugula 2829429d1aSJacques Pienaar static void createOpI(PatternRewriter &rewriter, Location loc, Value input) { 2929429d1aSJacques Pienaar rewriter.create<OpI>(loc, input); 30fec6c5acSUday Bondhugula } 31fec6c5acSUday Bondhugula 32fec6c5acSUday Bondhugula static void handleNoResultOp(PatternRewriter &rewriter, 33fec6c5acSUday Bondhugula OpSymbolBindingNoResult op) { 34fec6c5acSUday Bondhugula // Turn the no result op to a one-result op. 35fec6c5acSUday Bondhugula rewriter.create<OpSymbolBindingB>(op.getLoc(), op.operand().getType(), 36fec6c5acSUday Bondhugula op.operand()); 37fec6c5acSUday Bondhugula } 38fec6c5acSUday Bondhugula 3934b5482bSChia-hung Duan static bool getFirstI32Result(Operation *op, Value &value) { 4034b5482bSChia-hung Duan if (!Type(op->getResult(0).getType()).isSignlessInteger(32)) 4134b5482bSChia-hung Duan return false; 4234b5482bSChia-hung Duan value = op->getResult(0); 4334b5482bSChia-hung Duan return true; 4434b5482bSChia-hung Duan } 4534b5482bSChia-hung Duan 4634b5482bSChia-hung Duan static Value bindNativeCodeCallResult(Value value) { return value; } 4734b5482bSChia-hung Duan 48d7314b3cSChia-hung Duan static SmallVector<Value, 2> bindMultipleNativeCodeCallResult(Value input1, 49d7314b3cSChia-hung Duan Value input2) { 50d7314b3cSChia-hung Duan return SmallVector<Value, 2>({input2, input1}); 51d7314b3cSChia-hung Duan } 52d7314b3cSChia-hung Duan 5301641197SAlexEichenberger // Test that natives calls are only called once during rewrites. 5401641197SAlexEichenberger // OpM_Test will return Pi, increased by 1 for each subsequent calls. 5501641197SAlexEichenberger // This let us check the number of times OpM_Test was called by inspecting 5601641197SAlexEichenberger // the returned value in the MLIR output. 5701641197SAlexEichenberger static int64_t opMIncreasingValue = 314159265; 5801641197SAlexEichenberger static Attribute OpMTest(PatternRewriter &rewriter, Value val) { 5901641197SAlexEichenberger int64_t i = opMIncreasingValue++; 6001641197SAlexEichenberger return rewriter.getIntegerAttr(rewriter.getIntegerType(32), i); 6101641197SAlexEichenberger } 6201641197SAlexEichenberger 63fec6c5acSUday Bondhugula namespace { 64fec6c5acSUday Bondhugula #include "TestPatterns.inc" 65fec6c5acSUday Bondhugula } // end anonymous namespace 66fec6c5acSUday Bondhugula 67fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 68c484c7ddSChia-hung Duan // Test Reduce Pattern Interface 69c484c7ddSChia-hung Duan //===----------------------------------------------------------------------===// 70c484c7ddSChia-hung Duan 717776b19eSStephen Neuendorffer void test::populateTestReductionPatterns(RewritePatternSet &patterns) { 72c484c7ddSChia-hung Duan populateWithGenerated(patterns); 73c484c7ddSChia-hung Duan } 74c484c7ddSChia-hung Duan 75c484c7ddSChia-hung Duan //===----------------------------------------------------------------------===// 76fec6c5acSUday Bondhugula // Canonicalizer Driver. 77fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 78fec6c5acSUday Bondhugula 79fec6c5acSUday Bondhugula namespace { 8026f93d9fSAlex Zinenko struct FoldingPattern : public RewritePattern { 8126f93d9fSAlex Zinenko public: 8226f93d9fSAlex Zinenko FoldingPattern(MLIRContext *context) 8326f93d9fSAlex Zinenko : RewritePattern(TestOpInPlaceFoldAnchor::getOperationName(), 8426f93d9fSAlex Zinenko /*benefit=*/1, context) {} 8526f93d9fSAlex Zinenko 8626f93d9fSAlex Zinenko LogicalResult matchAndRewrite(Operation *op, 8726f93d9fSAlex Zinenko PatternRewriter &rewriter) const override { 882b638ed5SKazuaki Ishizaki // Exercise OperationFolder API for a single-result operation that is folded 8926f93d9fSAlex Zinenko // upon construction. The operation being created through the folder has an 9026f93d9fSAlex Zinenko // in-place folder, and it should be still present in the output. 9126f93d9fSAlex Zinenko // Furthermore, the folder should not crash when attempting to recover the 92a23d0559SKazuaki Ishizaki // (unchanged) operation result. 9326f93d9fSAlex Zinenko OperationFolder folder(op->getContext()); 9426f93d9fSAlex Zinenko Value result = folder.create<TestOpInPlaceFold>( 9526f93d9fSAlex Zinenko rewriter, op->getLoc(), rewriter.getIntegerType(32), op->getOperand(0), 9626f93d9fSAlex Zinenko rewriter.getI32IntegerAttr(0)); 9726f93d9fSAlex Zinenko assert(result); 9826f93d9fSAlex Zinenko rewriter.replaceOp(op, result); 9926f93d9fSAlex Zinenko return success(); 10026f93d9fSAlex Zinenko } 10126f93d9fSAlex Zinenko }; 10226f93d9fSAlex Zinenko 103e4635e63SRiver Riddle /// This pattern creates a foldable operation at the entry point of the block. 104e4635e63SRiver Riddle /// This tests the situation where the operation folder will need to replace an 105e4635e63SRiver Riddle /// operation with a previously created constant that does not initially 106e4635e63SRiver Riddle /// dominate the operation to replace. 107e4635e63SRiver Riddle struct FolderInsertBeforePreviouslyFoldedConstantPattern 108e4635e63SRiver Riddle : public OpRewritePattern<TestCastOp> { 109e4635e63SRiver Riddle public: 110e4635e63SRiver Riddle using OpRewritePattern<TestCastOp>::OpRewritePattern; 111e4635e63SRiver Riddle 112e4635e63SRiver Riddle LogicalResult matchAndRewrite(TestCastOp op, 113e4635e63SRiver Riddle PatternRewriter &rewriter) const override { 114e4635e63SRiver Riddle if (!op->hasAttr("test_fold_before_previously_folded_op")) 115e4635e63SRiver Riddle return failure(); 116e4635e63SRiver Riddle rewriter.setInsertionPointToStart(op->getBlock()); 117e4635e63SRiver Riddle 118*a54f4eaeSMogball auto constOp = rewriter.create<arith::ConstantOp>( 119*a54f4eaeSMogball op.getLoc(), rewriter.getBoolAttr(true)); 120e4635e63SRiver Riddle rewriter.replaceOpWithNewOp<TestCastOp>(op, rewriter.getI32Type(), 121e4635e63SRiver Riddle Value(constOp)); 122e4635e63SRiver Riddle return success(); 123e4635e63SRiver Riddle } 124e4635e63SRiver Riddle }; 125e4635e63SRiver Riddle 12680aca1eaSRiver Riddle struct TestPatternDriver : public PassWrapper<TestPatternDriver, FunctionPass> { 127b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-patterns"; } 128b5e22e6dSMehdi Amini StringRef getDescription() const final { return "Run test dialect patterns"; } 129fec6c5acSUday Bondhugula void runOnFunction() override { 130dc4e913bSChris Lattner mlir::RewritePatternSet patterns(&getContext()); 1311d909c9aSChris Lattner populateWithGenerated(patterns); 132fec6c5acSUday Bondhugula 133fec6c5acSUday Bondhugula // Verify named pattern is generated with expected name. 134e4635e63SRiver Riddle patterns.add<FoldingPattern, TestNamedPatternRule, 135e4635e63SRiver Riddle FolderInsertBeforePreviouslyFoldedConstantPattern>( 136e4635e63SRiver Riddle &getContext()); 137fec6c5acSUday Bondhugula 138e21adfa3SRiver Riddle (void)applyPatternsAndFoldGreedily(getFunction(), std::move(patterns)); 139fec6c5acSUday Bondhugula } 140fec6c5acSUday Bondhugula }; 141fec6c5acSUday Bondhugula } // end anonymous namespace 142fec6c5acSUday Bondhugula 143fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 144fec6c5acSUday Bondhugula // ReturnType Driver. 145fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 146fec6c5acSUday Bondhugula 147fec6c5acSUday Bondhugula namespace { 148fec6c5acSUday Bondhugula // Generate ops for each instance where the type can be successfully inferred. 149fec6c5acSUday Bondhugula template <typename OpTy> 150fec6c5acSUday Bondhugula static void invokeCreateWithInferredReturnType(Operation *op) { 151fec6c5acSUday Bondhugula auto *context = op->getContext(); 152fec6c5acSUday Bondhugula auto fop = op->getParentOfType<FuncOp>(); 153fec6c5acSUday Bondhugula auto location = UnknownLoc::get(context); 154fec6c5acSUday Bondhugula OpBuilder b(op); 155fec6c5acSUday Bondhugula b.setInsertionPointAfter(op); 156fec6c5acSUday Bondhugula 157fec6c5acSUday Bondhugula // Use permutations of 2 args as operands. 158fec6c5acSUday Bondhugula assert(fop.getNumArguments() >= 2); 159fec6c5acSUday Bondhugula for (int i = 0, e = fop.getNumArguments(); i < e; ++i) { 160fec6c5acSUday Bondhugula for (int j = 0; j < e; ++j) { 161fec6c5acSUday Bondhugula std::array<Value, 2> values = {{fop.getArgument(i), fop.getArgument(j)}}; 162fec6c5acSUday Bondhugula SmallVector<Type, 2> inferredReturnTypes; 1635eae715aSJacques Pienaar if (succeeded(OpTy::inferReturnTypes( 1645eae715aSJacques Pienaar context, llvm::None, values, op->getAttrDictionary(), 1655eae715aSJacques Pienaar op->getRegions(), inferredReturnTypes))) { 166fec6c5acSUday Bondhugula OperationState state(location, OpTy::getOperationName()); 1679db53a18SRiver Riddle // TODO: Expand to regions. 168bb1d976fSAlex Zinenko OpTy::build(b, state, values, op->getAttrs()); 169fec6c5acSUday Bondhugula (void)b.createOperation(state); 170fec6c5acSUday Bondhugula } 171fec6c5acSUday Bondhugula } 172fec6c5acSUday Bondhugula } 173fec6c5acSUday Bondhugula } 174fec6c5acSUday Bondhugula 175fec6c5acSUday Bondhugula static void reifyReturnShape(Operation *op) { 176fec6c5acSUday Bondhugula OpBuilder b(op); 177fec6c5acSUday Bondhugula 178fec6c5acSUday Bondhugula // Use permutations of 2 args as operands. 179fec6c5acSUday Bondhugula auto shapedOp = cast<OpWithShapedTypeInferTypeInterfaceOp>(op); 180fec6c5acSUday Bondhugula SmallVector<Value, 2> shapes; 181851d02f6SWenyi Zhao if (failed(shapedOp.reifyReturnTypeShapes(b, op->getOperands(), shapes)) || 1829b051703SMaheshRavishankar !llvm::hasSingleElement(shapes)) 183fec6c5acSUday Bondhugula return; 1849b051703SMaheshRavishankar for (auto it : llvm::enumerate(shapes)) { 185fec6c5acSUday Bondhugula op->emitRemark() << "value " << it.index() << ": " 186fec6c5acSUday Bondhugula << it.value().getDefiningOp(); 187fec6c5acSUday Bondhugula } 1889b051703SMaheshRavishankar } 189fec6c5acSUday Bondhugula 19080aca1eaSRiver Riddle struct TestReturnTypeDriver 19180aca1eaSRiver Riddle : public PassWrapper<TestReturnTypeDriver, FunctionPass> { 192e2310704SJulian Gross void getDependentDialects(DialectRegistry ®istry) const override { 193c0a6318dSMatthias Springer registry.insert<tensor::TensorDialect>(); 194e2310704SJulian Gross } 195b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-return-type"; } 196b5e22e6dSMehdi Amini StringRef getDescription() const final { return "Run return type functions"; } 197e2310704SJulian Gross 198fec6c5acSUday Bondhugula void runOnFunction() override { 199fec6c5acSUday Bondhugula if (getFunction().getName() == "testCreateFunctions") { 200fec6c5acSUday Bondhugula std::vector<Operation *> ops; 201fec6c5acSUday Bondhugula // Collect ops to avoid triggering on inserted ops. 202fec6c5acSUday Bondhugula for (auto &op : getFunction().getBody().front()) 203fec6c5acSUday Bondhugula ops.push_back(&op); 204fec6c5acSUday Bondhugula // Generate test patterns for each, but skip terminator. 205fec6c5acSUday Bondhugula for (auto *op : llvm::makeArrayRef(ops).drop_back()) { 206fec6c5acSUday Bondhugula // Test create method of each of the Op classes below. The resultant 207fec6c5acSUday Bondhugula // output would be in reverse order underneath `op` from which 208fec6c5acSUday Bondhugula // the attributes and regions are used. 209fec6c5acSUday Bondhugula invokeCreateWithInferredReturnType<OpWithInferTypeInterfaceOp>(op); 210fec6c5acSUday Bondhugula invokeCreateWithInferredReturnType< 211fec6c5acSUday Bondhugula OpWithShapedTypeInferTypeInterfaceOp>(op); 212fec6c5acSUday Bondhugula }; 213fec6c5acSUday Bondhugula return; 214fec6c5acSUday Bondhugula } 215fec6c5acSUday Bondhugula if (getFunction().getName() == "testReifyFunctions") { 216fec6c5acSUday Bondhugula std::vector<Operation *> ops; 217fec6c5acSUday Bondhugula // Collect ops to avoid triggering on inserted ops. 218fec6c5acSUday Bondhugula for (auto &op : getFunction().getBody().front()) 219fec6c5acSUday Bondhugula if (isa<OpWithShapedTypeInferTypeInterfaceOp>(op)) 220fec6c5acSUday Bondhugula ops.push_back(&op); 221fec6c5acSUday Bondhugula // Generate test patterns for each, but skip terminator. 222fec6c5acSUday Bondhugula for (auto *op : ops) 223fec6c5acSUday Bondhugula reifyReturnShape(op); 224fec6c5acSUday Bondhugula } 225fec6c5acSUday Bondhugula } 226fec6c5acSUday Bondhugula }; 227fec6c5acSUday Bondhugula } // end anonymous namespace 228fec6c5acSUday Bondhugula 2299ba37b3bSJacques Pienaar namespace { 2309ba37b3bSJacques Pienaar struct TestDerivedAttributeDriver 2319ba37b3bSJacques Pienaar : public PassWrapper<TestDerivedAttributeDriver, FunctionPass> { 232b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-derived-attr"; } 233b5e22e6dSMehdi Amini StringRef getDescription() const final { 234b5e22e6dSMehdi Amini return "Run test derived attributes"; 235b5e22e6dSMehdi Amini } 2369ba37b3bSJacques Pienaar void runOnFunction() override; 2379ba37b3bSJacques Pienaar }; 2389ba37b3bSJacques Pienaar } // end anonymous namespace 2399ba37b3bSJacques Pienaar 2409ba37b3bSJacques Pienaar void TestDerivedAttributeDriver::runOnFunction() { 2419ba37b3bSJacques Pienaar getFunction().walk([](DerivedAttributeOpInterface dOp) { 2429ba37b3bSJacques Pienaar auto dAttr = dOp.materializeDerivedAttributes(); 2439ba37b3bSJacques Pienaar if (!dAttr) 2449ba37b3bSJacques Pienaar return; 2459ba37b3bSJacques Pienaar for (auto d : dAttr) 2469ba37b3bSJacques Pienaar dOp.emitRemark() << d.first << " = " << d.second; 2479ba37b3bSJacques Pienaar }); 2489ba37b3bSJacques Pienaar } 2499ba37b3bSJacques Pienaar 250fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 251fec6c5acSUday Bondhugula // Legalization Driver. 252fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 253fec6c5acSUday Bondhugula 254fec6c5acSUday Bondhugula namespace { 255fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 256fec6c5acSUday Bondhugula // Region-Block Rewrite Testing 257fec6c5acSUday Bondhugula 258fec6c5acSUday Bondhugula /// This pattern is a simple pattern that inlines the first region of a given 259fec6c5acSUday Bondhugula /// operation into the parent region. 260fec6c5acSUday Bondhugula struct TestRegionRewriteBlockMovement : public ConversionPattern { 261fec6c5acSUday Bondhugula TestRegionRewriteBlockMovement(MLIRContext *ctx) 262fec6c5acSUday Bondhugula : ConversionPattern("test.region", 1, ctx) {} 263fec6c5acSUday Bondhugula 264fec6c5acSUday Bondhugula LogicalResult 265fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 266fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 267fec6c5acSUday Bondhugula // Inline this region into the parent region. 268fec6c5acSUday Bondhugula auto &parentRegion = *op->getParentRegion(); 269b0750e2dSTres Popp auto &opRegion = op->getRegion(0); 270fec6c5acSUday Bondhugula if (op->getAttr("legalizer.should_clone")) 271b0750e2dSTres Popp rewriter.cloneRegionBefore(opRegion, parentRegion, parentRegion.end()); 272fec6c5acSUday Bondhugula else 273b0750e2dSTres Popp rewriter.inlineRegionBefore(opRegion, parentRegion, parentRegion.end()); 274b0750e2dSTres Popp 275b0750e2dSTres Popp if (op->getAttr("legalizer.erase_old_blocks")) { 276b0750e2dSTres Popp while (!opRegion.empty()) 277b0750e2dSTres Popp rewriter.eraseBlock(&opRegion.front()); 278b0750e2dSTres Popp } 279fec6c5acSUday Bondhugula 280fec6c5acSUday Bondhugula // Drop this operation. 281fec6c5acSUday Bondhugula rewriter.eraseOp(op); 282fec6c5acSUday Bondhugula return success(); 283fec6c5acSUday Bondhugula } 284fec6c5acSUday Bondhugula }; 285fec6c5acSUday Bondhugula /// This pattern is a simple pattern that generates a region containing an 286fec6c5acSUday Bondhugula /// illegal operation. 287fec6c5acSUday Bondhugula struct TestRegionRewriteUndo : public RewritePattern { 288fec6c5acSUday Bondhugula TestRegionRewriteUndo(MLIRContext *ctx) 289fec6c5acSUday Bondhugula : RewritePattern("test.region_builder", 1, ctx) {} 290fec6c5acSUday Bondhugula 291fec6c5acSUday Bondhugula LogicalResult matchAndRewrite(Operation *op, 292fec6c5acSUday Bondhugula PatternRewriter &rewriter) const final { 293fec6c5acSUday Bondhugula // Create the region operation with an entry block containing arguments. 294fec6c5acSUday Bondhugula OperationState newRegion(op->getLoc(), "test.region"); 295fec6c5acSUday Bondhugula newRegion.addRegion(); 296fec6c5acSUday Bondhugula auto *regionOp = rewriter.createOperation(newRegion); 297fec6c5acSUday Bondhugula auto *entryBlock = rewriter.createBlock(®ionOp->getRegion(0)); 298fec6c5acSUday Bondhugula entryBlock->addArgument(rewriter.getIntegerType(64)); 299fec6c5acSUday Bondhugula 300fec6c5acSUday Bondhugula // Add an explicitly illegal operation to ensure the conversion fails. 301fec6c5acSUday Bondhugula rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getIntegerType(32)); 302fec6c5acSUday Bondhugula rewriter.create<TestValidOp>(op->getLoc(), ArrayRef<Value>()); 303fec6c5acSUday Bondhugula 304fec6c5acSUday Bondhugula // Drop this operation. 305fec6c5acSUday Bondhugula rewriter.eraseOp(op); 306fec6c5acSUday Bondhugula return success(); 307fec6c5acSUday Bondhugula } 308fec6c5acSUday Bondhugula }; 309f27f1e8cSAlex Zinenko /// A simple pattern that creates a block at the end of the parent region of the 310f27f1e8cSAlex Zinenko /// matched operation. 311f27f1e8cSAlex Zinenko struct TestCreateBlock : public RewritePattern { 312f27f1e8cSAlex Zinenko TestCreateBlock(MLIRContext *ctx) 313f27f1e8cSAlex Zinenko : RewritePattern("test.create_block", /*benefit=*/1, ctx) {} 314f27f1e8cSAlex Zinenko 315f27f1e8cSAlex Zinenko LogicalResult matchAndRewrite(Operation *op, 316f27f1e8cSAlex Zinenko PatternRewriter &rewriter) const final { 317f27f1e8cSAlex Zinenko Region ®ion = *op->getParentRegion(); 318f27f1e8cSAlex Zinenko Type i32Type = rewriter.getIntegerType(32); 319f27f1e8cSAlex Zinenko rewriter.createBlock(®ion, region.end(), {i32Type, i32Type}); 320f27f1e8cSAlex Zinenko rewriter.create<TerminatorOp>(op->getLoc()); 321f27f1e8cSAlex Zinenko rewriter.replaceOp(op, {}); 322f27f1e8cSAlex Zinenko return success(); 323f27f1e8cSAlex Zinenko } 324f27f1e8cSAlex Zinenko }; 325f27f1e8cSAlex Zinenko 326a23d0559SKazuaki Ishizaki /// A simple pattern that creates a block containing an invalid operation in 327f27f1e8cSAlex Zinenko /// order to trigger the block creation undo mechanism. 328f27f1e8cSAlex Zinenko struct TestCreateIllegalBlock : public RewritePattern { 329f27f1e8cSAlex Zinenko TestCreateIllegalBlock(MLIRContext *ctx) 330f27f1e8cSAlex Zinenko : RewritePattern("test.create_illegal_block", /*benefit=*/1, ctx) {} 331f27f1e8cSAlex Zinenko 332f27f1e8cSAlex Zinenko LogicalResult matchAndRewrite(Operation *op, 333f27f1e8cSAlex Zinenko PatternRewriter &rewriter) const final { 334f27f1e8cSAlex Zinenko Region ®ion = *op->getParentRegion(); 335f27f1e8cSAlex Zinenko Type i32Type = rewriter.getIntegerType(32); 336f27f1e8cSAlex Zinenko rewriter.createBlock(®ion, region.end(), {i32Type, i32Type}); 337f27f1e8cSAlex Zinenko // Create an illegal op to ensure the conversion fails. 338f27f1e8cSAlex Zinenko rewriter.create<ILLegalOpF>(op->getLoc(), i32Type); 339f27f1e8cSAlex Zinenko rewriter.create<TerminatorOp>(op->getLoc()); 340f27f1e8cSAlex Zinenko rewriter.replaceOp(op, {}); 341f27f1e8cSAlex Zinenko return success(); 342f27f1e8cSAlex Zinenko } 343f27f1e8cSAlex Zinenko }; 344fec6c5acSUday Bondhugula 3450816de16SRiver Riddle /// A simple pattern that tests the undo mechanism when replacing the uses of a 3460816de16SRiver Riddle /// block argument. 3470816de16SRiver Riddle struct TestUndoBlockArgReplace : public ConversionPattern { 3480816de16SRiver Riddle TestUndoBlockArgReplace(MLIRContext *ctx) 3490816de16SRiver Riddle : ConversionPattern("test.undo_block_arg_replace", /*benefit=*/1, ctx) {} 3500816de16SRiver Riddle 3510816de16SRiver Riddle LogicalResult 3520816de16SRiver Riddle matchAndRewrite(Operation *op, ArrayRef<Value> operands, 3530816de16SRiver Riddle ConversionPatternRewriter &rewriter) const final { 3540816de16SRiver Riddle auto illegalOp = 3550816de16SRiver Riddle rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getF32Type()); 356e2b71610SRahul Joshi rewriter.replaceUsesOfBlockArgument(op->getRegion(0).getArgument(0), 3570816de16SRiver Riddle illegalOp); 3580816de16SRiver Riddle rewriter.updateRootInPlace(op, [] {}); 3590816de16SRiver Riddle return success(); 3600816de16SRiver Riddle } 3610816de16SRiver Riddle }; 3620816de16SRiver Riddle 363df48026bSAlex Zinenko /// A rewrite pattern that tests the undo mechanism when erasing a block. 364df48026bSAlex Zinenko struct TestUndoBlockErase : public ConversionPattern { 365df48026bSAlex Zinenko TestUndoBlockErase(MLIRContext *ctx) 366df48026bSAlex Zinenko : ConversionPattern("test.undo_block_erase", /*benefit=*/1, ctx) {} 367df48026bSAlex Zinenko 368df48026bSAlex Zinenko LogicalResult 369df48026bSAlex Zinenko matchAndRewrite(Operation *op, ArrayRef<Value> operands, 370df48026bSAlex Zinenko ConversionPatternRewriter &rewriter) const final { 371df48026bSAlex Zinenko Block *secondBlock = &*std::next(op->getRegion(0).begin()); 372df48026bSAlex Zinenko rewriter.setInsertionPointToStart(secondBlock); 373df48026bSAlex Zinenko rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getF32Type()); 374df48026bSAlex Zinenko rewriter.eraseBlock(secondBlock); 375df48026bSAlex Zinenko rewriter.updateRootInPlace(op, [] {}); 376df48026bSAlex Zinenko return success(); 377df48026bSAlex Zinenko } 378df48026bSAlex Zinenko }; 379df48026bSAlex Zinenko 380fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 381fec6c5acSUday Bondhugula // Type-Conversion Rewrite Testing 382fec6c5acSUday Bondhugula 383fec6c5acSUday Bondhugula /// This patterns erases a region operation that has had a type conversion. 384fec6c5acSUday Bondhugula struct TestDropOpSignatureConversion : public ConversionPattern { 385fec6c5acSUday Bondhugula TestDropOpSignatureConversion(MLIRContext *ctx, TypeConverter &converter) 38676f3c2f3SRiver Riddle : ConversionPattern(converter, "test.drop_region_op", 1, ctx) {} 387fec6c5acSUday Bondhugula LogicalResult 388fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 389fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const override { 390fec6c5acSUday Bondhugula Region ®ion = op->getRegion(0); 391fec6c5acSUday Bondhugula Block *entry = ®ion.front(); 392fec6c5acSUday Bondhugula 393fec6c5acSUday Bondhugula // Convert the original entry arguments. 3948d67d187SRiver Riddle TypeConverter &converter = *getTypeConverter(); 395fec6c5acSUday Bondhugula TypeConverter::SignatureConversion result(entry->getNumArguments()); 3968d67d187SRiver Riddle if (failed(converter.convertSignatureArgs(entry->getArgumentTypes(), 3978d67d187SRiver Riddle result)) || 3988d67d187SRiver Riddle failed(rewriter.convertRegionTypes(®ion, converter, &result))) 399fec6c5acSUday Bondhugula return failure(); 400fec6c5acSUday Bondhugula 401fec6c5acSUday Bondhugula // Convert the region signature and just drop the operation. 402fec6c5acSUday Bondhugula rewriter.eraseOp(op); 403fec6c5acSUday Bondhugula return success(); 404fec6c5acSUday Bondhugula } 405fec6c5acSUday Bondhugula }; 406fec6c5acSUday Bondhugula /// This pattern simply updates the operands of the given operation. 407fec6c5acSUday Bondhugula struct TestPassthroughInvalidOp : public ConversionPattern { 408fec6c5acSUday Bondhugula TestPassthroughInvalidOp(MLIRContext *ctx) 409fec6c5acSUday Bondhugula : ConversionPattern("test.invalid", 1, ctx) {} 410fec6c5acSUday Bondhugula LogicalResult 411fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 412fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 413fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestValidOp>(op, llvm::None, operands, 414fec6c5acSUday Bondhugula llvm::None); 415fec6c5acSUday Bondhugula return success(); 416fec6c5acSUday Bondhugula } 417fec6c5acSUday Bondhugula }; 418fec6c5acSUday Bondhugula /// This pattern handles the case of a split return value. 419fec6c5acSUday Bondhugula struct TestSplitReturnType : public ConversionPattern { 420fec6c5acSUday Bondhugula TestSplitReturnType(MLIRContext *ctx) 421fec6c5acSUday Bondhugula : ConversionPattern("test.return", 1, ctx) {} 422fec6c5acSUday Bondhugula LogicalResult 423fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 424fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 425fec6c5acSUday Bondhugula // Check for a return of F32. 426fec6c5acSUday Bondhugula if (op->getNumOperands() != 1 || !op->getOperand(0).getType().isF32()) 427fec6c5acSUday Bondhugula return failure(); 428fec6c5acSUday Bondhugula 429fec6c5acSUday Bondhugula // Check if the first operation is a cast operation, if it is we use the 430fec6c5acSUday Bondhugula // results directly. 431fec6c5acSUday Bondhugula auto *defOp = operands[0].getDefiningOp(); 432fec6c5acSUday Bondhugula if (auto packerOp = llvm::dyn_cast_or_null<TestCastOp>(defOp)) { 433fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestReturnOp>(op, packerOp.getOperands()); 434fec6c5acSUday Bondhugula return success(); 435fec6c5acSUday Bondhugula } 436fec6c5acSUday Bondhugula 437fec6c5acSUday Bondhugula // Otherwise, fail to match. 438fec6c5acSUday Bondhugula return failure(); 439fec6c5acSUday Bondhugula } 440fec6c5acSUday Bondhugula }; 441fec6c5acSUday Bondhugula 442fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 443fec6c5acSUday Bondhugula // Multi-Level Type-Conversion Rewrite Testing 444fec6c5acSUday Bondhugula struct TestChangeProducerTypeI32ToF32 : public ConversionPattern { 445fec6c5acSUday Bondhugula TestChangeProducerTypeI32ToF32(MLIRContext *ctx) 446fec6c5acSUday Bondhugula : ConversionPattern("test.type_producer", 1, ctx) {} 447fec6c5acSUday Bondhugula LogicalResult 448fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 449fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 450fec6c5acSUday Bondhugula // If the type is I32, change the type to F32. 451fec6c5acSUday Bondhugula if (!Type(*op->result_type_begin()).isSignlessInteger(32)) 452fec6c5acSUday Bondhugula return failure(); 453fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getF32Type()); 454fec6c5acSUday Bondhugula return success(); 455fec6c5acSUday Bondhugula } 456fec6c5acSUday Bondhugula }; 457fec6c5acSUday Bondhugula struct TestChangeProducerTypeF32ToF64 : public ConversionPattern { 458fec6c5acSUday Bondhugula TestChangeProducerTypeF32ToF64(MLIRContext *ctx) 459fec6c5acSUday Bondhugula : ConversionPattern("test.type_producer", 1, ctx) {} 460fec6c5acSUday Bondhugula LogicalResult 461fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 462fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 463fec6c5acSUday Bondhugula // If the type is F32, change the type to F64. 464fec6c5acSUday Bondhugula if (!Type(*op->result_type_begin()).isF32()) 465fec6c5acSUday Bondhugula return rewriter.notifyMatchFailure(op, "expected single f32 operand"); 466fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getF64Type()); 467fec6c5acSUday Bondhugula return success(); 468fec6c5acSUday Bondhugula } 469fec6c5acSUday Bondhugula }; 470fec6c5acSUday Bondhugula struct TestChangeProducerTypeF32ToInvalid : public ConversionPattern { 471fec6c5acSUday Bondhugula TestChangeProducerTypeF32ToInvalid(MLIRContext *ctx) 472fec6c5acSUday Bondhugula : ConversionPattern("test.type_producer", 10, ctx) {} 473fec6c5acSUday Bondhugula LogicalResult 474fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 475fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 476fec6c5acSUday Bondhugula // Always convert to B16, even though it is not a legal type. This tests 477fec6c5acSUday Bondhugula // that values are unmapped correctly. 478fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, rewriter.getBF16Type()); 479fec6c5acSUday Bondhugula return success(); 480fec6c5acSUday Bondhugula } 481fec6c5acSUday Bondhugula }; 482fec6c5acSUday Bondhugula struct TestUpdateConsumerType : public ConversionPattern { 483fec6c5acSUday Bondhugula TestUpdateConsumerType(MLIRContext *ctx) 484fec6c5acSUday Bondhugula : ConversionPattern("test.type_consumer", 1, ctx) {} 485fec6c5acSUday Bondhugula LogicalResult 486fec6c5acSUday Bondhugula matchAndRewrite(Operation *op, ArrayRef<Value> operands, 487fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const final { 488fec6c5acSUday Bondhugula // Verify that the incoming operand has been successfully remapped to F64. 489fec6c5acSUday Bondhugula if (!operands[0].getType().isF64()) 490fec6c5acSUday Bondhugula return failure(); 491fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<TestTypeConsumerOp>(op, operands[0]); 492fec6c5acSUday Bondhugula return success(); 493fec6c5acSUday Bondhugula } 494fec6c5acSUday Bondhugula }; 495fec6c5acSUday Bondhugula 496fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 497fec6c5acSUday Bondhugula // Non-Root Replacement Rewrite Testing 498fec6c5acSUday Bondhugula /// This pattern generates an invalid operation, but replaces it before the 499fec6c5acSUday Bondhugula /// pattern is finished. This checks that we don't need to legalize the 500fec6c5acSUday Bondhugula /// temporary op. 501fec6c5acSUday Bondhugula struct TestNonRootReplacement : public RewritePattern { 502fec6c5acSUday Bondhugula TestNonRootReplacement(MLIRContext *ctx) 503fec6c5acSUday Bondhugula : RewritePattern("test.replace_non_root", 1, ctx) {} 504fec6c5acSUday Bondhugula 505fec6c5acSUday Bondhugula LogicalResult matchAndRewrite(Operation *op, 506fec6c5acSUday Bondhugula PatternRewriter &rewriter) const final { 507fec6c5acSUday Bondhugula auto resultType = *op->result_type_begin(); 508fec6c5acSUday Bondhugula auto illegalOp = rewriter.create<ILLegalOpF>(op->getLoc(), resultType); 509fec6c5acSUday Bondhugula auto legalOp = rewriter.create<LegalOpB>(op->getLoc(), resultType); 510fec6c5acSUday Bondhugula 511fec6c5acSUday Bondhugula rewriter.replaceOp(illegalOp, {legalOp}); 512fec6c5acSUday Bondhugula rewriter.replaceOp(op, {illegalOp}); 513fec6c5acSUday Bondhugula return success(); 514fec6c5acSUday Bondhugula } 515fec6c5acSUday Bondhugula }; 516bd1ccfe6SRiver Riddle 517bd1ccfe6SRiver Riddle //===----------------------------------------------------------------------===// 518bd1ccfe6SRiver Riddle // Recursive Rewrite Testing 519bd1ccfe6SRiver Riddle /// This pattern is applied to the same operation multiple times, but has a 520bd1ccfe6SRiver Riddle /// bounded recursion. 521bd1ccfe6SRiver Riddle struct TestBoundedRecursiveRewrite 522bd1ccfe6SRiver Riddle : public OpRewritePattern<TestRecursiveRewriteOp> { 5232257e4a7SRiver Riddle using OpRewritePattern<TestRecursiveRewriteOp>::OpRewritePattern; 5242257e4a7SRiver Riddle 5252257e4a7SRiver Riddle void initialize() { 526b99bd771SRiver Riddle // The conversion target handles bounding the recursion of this pattern. 527b99bd771SRiver Riddle setHasBoundedRewriteRecursion(); 528b99bd771SRiver Riddle } 529bd1ccfe6SRiver Riddle 530bd1ccfe6SRiver Riddle LogicalResult matchAndRewrite(TestRecursiveRewriteOp op, 531bd1ccfe6SRiver Riddle PatternRewriter &rewriter) const final { 532bd1ccfe6SRiver Riddle // Decrement the depth of the op in-place. 533bd1ccfe6SRiver Riddle rewriter.updateRootInPlace(op, [&] { 5341ffc1aaaSChristian Sigg op->setAttr("depth", rewriter.getI64IntegerAttr(op.depth() - 1)); 535bd1ccfe6SRiver Riddle }); 536bd1ccfe6SRiver Riddle return success(); 537bd1ccfe6SRiver Riddle } 538bd1ccfe6SRiver Riddle }; 5395d5df06aSAlex Zinenko 5405d5df06aSAlex Zinenko struct TestNestedOpCreationUndoRewrite 5415d5df06aSAlex Zinenko : public OpRewritePattern<IllegalOpWithRegionAnchor> { 5425d5df06aSAlex Zinenko using OpRewritePattern<IllegalOpWithRegionAnchor>::OpRewritePattern; 5435d5df06aSAlex Zinenko 5445d5df06aSAlex Zinenko LogicalResult matchAndRewrite(IllegalOpWithRegionAnchor op, 5455d5df06aSAlex Zinenko PatternRewriter &rewriter) const final { 5465d5df06aSAlex Zinenko // rewriter.replaceOpWithNewOp<IllegalOpWithRegion>(op); 5475d5df06aSAlex Zinenko rewriter.replaceOpWithNewOp<IllegalOpWithRegion>(op); 5485d5df06aSAlex Zinenko return success(); 5495d5df06aSAlex Zinenko }; 5505d5df06aSAlex Zinenko }; 551a360a978SMehdi Amini 552a360a978SMehdi Amini // This pattern matches `test.blackhole` and delete this op and its producer. 553a360a978SMehdi Amini struct TestReplaceEraseOp : public OpRewritePattern<BlackHoleOp> { 554a360a978SMehdi Amini using OpRewritePattern<BlackHoleOp>::OpRewritePattern; 555a360a978SMehdi Amini 556a360a978SMehdi Amini LogicalResult matchAndRewrite(BlackHoleOp op, 557a360a978SMehdi Amini PatternRewriter &rewriter) const final { 558a360a978SMehdi Amini Operation *producer = op.getOperand().getDefiningOp(); 559a360a978SMehdi Amini // Always erase the user before the producer, the framework should handle 560a360a978SMehdi Amini // this correctly. 561a360a978SMehdi Amini rewriter.eraseOp(op); 562a360a978SMehdi Amini rewriter.eraseOp(producer); 563a360a978SMehdi Amini return success(); 564a360a978SMehdi Amini }; 565a360a978SMehdi Amini }; 566ec03bbe8SVladislav Vinogradov 567ec03bbe8SVladislav Vinogradov // This pattern replaces explicitly illegal op with explicitly legal op, 568ec03bbe8SVladislav Vinogradov // but in addition creates unregistered operation. 569ec03bbe8SVladislav Vinogradov struct TestCreateUnregisteredOp : public OpRewritePattern<ILLegalOpG> { 570ec03bbe8SVladislav Vinogradov using OpRewritePattern<ILLegalOpG>::OpRewritePattern; 571ec03bbe8SVladislav Vinogradov 572ec03bbe8SVladislav Vinogradov LogicalResult matchAndRewrite(ILLegalOpG op, 573ec03bbe8SVladislav Vinogradov PatternRewriter &rewriter) const final { 574ec03bbe8SVladislav Vinogradov IntegerAttr attr = rewriter.getI32IntegerAttr(0); 575ec03bbe8SVladislav Vinogradov Value val = rewriter.create<ConstantOp>(op->getLoc(), attr); 576ec03bbe8SVladislav Vinogradov rewriter.replaceOpWithNewOp<LegalOpC>(op, val); 577ec03bbe8SVladislav Vinogradov return success(); 578ec03bbe8SVladislav Vinogradov }; 579ec03bbe8SVladislav Vinogradov }; 580fec6c5acSUday Bondhugula } // namespace 581fec6c5acSUday Bondhugula 582fec6c5acSUday Bondhugula namespace { 583fec6c5acSUday Bondhugula struct TestTypeConverter : public TypeConverter { 584fec6c5acSUday Bondhugula using TypeConverter::TypeConverter; 5855c5dafc5SAlex Zinenko TestTypeConverter() { 5865c5dafc5SAlex Zinenko addConversion(convertType); 5874589dd92SRiver Riddle addArgumentMaterialization(materializeCast); 5884589dd92SRiver Riddle addSourceMaterialization(materializeCast); 5897cc79984SVladislav Vinogradov 5907cc79984SVladislav Vinogradov /// Materialize the cast for one-to-one conversion from i64 to f64. 5917cc79984SVladislav Vinogradov const auto materializeOneToOneCast = 5927cc79984SVladislav Vinogradov [](OpBuilder &builder, IntegerType resultType, ValueRange inputs, 5937cc79984SVladislav Vinogradov Location loc) -> Optional<Value> { 5947cc79984SVladislav Vinogradov if (resultType.getWidth() == 42 && inputs.size() == 1) 5957cc79984SVladislav Vinogradov return builder.create<TestCastOp>(loc, resultType, inputs).getResult(); 5967cc79984SVladislav Vinogradov return llvm::None; 5977cc79984SVladislav Vinogradov }; 5987cc79984SVladislav Vinogradov addArgumentMaterialization(materializeOneToOneCast); 5995c5dafc5SAlex Zinenko } 600fec6c5acSUday Bondhugula 601fec6c5acSUday Bondhugula static LogicalResult convertType(Type t, SmallVectorImpl<Type> &results) { 602fec6c5acSUday Bondhugula // Drop I16 types. 603fec6c5acSUday Bondhugula if (t.isSignlessInteger(16)) 604fec6c5acSUday Bondhugula return success(); 605fec6c5acSUday Bondhugula 606fec6c5acSUday Bondhugula // Convert I64 to F64. 607fec6c5acSUday Bondhugula if (t.isSignlessInteger(64)) { 608fec6c5acSUday Bondhugula results.push_back(FloatType::getF64(t.getContext())); 609fec6c5acSUday Bondhugula return success(); 610fec6c5acSUday Bondhugula } 611fec6c5acSUday Bondhugula 6125c5dafc5SAlex Zinenko // Convert I42 to I43. 6135c5dafc5SAlex Zinenko if (t.isInteger(42)) { 6141b97cdf8SRiver Riddle results.push_back(IntegerType::get(t.getContext(), 43)); 6155c5dafc5SAlex Zinenko return success(); 6165c5dafc5SAlex Zinenko } 6175c5dafc5SAlex Zinenko 618fec6c5acSUday Bondhugula // Split F32 into F16,F16. 619fec6c5acSUday Bondhugula if (t.isF32()) { 620fec6c5acSUday Bondhugula results.assign(2, FloatType::getF16(t.getContext())); 621fec6c5acSUday Bondhugula return success(); 622fec6c5acSUday Bondhugula } 623fec6c5acSUday Bondhugula 624fec6c5acSUday Bondhugula // Otherwise, convert the type directly. 625fec6c5acSUday Bondhugula results.push_back(t); 626fec6c5acSUday Bondhugula return success(); 627fec6c5acSUday Bondhugula } 628fec6c5acSUday Bondhugula 6295c5dafc5SAlex Zinenko /// Hook for materializing a conversion. This is necessary because we generate 6305c5dafc5SAlex Zinenko /// 1->N type mappings. 6314589dd92SRiver Riddle static Optional<Value> materializeCast(OpBuilder &builder, Type resultType, 6324589dd92SRiver Riddle ValueRange inputs, Location loc) { 6335c5dafc5SAlex Zinenko if (inputs.size() == 1) 6345c5dafc5SAlex Zinenko return inputs[0]; 6354589dd92SRiver Riddle return builder.create<TestCastOp>(loc, resultType, inputs).getResult(); 6365c5dafc5SAlex Zinenko } 637fec6c5acSUday Bondhugula }; 638fec6c5acSUday Bondhugula 639fec6c5acSUday Bondhugula struct TestLegalizePatternDriver 64080aca1eaSRiver Riddle : public PassWrapper<TestLegalizePatternDriver, OperationPass<ModuleOp>> { 641b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-legalize-patterns"; } 642b5e22e6dSMehdi Amini StringRef getDescription() const final { 643b5e22e6dSMehdi Amini return "Run test dialect legalization patterns"; 644b5e22e6dSMehdi Amini } 645fec6c5acSUday Bondhugula /// The mode of conversion to use with the driver. 646fec6c5acSUday Bondhugula enum class ConversionMode { Analysis, Full, Partial }; 647fec6c5acSUday Bondhugula 648fec6c5acSUday Bondhugula TestLegalizePatternDriver(ConversionMode mode) : mode(mode) {} 649fec6c5acSUday Bondhugula 650ec03bbe8SVladislav Vinogradov void getDependentDialects(DialectRegistry ®istry) const override { 651ec03bbe8SVladislav Vinogradov registry.insert<StandardOpsDialect>(); 652ec03bbe8SVladislav Vinogradov } 653ec03bbe8SVladislav Vinogradov 654722f909fSRiver Riddle void runOnOperation() override { 655fec6c5acSUday Bondhugula TestTypeConverter converter; 656dc4e913bSChris Lattner mlir::RewritePatternSet patterns(&getContext()); 6571d909c9aSChris Lattner populateWithGenerated(patterns); 658dc4e913bSChris Lattner patterns 659dc4e913bSChris Lattner .add<TestRegionRewriteBlockMovement, TestRegionRewriteUndo, 660dc4e913bSChris Lattner TestCreateBlock, TestCreateIllegalBlock, TestUndoBlockArgReplace, 661dc4e913bSChris Lattner TestUndoBlockErase, TestPassthroughInvalidOp, TestSplitReturnType, 662df48026bSAlex Zinenko TestChangeProducerTypeI32ToF32, TestChangeProducerTypeF32ToF64, 663fec6c5acSUday Bondhugula TestChangeProducerTypeF32ToInvalid, TestUpdateConsumerType, 6645d5df06aSAlex Zinenko TestNonRootReplacement, TestBoundedRecursiveRewrite, 665ec03bbe8SVladislav Vinogradov TestNestedOpCreationUndoRewrite, TestReplaceEraseOp, 666ec03bbe8SVladislav Vinogradov TestCreateUnregisteredOp>(&getContext()); 667dc4e913bSChris Lattner patterns.add<TestDropOpSignatureConversion>(&getContext(), converter); 6683a506b31SChris Lattner mlir::populateFuncOpTypeConversionPattern(patterns, converter); 6693a506b31SChris Lattner mlir::populateCallOpTypeConversionPattern(patterns, converter); 670fec6c5acSUday Bondhugula 671fec6c5acSUday Bondhugula // Define the conversion target used for the test. 672fec6c5acSUday Bondhugula ConversionTarget target(getContext()); 673973ddb7dSMehdi Amini target.addLegalOp<ModuleOp>(); 674ec03bbe8SVladislav Vinogradov target.addLegalOp<LegalOpA, LegalOpB, LegalOpC, TestCastOp, TestValidOp, 675f27f1e8cSAlex Zinenko TerminatorOp>(); 676fec6c5acSUday Bondhugula target 677fec6c5acSUday Bondhugula .addIllegalOp<ILLegalOpF, TestRegionBuilderOp, TestOpWithRegionFold>(); 678fec6c5acSUday Bondhugula target.addDynamicallyLegalOp<TestReturnOp>([](TestReturnOp op) { 679fec6c5acSUday Bondhugula // Don't allow F32 operands. 680fec6c5acSUday Bondhugula return llvm::none_of(op.getOperandTypes(), 681fec6c5acSUday Bondhugula [](Type type) { return type.isF32(); }); 682fec6c5acSUday Bondhugula }); 6838d67d187SRiver Riddle target.addDynamicallyLegalOp<FuncOp>([&](FuncOp op) { 6848d67d187SRiver Riddle return converter.isSignatureLegal(op.getType()) && 6858d67d187SRiver Riddle converter.isLegal(&op.getBody()); 6868d67d187SRiver Riddle }); 687fec6c5acSUday Bondhugula 688*a54f4eaeSMogball // TestCreateUnregisteredOp creates `arith.constant` operation, 689ec03bbe8SVladislav Vinogradov // which was not added to target intentionally to test 690ec03bbe8SVladislav Vinogradov // correct error code from conversion driver. 691ec03bbe8SVladislav Vinogradov target.addDynamicallyLegalOp<ILLegalOpG>([](ILLegalOpG) { return false; }); 692ec03bbe8SVladislav Vinogradov 693fec6c5acSUday Bondhugula // Expect the type_producer/type_consumer operations to only operate on f64. 694fec6c5acSUday Bondhugula target.addDynamicallyLegalOp<TestTypeProducerOp>( 695fec6c5acSUday Bondhugula [](TestTypeProducerOp op) { return op.getType().isF64(); }); 696fec6c5acSUday Bondhugula target.addDynamicallyLegalOp<TestTypeConsumerOp>([](TestTypeConsumerOp op) { 697fec6c5acSUday Bondhugula return op.getOperand().getType().isF64(); 698fec6c5acSUday Bondhugula }); 699fec6c5acSUday Bondhugula 700fec6c5acSUday Bondhugula // Check support for marking certain operations as recursively legal. 701fec6c5acSUday Bondhugula target.markOpRecursivelyLegal<FuncOp, ModuleOp>([](Operation *op) { 702fec6c5acSUday Bondhugula return static_cast<bool>( 703fec6c5acSUday Bondhugula op->getAttrOfType<UnitAttr>("test.recursively_legal")); 704fec6c5acSUday Bondhugula }); 705fec6c5acSUday Bondhugula 706bd1ccfe6SRiver Riddle // Mark the bound recursion operation as dynamically legal. 707bd1ccfe6SRiver Riddle target.addDynamicallyLegalOp<TestRecursiveRewriteOp>( 708bd1ccfe6SRiver Riddle [](TestRecursiveRewriteOp op) { return op.depth() == 0; }); 709bd1ccfe6SRiver Riddle 710fec6c5acSUday Bondhugula // Handle a partial conversion. 711fec6c5acSUday Bondhugula if (mode == ConversionMode::Partial) { 7128de482eaSLucy Fox DenseSet<Operation *> unlegalizedOps; 713ec03bbe8SVladislav Vinogradov if (failed(applyPartialConversion( 714ec03bbe8SVladislav Vinogradov getOperation(), target, std::move(patterns), &unlegalizedOps))) { 715ec03bbe8SVladislav Vinogradov getOperation()->emitRemark() << "applyPartialConversion failed"; 716ec03bbe8SVladislav Vinogradov } 7178de482eaSLucy Fox // Emit remarks for each legalizable operation. 7188de482eaSLucy Fox for (auto *op : unlegalizedOps) 7198de482eaSLucy Fox op->emitRemark() << "op '" << op->getName() << "' is not legalizable"; 720fec6c5acSUday Bondhugula return; 721fec6c5acSUday Bondhugula } 722fec6c5acSUday Bondhugula 723fec6c5acSUday Bondhugula // Handle a full conversion. 724fec6c5acSUday Bondhugula if (mode == ConversionMode::Full) { 725fec6c5acSUday Bondhugula // Check support for marking unknown operations as dynamically legal. 726fec6c5acSUday Bondhugula target.markUnknownOpDynamicallyLegal([](Operation *op) { 727fec6c5acSUday Bondhugula return (bool)op->getAttrOfType<UnitAttr>("test.dynamically_legal"); 728fec6c5acSUday Bondhugula }); 729fec6c5acSUday Bondhugula 730ec03bbe8SVladislav Vinogradov if (failed(applyFullConversion(getOperation(), target, 731ec03bbe8SVladislav Vinogradov std::move(patterns)))) { 732ec03bbe8SVladislav Vinogradov getOperation()->emitRemark() << "applyFullConversion failed"; 733ec03bbe8SVladislav Vinogradov } 734fec6c5acSUday Bondhugula return; 735fec6c5acSUday Bondhugula } 736fec6c5acSUday Bondhugula 737fec6c5acSUday Bondhugula // Otherwise, handle an analysis conversion. 738fec6c5acSUday Bondhugula assert(mode == ConversionMode::Analysis); 739fec6c5acSUday Bondhugula 740fec6c5acSUday Bondhugula // Analyze the convertible operations. 741fec6c5acSUday Bondhugula DenseSet<Operation *> legalizedOps; 7423fffffa8SRiver Riddle if (failed(applyAnalysisConversion(getOperation(), target, 7433fffffa8SRiver Riddle std::move(patterns), legalizedOps))) 744fec6c5acSUday Bondhugula return signalPassFailure(); 745fec6c5acSUday Bondhugula 746fec6c5acSUday Bondhugula // Emit remarks for each legalizable operation. 747fec6c5acSUday Bondhugula for (auto *op : legalizedOps) 748fec6c5acSUday Bondhugula op->emitRemark() << "op '" << op->getName() << "' is legalizable"; 749fec6c5acSUday Bondhugula } 750fec6c5acSUday Bondhugula 751fec6c5acSUday Bondhugula /// The mode of conversion to use. 752fec6c5acSUday Bondhugula ConversionMode mode; 753fec6c5acSUday Bondhugula }; 754fec6c5acSUday Bondhugula } // end anonymous namespace 755fec6c5acSUday Bondhugula 756fec6c5acSUday Bondhugula static llvm::cl::opt<TestLegalizePatternDriver::ConversionMode> 757fec6c5acSUday Bondhugula legalizerConversionMode( 758fec6c5acSUday Bondhugula "test-legalize-mode", 759fec6c5acSUday Bondhugula llvm::cl::desc("The legalization mode to use with the test driver"), 760fec6c5acSUday Bondhugula llvm::cl::init(TestLegalizePatternDriver::ConversionMode::Partial), 761fec6c5acSUday Bondhugula llvm::cl::values( 762fec6c5acSUday Bondhugula clEnumValN(TestLegalizePatternDriver::ConversionMode::Analysis, 763fec6c5acSUday Bondhugula "analysis", "Perform an analysis conversion"), 764fec6c5acSUday Bondhugula clEnumValN(TestLegalizePatternDriver::ConversionMode::Full, "full", 765fec6c5acSUday Bondhugula "Perform a full conversion"), 766fec6c5acSUday Bondhugula clEnumValN(TestLegalizePatternDriver::ConversionMode::Partial, 767fec6c5acSUday Bondhugula "partial", "Perform a partial conversion"))); 768fec6c5acSUday Bondhugula 769fec6c5acSUday Bondhugula //===----------------------------------------------------------------------===// 770fec6c5acSUday Bondhugula // ConversionPatternRewriter::getRemappedValue testing. This method is used 7715aacce3dSKazuaki Ishizaki // to get the remapped value of an original value that was replaced using 772fec6c5acSUday Bondhugula // ConversionPatternRewriter. 773fec6c5acSUday Bondhugula namespace { 774fec6c5acSUday Bondhugula /// Converter that replaces a one-result one-operand OneVResOneVOperandOp1 with 775fec6c5acSUday Bondhugula /// a one-operand two-result OneVResOneVOperandOp1 by replicating its original 776fec6c5acSUday Bondhugula /// operand twice. 777fec6c5acSUday Bondhugula /// 778fec6c5acSUday Bondhugula /// Example: 779fec6c5acSUday Bondhugula /// %1 = test.one_variadic_out_one_variadic_in1"(%0) 780fec6c5acSUday Bondhugula /// is replaced with: 781fec6c5acSUday Bondhugula /// %1 = test.one_variadic_out_one_variadic_in1"(%0, %0) 782fec6c5acSUday Bondhugula struct OneVResOneVOperandOp1Converter 783fec6c5acSUday Bondhugula : public OpConversionPattern<OneVResOneVOperandOp1> { 784fec6c5acSUday Bondhugula using OpConversionPattern<OneVResOneVOperandOp1>::OpConversionPattern; 785fec6c5acSUday Bondhugula 786fec6c5acSUday Bondhugula LogicalResult 787ef976337SRiver Riddle matchAndRewrite(OneVResOneVOperandOp1 op, OpAdaptor adaptor, 788fec6c5acSUday Bondhugula ConversionPatternRewriter &rewriter) const override { 789fec6c5acSUday Bondhugula auto origOps = op.getOperands(); 790fec6c5acSUday Bondhugula assert(std::distance(origOps.begin(), origOps.end()) == 1 && 791fec6c5acSUday Bondhugula "One operand expected"); 792fec6c5acSUday Bondhugula Value origOp = *origOps.begin(); 793fec6c5acSUday Bondhugula SmallVector<Value, 2> remappedOperands; 794fec6c5acSUday Bondhugula // Replicate the remapped original operand twice. Note that we don't used 795fec6c5acSUday Bondhugula // the remapped 'operand' since the goal is testing 'getRemappedValue'. 796fec6c5acSUday Bondhugula remappedOperands.push_back(rewriter.getRemappedValue(origOp)); 797fec6c5acSUday Bondhugula remappedOperands.push_back(rewriter.getRemappedValue(origOp)); 798fec6c5acSUday Bondhugula 799fec6c5acSUday Bondhugula rewriter.replaceOpWithNewOp<OneVResOneVOperandOp1>(op, op.getResultTypes(), 800fec6c5acSUday Bondhugula remappedOperands); 801fec6c5acSUday Bondhugula return success(); 802fec6c5acSUday Bondhugula } 803fec6c5acSUday Bondhugula }; 804fec6c5acSUday Bondhugula 80580aca1eaSRiver Riddle struct TestRemappedValue 80680aca1eaSRiver Riddle : public mlir::PassWrapper<TestRemappedValue, FunctionPass> { 807b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-remapped-value"; } 808b5e22e6dSMehdi Amini StringRef getDescription() const final { 809b5e22e6dSMehdi Amini return "Test public remapped value mechanism in ConversionPatternRewriter"; 810b5e22e6dSMehdi Amini } 811fec6c5acSUday Bondhugula void runOnFunction() override { 812dc4e913bSChris Lattner mlir::RewritePatternSet patterns(&getContext()); 813dc4e913bSChris Lattner patterns.add<OneVResOneVOperandOp1Converter>(&getContext()); 814fec6c5acSUday Bondhugula 815fec6c5acSUday Bondhugula mlir::ConversionTarget target(getContext()); 816973ddb7dSMehdi Amini target.addLegalOp<ModuleOp, FuncOp, TestReturnOp>(); 817fec6c5acSUday Bondhugula // We make OneVResOneVOperandOp1 legal only when it has more that one 818fec6c5acSUday Bondhugula // operand. This will trigger the conversion that will replace one-operand 819fec6c5acSUday Bondhugula // OneVResOneVOperandOp1 with two-operand OneVResOneVOperandOp1. 820fec6c5acSUday Bondhugula target.addDynamicallyLegalOp<OneVResOneVOperandOp1>( 821fec6c5acSUday Bondhugula [](Operation *op) -> bool { 822fec6c5acSUday Bondhugula return std::distance(op->operand_begin(), op->operand_end()) > 1; 823fec6c5acSUday Bondhugula }); 824fec6c5acSUday Bondhugula 8253fffffa8SRiver Riddle if (failed(mlir::applyFullConversion(getFunction(), target, 8263fffffa8SRiver Riddle std::move(patterns)))) { 827fec6c5acSUday Bondhugula signalPassFailure(); 828fec6c5acSUday Bondhugula } 829fec6c5acSUday Bondhugula } 830fec6c5acSUday Bondhugula }; 831fec6c5acSUday Bondhugula } // end anonymous namespace 832fec6c5acSUday Bondhugula 83380d7ac3bSRiver Riddle //===----------------------------------------------------------------------===// 83480d7ac3bSRiver Riddle // Test patterns without a specific root operation kind 83580d7ac3bSRiver Riddle //===----------------------------------------------------------------------===// 83680d7ac3bSRiver Riddle 83780d7ac3bSRiver Riddle namespace { 83880d7ac3bSRiver Riddle /// This pattern matches and removes any operation in the test dialect. 83980d7ac3bSRiver Riddle struct RemoveTestDialectOps : public RewritePattern { 84076f3c2f3SRiver Riddle RemoveTestDialectOps(MLIRContext *context) 84176f3c2f3SRiver Riddle : RewritePattern(MatchAnyOpTypeTag(), /*benefit=*/1, context) {} 84280d7ac3bSRiver Riddle 84380d7ac3bSRiver Riddle LogicalResult matchAndRewrite(Operation *op, 84480d7ac3bSRiver Riddle PatternRewriter &rewriter) const override { 84580d7ac3bSRiver Riddle if (!isa<TestDialect>(op->getDialect())) 84680d7ac3bSRiver Riddle return failure(); 84780d7ac3bSRiver Riddle rewriter.eraseOp(op); 84880d7ac3bSRiver Riddle return success(); 84980d7ac3bSRiver Riddle } 85080d7ac3bSRiver Riddle }; 85180d7ac3bSRiver Riddle 85280d7ac3bSRiver Riddle struct TestUnknownRootOpDriver 85380d7ac3bSRiver Riddle : public mlir::PassWrapper<TestUnknownRootOpDriver, FunctionPass> { 854b5e22e6dSMehdi Amini StringRef getArgument() const final { 855b5e22e6dSMehdi Amini return "test-legalize-unknown-root-patterns"; 856b5e22e6dSMehdi Amini } 857b5e22e6dSMehdi Amini StringRef getDescription() const final { 858b5e22e6dSMehdi Amini return "Test public remapped value mechanism in ConversionPatternRewriter"; 859b5e22e6dSMehdi Amini } 86080d7ac3bSRiver Riddle void runOnFunction() override { 861dc4e913bSChris Lattner mlir::RewritePatternSet patterns(&getContext()); 86276f3c2f3SRiver Riddle patterns.add<RemoveTestDialectOps>(&getContext()); 86380d7ac3bSRiver Riddle 86480d7ac3bSRiver Riddle mlir::ConversionTarget target(getContext()); 86580d7ac3bSRiver Riddle target.addIllegalDialect<TestDialect>(); 8663fffffa8SRiver Riddle if (failed( 8673fffffa8SRiver Riddle applyPartialConversion(getFunction(), target, std::move(patterns)))) 86880d7ac3bSRiver Riddle signalPassFailure(); 86980d7ac3bSRiver Riddle } 87080d7ac3bSRiver Riddle }; 87180d7ac3bSRiver Riddle } // end anonymous namespace 87280d7ac3bSRiver Riddle 8734589dd92SRiver Riddle //===----------------------------------------------------------------------===// 8744589dd92SRiver Riddle // Test type conversions 8754589dd92SRiver Riddle //===----------------------------------------------------------------------===// 8764589dd92SRiver Riddle 8774589dd92SRiver Riddle namespace { 8784589dd92SRiver Riddle struct TestTypeConversionProducer 8794589dd92SRiver Riddle : public OpConversionPattern<TestTypeProducerOp> { 8804589dd92SRiver Riddle using OpConversionPattern<TestTypeProducerOp>::OpConversionPattern; 8814589dd92SRiver Riddle LogicalResult 882ef976337SRiver Riddle matchAndRewrite(TestTypeProducerOp op, OpAdaptor adaptor, 8834589dd92SRiver Riddle ConversionPatternRewriter &rewriter) const final { 8844589dd92SRiver Riddle Type resultType = op.getType(); 8854589dd92SRiver Riddle if (resultType.isa<FloatType>()) 8864589dd92SRiver Riddle resultType = rewriter.getF64Type(); 8874589dd92SRiver Riddle else if (resultType.isInteger(16)) 8884589dd92SRiver Riddle resultType = rewriter.getIntegerType(64); 8894589dd92SRiver Riddle else 8904589dd92SRiver Riddle return failure(); 8914589dd92SRiver Riddle 8924589dd92SRiver Riddle rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, resultType); 8934589dd92SRiver Riddle return success(); 8944589dd92SRiver Riddle } 8954589dd92SRiver Riddle }; 8964589dd92SRiver Riddle 8970409eb28SAlex Zinenko /// Call signature conversion and then fail the rewrite to trigger the undo 8980409eb28SAlex Zinenko /// mechanism. 8990409eb28SAlex Zinenko struct TestSignatureConversionUndo 9000409eb28SAlex Zinenko : public OpConversionPattern<TestSignatureConversionUndoOp> { 9010409eb28SAlex Zinenko using OpConversionPattern<TestSignatureConversionUndoOp>::OpConversionPattern; 9020409eb28SAlex Zinenko 9030409eb28SAlex Zinenko LogicalResult 904ef976337SRiver Riddle matchAndRewrite(TestSignatureConversionUndoOp op, OpAdaptor adaptor, 9050409eb28SAlex Zinenko ConversionPatternRewriter &rewriter) const final { 9060409eb28SAlex Zinenko (void)rewriter.convertRegionTypes(&op->getRegion(0), *getTypeConverter()); 9070409eb28SAlex Zinenko return failure(); 9080409eb28SAlex Zinenko } 9090409eb28SAlex Zinenko }; 9100409eb28SAlex Zinenko 9110409eb28SAlex Zinenko /// Just forward the operands to the root op. This is essentially a no-op 9120409eb28SAlex Zinenko /// pattern that is used to trigger target materialization. 9130409eb28SAlex Zinenko struct TestTypeConsumerForward 9140409eb28SAlex Zinenko : public OpConversionPattern<TestTypeConsumerOp> { 9150409eb28SAlex Zinenko using OpConversionPattern<TestTypeConsumerOp>::OpConversionPattern; 9160409eb28SAlex Zinenko 9170409eb28SAlex Zinenko LogicalResult 918ef976337SRiver Riddle matchAndRewrite(TestTypeConsumerOp op, OpAdaptor adaptor, 9190409eb28SAlex Zinenko ConversionPatternRewriter &rewriter) const final { 920ef976337SRiver Riddle rewriter.updateRootInPlace(op, 921ef976337SRiver Riddle [&] { op->setOperands(adaptor.getOperands()); }); 9220409eb28SAlex Zinenko return success(); 9230409eb28SAlex Zinenko } 9240409eb28SAlex Zinenko }; 9250409eb28SAlex Zinenko 9265b91060dSAlex Zinenko struct TestTypeConversionAnotherProducer 9275b91060dSAlex Zinenko : public OpRewritePattern<TestAnotherTypeProducerOp> { 9285b91060dSAlex Zinenko using OpRewritePattern<TestAnotherTypeProducerOp>::OpRewritePattern; 9295b91060dSAlex Zinenko 9305b91060dSAlex Zinenko LogicalResult matchAndRewrite(TestAnotherTypeProducerOp op, 9315b91060dSAlex Zinenko PatternRewriter &rewriter) const final { 9325b91060dSAlex Zinenko rewriter.replaceOpWithNewOp<TestTypeProducerOp>(op, op.getType()); 9335b91060dSAlex Zinenko return success(); 9345b91060dSAlex Zinenko } 9355b91060dSAlex Zinenko }; 9365b91060dSAlex Zinenko 9374589dd92SRiver Riddle struct TestTypeConversionDriver 9384589dd92SRiver Riddle : public PassWrapper<TestTypeConversionDriver, OperationPass<ModuleOp>> { 939f9dc2b70SMehdi Amini void getDependentDialects(DialectRegistry ®istry) const override { 940f9dc2b70SMehdi Amini registry.insert<TestDialect>(); 941f9dc2b70SMehdi Amini } 942b5e22e6dSMehdi Amini StringRef getArgument() const final { 943b5e22e6dSMehdi Amini return "test-legalize-type-conversion"; 944b5e22e6dSMehdi Amini } 945b5e22e6dSMehdi Amini StringRef getDescription() const final { 946b5e22e6dSMehdi Amini return "Test various type conversion functionalities in DialectConversion"; 947b5e22e6dSMehdi Amini } 948f9dc2b70SMehdi Amini 9494589dd92SRiver Riddle void runOnOperation() override { 9504589dd92SRiver Riddle // Initialize the type converter. 9514589dd92SRiver Riddle TypeConverter converter; 9524589dd92SRiver Riddle 9534589dd92SRiver Riddle /// Add the legal set of type conversions. 9544589dd92SRiver Riddle converter.addConversion([](Type type) -> Type { 9554589dd92SRiver Riddle // Treat F64 as legal. 9564589dd92SRiver Riddle if (type.isF64()) 9574589dd92SRiver Riddle return type; 9584589dd92SRiver Riddle // Allow converting BF16/F16/F32 to F64. 9594589dd92SRiver Riddle if (type.isBF16() || type.isF16() || type.isF32()) 9604589dd92SRiver Riddle return FloatType::getF64(type.getContext()); 9614589dd92SRiver Riddle // Otherwise, the type is illegal. 9624589dd92SRiver Riddle return nullptr; 9634589dd92SRiver Riddle }); 9644589dd92SRiver Riddle converter.addConversion([](IntegerType type, SmallVectorImpl<Type> &) { 9654589dd92SRiver Riddle // Drop all integer types. 9664589dd92SRiver Riddle return success(); 9674589dd92SRiver Riddle }); 9684589dd92SRiver Riddle 9694589dd92SRiver Riddle /// Add the legal set of type materializations. 9704589dd92SRiver Riddle converter.addSourceMaterialization([](OpBuilder &builder, Type resultType, 9714589dd92SRiver Riddle ValueRange inputs, 9724589dd92SRiver Riddle Location loc) -> Value { 9734589dd92SRiver Riddle // Allow casting from F64 back to F32. 9744589dd92SRiver Riddle if (!resultType.isF16() && inputs.size() == 1 && 9754589dd92SRiver Riddle inputs[0].getType().isF64()) 9764589dd92SRiver Riddle return builder.create<TestCastOp>(loc, resultType, inputs).getResult(); 9774589dd92SRiver Riddle // Allow producing an i32 or i64 from nothing. 9784589dd92SRiver Riddle if ((resultType.isInteger(32) || resultType.isInteger(64)) && 9794589dd92SRiver Riddle inputs.empty()) 9804589dd92SRiver Riddle return builder.create<TestTypeProducerOp>(loc, resultType); 9814589dd92SRiver Riddle // Allow producing an i64 from an integer. 9824589dd92SRiver Riddle if (resultType.isa<IntegerType>() && inputs.size() == 1 && 9834589dd92SRiver Riddle inputs[0].getType().isa<IntegerType>()) 9844589dd92SRiver Riddle return builder.create<TestCastOp>(loc, resultType, inputs).getResult(); 9854589dd92SRiver Riddle // Otherwise, fail. 9864589dd92SRiver Riddle return nullptr; 9874589dd92SRiver Riddle }); 9884589dd92SRiver Riddle 9894589dd92SRiver Riddle // Initialize the conversion target. 9904589dd92SRiver Riddle mlir::ConversionTarget target(getContext()); 9914589dd92SRiver Riddle target.addDynamicallyLegalOp<TestTypeProducerOp>([](TestTypeProducerOp op) { 9924589dd92SRiver Riddle return op.getType().isF64() || op.getType().isInteger(64); 9934589dd92SRiver Riddle }); 9944589dd92SRiver Riddle target.addDynamicallyLegalOp<FuncOp>([&](FuncOp op) { 9954589dd92SRiver Riddle return converter.isSignatureLegal(op.getType()) && 9964589dd92SRiver Riddle converter.isLegal(&op.getBody()); 9974589dd92SRiver Riddle }); 9984589dd92SRiver Riddle target.addDynamicallyLegalOp<TestCastOp>([&](TestCastOp op) { 9994589dd92SRiver Riddle // Allow casts from F64 to F32. 10004589dd92SRiver Riddle return (*op.operand_type_begin()).isF64() && op.getType().isF32(); 10014589dd92SRiver Riddle }); 10024589dd92SRiver Riddle 10034589dd92SRiver Riddle // Initialize the set of rewrite patterns. 1004dc4e913bSChris Lattner RewritePatternSet patterns(&getContext()); 1005dc4e913bSChris Lattner patterns.add<TestTypeConsumerForward, TestTypeConversionProducer, 10060409eb28SAlex Zinenko TestSignatureConversionUndo>(converter, &getContext()); 1007dc4e913bSChris Lattner patterns.add<TestTypeConversionAnotherProducer>(&getContext()); 10083a506b31SChris Lattner mlir::populateFuncOpTypeConversionPattern(patterns, converter); 10094589dd92SRiver Riddle 10103fffffa8SRiver Riddle if (failed(applyPartialConversion(getOperation(), target, 10113fffffa8SRiver Riddle std::move(patterns)))) 10124589dd92SRiver Riddle signalPassFailure(); 10134589dd92SRiver Riddle } 10144589dd92SRiver Riddle }; 10154589dd92SRiver Riddle } // end anonymous namespace 10164589dd92SRiver Riddle 1017c8fb6ee3SRiver Riddle //===----------------------------------------------------------------------===// 1018c8fb6ee3SRiver Riddle // Test Block Merging 1019c8fb6ee3SRiver Riddle //===----------------------------------------------------------------------===// 1020c8fb6ee3SRiver Riddle 1021e888886cSMaheshRavishankar namespace { 1022e888886cSMaheshRavishankar /// A rewriter pattern that tests that blocks can be merged. 1023e888886cSMaheshRavishankar struct TestMergeBlock : public OpConversionPattern<TestMergeBlocksOp> { 1024e888886cSMaheshRavishankar using OpConversionPattern<TestMergeBlocksOp>::OpConversionPattern; 1025e888886cSMaheshRavishankar 1026e888886cSMaheshRavishankar LogicalResult 1027ef976337SRiver Riddle matchAndRewrite(TestMergeBlocksOp op, OpAdaptor adaptor, 1028e888886cSMaheshRavishankar ConversionPatternRewriter &rewriter) const final { 1029e888886cSMaheshRavishankar Block &firstBlock = op.body().front(); 1030e888886cSMaheshRavishankar Operation *branchOp = firstBlock.getTerminator(); 1031e888886cSMaheshRavishankar Block *secondBlock = &*(std::next(op.body().begin())); 1032e888886cSMaheshRavishankar auto succOperands = branchOp->getOperands(); 1033e888886cSMaheshRavishankar SmallVector<Value, 2> replacements(succOperands); 1034e888886cSMaheshRavishankar rewriter.eraseOp(branchOp); 1035e888886cSMaheshRavishankar rewriter.mergeBlocks(secondBlock, &firstBlock, replacements); 1036e888886cSMaheshRavishankar rewriter.updateRootInPlace(op, [] {}); 1037e888886cSMaheshRavishankar return success(); 1038e888886cSMaheshRavishankar } 1039e888886cSMaheshRavishankar }; 1040e888886cSMaheshRavishankar 1041e888886cSMaheshRavishankar /// A rewrite pattern to tests the undo mechanism of blocks being merged. 1042e888886cSMaheshRavishankar struct TestUndoBlocksMerge : public ConversionPattern { 1043e888886cSMaheshRavishankar TestUndoBlocksMerge(MLIRContext *ctx) 1044e888886cSMaheshRavishankar : ConversionPattern("test.undo_blocks_merge", /*benefit=*/1, ctx) {} 1045e888886cSMaheshRavishankar LogicalResult 1046e888886cSMaheshRavishankar matchAndRewrite(Operation *op, ArrayRef<Value> operands, 1047e888886cSMaheshRavishankar ConversionPatternRewriter &rewriter) const final { 1048e888886cSMaheshRavishankar Block &firstBlock = op->getRegion(0).front(); 1049e888886cSMaheshRavishankar Operation *branchOp = firstBlock.getTerminator(); 1050e888886cSMaheshRavishankar Block *secondBlock = &*(std::next(op->getRegion(0).begin())); 1051e888886cSMaheshRavishankar rewriter.setInsertionPointToStart(secondBlock); 1052e888886cSMaheshRavishankar rewriter.create<ILLegalOpF>(op->getLoc(), rewriter.getF32Type()); 1053e888886cSMaheshRavishankar auto succOperands = branchOp->getOperands(); 1054e888886cSMaheshRavishankar SmallVector<Value, 2> replacements(succOperands); 1055e888886cSMaheshRavishankar rewriter.eraseOp(branchOp); 1056e888886cSMaheshRavishankar rewriter.mergeBlocks(secondBlock, &firstBlock, replacements); 1057e888886cSMaheshRavishankar rewriter.updateRootInPlace(op, [] {}); 1058e888886cSMaheshRavishankar return success(); 1059e888886cSMaheshRavishankar } 1060e888886cSMaheshRavishankar }; 1061e888886cSMaheshRavishankar 1062e888886cSMaheshRavishankar /// A rewrite mechanism to inline the body of the op into its parent, when both 1063e888886cSMaheshRavishankar /// ops can have a single block. 1064e888886cSMaheshRavishankar struct TestMergeSingleBlockOps 1065e888886cSMaheshRavishankar : public OpConversionPattern<SingleBlockImplicitTerminatorOp> { 1066e888886cSMaheshRavishankar using OpConversionPattern< 1067e888886cSMaheshRavishankar SingleBlockImplicitTerminatorOp>::OpConversionPattern; 1068e888886cSMaheshRavishankar 1069e888886cSMaheshRavishankar LogicalResult 1070ef976337SRiver Riddle matchAndRewrite(SingleBlockImplicitTerminatorOp op, OpAdaptor adaptor, 1071e888886cSMaheshRavishankar ConversionPatternRewriter &rewriter) const final { 1072e888886cSMaheshRavishankar SingleBlockImplicitTerminatorOp parentOp = 10730bf4a82aSChristian Sigg op->getParentOfType<SingleBlockImplicitTerminatorOp>(); 1074e888886cSMaheshRavishankar if (!parentOp) 1075e888886cSMaheshRavishankar return failure(); 1076e888886cSMaheshRavishankar Block &innerBlock = op.region().front(); 1077e888886cSMaheshRavishankar TerminatorOp innerTerminator = 1078e888886cSMaheshRavishankar cast<TerminatorOp>(innerBlock.getTerminator()); 10799c7b0c4aSRahul Joshi rewriter.mergeBlockBefore(&innerBlock, op); 1080e888886cSMaheshRavishankar rewriter.eraseOp(innerTerminator); 1081e888886cSMaheshRavishankar rewriter.eraseOp(op); 1082e888886cSMaheshRavishankar rewriter.updateRootInPlace(op, [] {}); 1083e888886cSMaheshRavishankar return success(); 1084e888886cSMaheshRavishankar } 1085e888886cSMaheshRavishankar }; 1086e888886cSMaheshRavishankar 1087e888886cSMaheshRavishankar struct TestMergeBlocksPatternDriver 1088e888886cSMaheshRavishankar : public PassWrapper<TestMergeBlocksPatternDriver, 1089e888886cSMaheshRavishankar OperationPass<ModuleOp>> { 1090b5e22e6dSMehdi Amini StringRef getArgument() const final { return "test-merge-blocks"; } 1091b5e22e6dSMehdi Amini StringRef getDescription() const final { 1092b5e22e6dSMehdi Amini return "Test Merging operation in ConversionPatternRewriter"; 1093b5e22e6dSMehdi Amini } 1094e888886cSMaheshRavishankar void runOnOperation() override { 1095e888886cSMaheshRavishankar MLIRContext *context = &getContext(); 1096dc4e913bSChris Lattner mlir::RewritePatternSet patterns(context); 1097dc4e913bSChris Lattner patterns.add<TestMergeBlock, TestUndoBlocksMerge, TestMergeSingleBlockOps>( 1098e888886cSMaheshRavishankar context); 1099e888886cSMaheshRavishankar ConversionTarget target(*context); 1100973ddb7dSMehdi Amini target.addLegalOp<FuncOp, ModuleOp, TerminatorOp, TestBranchOp, 1101973ddb7dSMehdi Amini TestTypeConsumerOp, TestTypeProducerOp, TestReturnOp>(); 1102e888886cSMaheshRavishankar target.addIllegalOp<ILLegalOpF>(); 1103e888886cSMaheshRavishankar 1104e888886cSMaheshRavishankar /// Expect the op to have a single block after legalization. 1105e888886cSMaheshRavishankar target.addDynamicallyLegalOp<TestMergeBlocksOp>( 1106e888886cSMaheshRavishankar [&](TestMergeBlocksOp op) -> bool { 1107e888886cSMaheshRavishankar return llvm::hasSingleElement(op.body()); 1108e888886cSMaheshRavishankar }); 1109e888886cSMaheshRavishankar 1110e888886cSMaheshRavishankar /// Only allow `test.br` within test.merge_blocks op. 1111e888886cSMaheshRavishankar target.addDynamicallyLegalOp<TestBranchOp>([&](TestBranchOp op) -> bool { 11120bf4a82aSChristian Sigg return op->getParentOfType<TestMergeBlocksOp>(); 1113e888886cSMaheshRavishankar }); 1114e888886cSMaheshRavishankar 1115e888886cSMaheshRavishankar /// Expect that all nested test.SingleBlockImplicitTerminator ops are 1116e888886cSMaheshRavishankar /// inlined. 1117e888886cSMaheshRavishankar target.addDynamicallyLegalOp<SingleBlockImplicitTerminatorOp>( 1118e888886cSMaheshRavishankar [&](SingleBlockImplicitTerminatorOp op) -> bool { 11190bf4a82aSChristian Sigg return !op->getParentOfType<SingleBlockImplicitTerminatorOp>(); 1120e888886cSMaheshRavishankar }); 1121e888886cSMaheshRavishankar 1122e888886cSMaheshRavishankar DenseSet<Operation *> unlegalizedOps; 11233fffffa8SRiver Riddle (void)applyPartialConversion(getOperation(), target, std::move(patterns), 1124e888886cSMaheshRavishankar &unlegalizedOps); 1125e888886cSMaheshRavishankar for (auto *op : unlegalizedOps) 1126e888886cSMaheshRavishankar op->emitRemark() << "op '" << op->getName() << "' is not legalizable"; 1127e888886cSMaheshRavishankar } 1128e888886cSMaheshRavishankar }; 1129e888886cSMaheshRavishankar } // namespace 1130e888886cSMaheshRavishankar 11314589dd92SRiver Riddle //===----------------------------------------------------------------------===// 1132c8fb6ee3SRiver Riddle // Test Selective Replacement 1133c8fb6ee3SRiver Riddle //===----------------------------------------------------------------------===// 1134c8fb6ee3SRiver Riddle 1135c8fb6ee3SRiver Riddle namespace { 1136c8fb6ee3SRiver Riddle /// A rewrite mechanism to inline the body of the op into its parent, when both 1137c8fb6ee3SRiver Riddle /// ops can have a single block. 1138c8fb6ee3SRiver Riddle struct TestSelectiveOpReplacementPattern : public OpRewritePattern<TestCastOp> { 1139c8fb6ee3SRiver Riddle using OpRewritePattern<TestCastOp>::OpRewritePattern; 1140c8fb6ee3SRiver Riddle 1141c8fb6ee3SRiver Riddle LogicalResult matchAndRewrite(TestCastOp op, 1142c8fb6ee3SRiver Riddle PatternRewriter &rewriter) const final { 1143c8fb6ee3SRiver Riddle if (op.getNumOperands() != 2) 1144c8fb6ee3SRiver Riddle return failure(); 1145c8fb6ee3SRiver Riddle OperandRange operands = op.getOperands(); 1146c8fb6ee3SRiver Riddle 1147c8fb6ee3SRiver Riddle // Replace non-terminator uses with the first operand. 1148c8fb6ee3SRiver Riddle rewriter.replaceOpWithIf(op, operands[0], [](OpOperand &operand) { 1149fe7c0d90SRiver Riddle return operand.getOwner()->hasTrait<OpTrait::IsTerminator>(); 1150c8fb6ee3SRiver Riddle }); 1151c8fb6ee3SRiver Riddle // Replace everything else with the second operand if the operation isn't 1152c8fb6ee3SRiver Riddle // dead. 1153c8fb6ee3SRiver Riddle rewriter.replaceOp(op, op.getOperand(1)); 1154c8fb6ee3SRiver Riddle return success(); 1155c8fb6ee3SRiver Riddle } 1156c8fb6ee3SRiver Riddle }; 1157c8fb6ee3SRiver Riddle 1158c8fb6ee3SRiver Riddle struct TestSelectiveReplacementPatternDriver 1159c8fb6ee3SRiver Riddle : public PassWrapper<TestSelectiveReplacementPatternDriver, 1160c8fb6ee3SRiver Riddle OperationPass<>> { 1161b5e22e6dSMehdi Amini StringRef getArgument() const final { 1162b5e22e6dSMehdi Amini return "test-pattern-selective-replacement"; 1163b5e22e6dSMehdi Amini } 1164b5e22e6dSMehdi Amini StringRef getDescription() const final { 1165b5e22e6dSMehdi Amini return "Test selective replacement in the PatternRewriter"; 1166b5e22e6dSMehdi Amini } 1167c8fb6ee3SRiver Riddle void runOnOperation() override { 1168c8fb6ee3SRiver Riddle MLIRContext *context = &getContext(); 1169dc4e913bSChris Lattner mlir::RewritePatternSet patterns(context); 1170dc4e913bSChris Lattner patterns.add<TestSelectiveOpReplacementPattern>(context); 1171e21adfa3SRiver Riddle (void)applyPatternsAndFoldGreedily(getOperation()->getRegions(), 1172c8fb6ee3SRiver Riddle std::move(patterns)); 1173c8fb6ee3SRiver Riddle } 1174c8fb6ee3SRiver Riddle }; 1175c8fb6ee3SRiver Riddle } // namespace 1176c8fb6ee3SRiver Riddle 1177c8fb6ee3SRiver Riddle //===----------------------------------------------------------------------===// 11784589dd92SRiver Riddle // PassRegistration 11794589dd92SRiver Riddle //===----------------------------------------------------------------------===// 11804589dd92SRiver Riddle 1181fec6c5acSUday Bondhugula namespace mlir { 118272c65b69SAlexander Belyaev namespace test { 1183fec6c5acSUday Bondhugula void registerPatternsTestPass() { 1184b5e22e6dSMehdi Amini PassRegistration<TestReturnTypeDriver>(); 1185fec6c5acSUday Bondhugula 1186b5e22e6dSMehdi Amini PassRegistration<TestDerivedAttributeDriver>(); 11879ba37b3bSJacques Pienaar 1188b5e22e6dSMehdi Amini PassRegistration<TestPatternDriver>(); 1189fec6c5acSUday Bondhugula 1190b5e22e6dSMehdi Amini PassRegistration<TestLegalizePatternDriver>([] { 1191b5e22e6dSMehdi Amini return std::make_unique<TestLegalizePatternDriver>(legalizerConversionMode); 1192fec6c5acSUday Bondhugula }); 1193fec6c5acSUday Bondhugula 1194b5e22e6dSMehdi Amini PassRegistration<TestRemappedValue>(); 119580d7ac3bSRiver Riddle 1196b5e22e6dSMehdi Amini PassRegistration<TestUnknownRootOpDriver>(); 11974589dd92SRiver Riddle 1198b5e22e6dSMehdi Amini PassRegistration<TestTypeConversionDriver>(); 1199e888886cSMaheshRavishankar 1200b5e22e6dSMehdi Amini PassRegistration<TestMergeBlocksPatternDriver>(); 1201b5e22e6dSMehdi Amini PassRegistration<TestSelectiveReplacementPatternDriver>(); 1202fec6c5acSUday Bondhugula } 120372c65b69SAlexander Belyaev } // namespace test 1204fec6c5acSUday Bondhugula } // namespace mlir 1205