1 //===- Utils.cpp - Utilities to support the Linalg dialect ----------------===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 // 9 // This file implements utilities for the Linalg dialect. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/Dialect/Linalg/Utils/Utils.h" 14 #include "mlir/Dialect/Affine/IR/AffineOps.h" 15 #include "mlir/Dialect/Linalg/IR/LinalgOps.h" 16 #include "mlir/Dialect/Linalg/IR/LinalgTypes.h" 17 #include "mlir/Dialect/LoopOps/LoopOps.h" 18 #include "mlir/Dialect/StandardOps/IR/Ops.h" 19 #include "mlir/IR/AffineExpr.h" 20 #include "mlir/IR/AffineMap.h" 21 #include "mlir/IR/Matchers.h" 22 #include "mlir/IR/OpImplementation.h" 23 #include "mlir/Pass/Pass.h" 24 #include "mlir/Support/STLExtras.h" 25 #include "mlir/Transforms/FoldUtils.h" 26 27 using namespace mlir; 28 using namespace mlir::linalg; 29 using namespace mlir::loop; 30 31 Optional<RegionMatcher::BinaryOpKind> 32 RegionMatcher::matchAsScalarBinaryOp(GenericOp op) { 33 auto ®ion = op.region(); 34 if (!has_single_element(region)) 35 return llvm::None; 36 37 Block &block = region.front(); 38 if (block.getNumArguments() != 2 || 39 !block.getArgument(0).getType().isSignlessIntOrFloat() || 40 !block.getArgument(1).getType().isSignlessIntOrFloat()) 41 return llvm::None; 42 43 auto &ops = block.getOperations(); 44 if (!has_single_element(block.without_terminator())) 45 return llvm::None; 46 47 using mlir::matchers::m_Val; 48 auto a = m_Val(block.getArgument(0)); 49 auto b = m_Val(block.getArgument(1)); 50 51 auto addPattern = m_Op<linalg::YieldOp>(m_Op<AddIOp>(a, b)); 52 if (addPattern.match(&ops.back())) 53 return BinaryOpKind::IAdd; 54 55 return llvm::None; 56 } 57 58 static Value emitOrFoldComposedAffineApply(OpBuilder &b, Location loc, 59 AffineMap map, 60 ArrayRef<Value> operandsRef, 61 OperationFolder *folder) { 62 SmallVector<Value, 4> operands(operandsRef.begin(), operandsRef.end()); 63 fullyComposeAffineMapAndOperands(&map, &operands); 64 canonicalizeMapAndOperands(&map, &operands); 65 return folder ? folder->create<AffineApplyOp>(b, loc, map, operands) 66 : b.create<AffineApplyOp>(loc, map, operands); 67 } 68 69 SmallVector<Value, 4> mlir::linalg::applyMapToValues(OpBuilder &b, Location loc, 70 AffineMap map, 71 ArrayRef<Value> values, 72 OperationFolder *folder) { 73 SmallVector<Value, 4> res; 74 res.reserve(map.getNumResults()); 75 unsigned numDims = map.getNumDims(); 76 // For each `expr` in `map`, applies the `expr` to the values extracted from 77 // ranges. If the resulting application can be folded into a Value, the 78 // folding occurs eagerly. Otherwise, an affine.apply operation is emitted. 79 for (auto expr : map.getResults()) { 80 AffineMap map = AffineMap::get(numDims, 0, expr); 81 res.push_back(emitOrFoldComposedAffineApply(b, loc, map, values, folder)); 82 } 83 return res; 84 } 85 86 /// Returns all the operands of `linalgOp` that are not views. 87 /// Asserts that these operands are value types to allow transformations like 88 /// tiling to just use the values when cloning `linalgOp`. 89 SmallVector<Value, 4> 90 mlir::linalg::getAssumedNonViewOperands(LinalgOp linalgOp) { 91 auto *op = linalgOp.getOperation(); 92 unsigned numViews = linalgOp.getNumInputsAndOutputs(); 93 unsigned nOperands = op->getNumOperands() - numViews; 94 SmallVector<Value, 4> res; 95 res.reserve(nOperands); 96 for (unsigned i = 0; i < nOperands; ++i) { 97 res.push_back(op->getOperand(numViews + i)); 98 auto t = res.back().getType(); 99 (void)t; 100 assert((t.isSignlessIntOrIndexOrFloat() || t.isa<VectorType>()) && 101 "expected scalar or vector type"); 102 } 103 return res; 104 } 105