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/SCF/SCF.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/Transforms/FoldUtils.h" 25 26 using namespace mlir; 27 using namespace mlir::linalg; 28 using namespace mlir::scf; 29 30 Optional<RegionMatcher::BinaryOpKind> 31 RegionMatcher::matchAsScalarBinaryOp(GenericOp op) { 32 auto ®ion = op.region(); 33 if (!llvm::hasSingleElement(region)) 34 return llvm::None; 35 36 Block &block = region.front(); 37 if (block.getNumArguments() != 2 || 38 !block.getArgument(0).getType().isSignlessIntOrFloat() || 39 !block.getArgument(1).getType().isSignlessIntOrFloat()) 40 return llvm::None; 41 42 auto &ops = block.getOperations(); 43 if (!llvm::hasSingleElement(block.without_terminator())) 44 return llvm::None; 45 46 using mlir::matchers::m_Val; 47 auto a = m_Val(block.getArgument(0)); 48 auto b = m_Val(block.getArgument(1)); 49 50 auto addPattern = m_Op<linalg::YieldOp>(m_Op<AddIOp>(a, b)); 51 if (addPattern.match(&ops.back())) 52 return BinaryOpKind::IAdd; 53 54 return llvm::None; 55 } 56 57 static Value emitOrFoldComposedAffineApply(OpBuilder &b, Location loc, 58 AffineMap map, 59 ArrayRef<Value> operandsRef, 60 OperationFolder *folder) { 61 SmallVector<Value, 4> operands(operandsRef.begin(), operandsRef.end()); 62 fullyComposeAffineMapAndOperands(&map, &operands); 63 canonicalizeMapAndOperands(&map, &operands); 64 return folder ? folder->create<AffineApplyOp>(b, loc, map, operands) 65 : b.create<AffineApplyOp>(loc, map, operands); 66 } 67 68 SmallVector<Value, 4> mlir::linalg::applyMapToValues(OpBuilder &b, Location loc, 69 AffineMap map, 70 ArrayRef<Value> values, 71 OperationFolder *folder) { 72 SmallVector<Value, 4> res; 73 res.reserve(map.getNumResults()); 74 unsigned numDims = map.getNumDims(); 75 // For each `expr` in `map`, applies the `expr` to the values extracted from 76 // ranges. If the resulting application can be folded into a Value, the 77 // folding occurs eagerly. Otherwise, an affine.apply operation is emitted. 78 for (auto expr : map.getResults()) { 79 AffineMap map = AffineMap::get(numDims, 0, expr); 80 res.push_back(emitOrFoldComposedAffineApply(b, loc, map, values, folder)); 81 } 82 return res; 83 } 84 85 /// Returns all the operands of `linalgOp` that are not views. 86 /// Asserts that these operands are value types to allow transformations like 87 /// tiling to just use the values when cloning `linalgOp`. 88 SmallVector<Value, 4> 89 mlir::linalg::getAssumedNonViewOperands(LinalgOp linalgOp) { 90 auto *op = linalgOp.getOperation(); 91 unsigned numViews = linalgOp.getNumInputsAndOutputs(); 92 unsigned nOperands = op->getNumOperands() - numViews; 93 SmallVector<Value, 4> res; 94 res.reserve(nOperands); 95 for (unsigned i = 0; i < nOperands; ++i) { 96 res.push_back(op->getOperand(numViews + i)); 97 auto t = res.back().getType(); 98 (void)t; 99 assert((t.isSignlessIntOrIndexOrFloat() || t.isa<VectorType>()) && 100 "expected scalar or vector type"); 101 } 102 return res; 103 } 104