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(®ionOp->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 ®ion = *op->getParentRegion(); 196f27f1e8cSAlex Zinenko Type i32Type = rewriter.getIntegerType(32); 197f27f1e8cSAlex Zinenko rewriter.createBlock(®ion, 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 ®ion = *op->getParentRegion(); 213f27f1e8cSAlex Zinenko Type i32Type = rewriter.getIntegerType(32); 214f27f1e8cSAlex Zinenko rewriter.createBlock(®ion, 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 ®ion = op->getRegion(0); 235fec6c5acSUday Bondhugula Block *entry = ®ion.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(®ion, 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