1 //===- Dialect.cpp - Implementation of the linalg dialect and types -------===// 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 the Linalg dialect types and dialect. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "mlir/Dialect/Bufferization/IR/BufferizableOpInterface.h" 14 #include "mlir/Dialect/Linalg/IR/Linalg.h" 15 #include "mlir/IR/BuiltinTypes.h" 16 #include "mlir/IR/Dialect.h" 17 #include "mlir/IR/DialectImplementation.h" 18 #include "mlir/IR/FunctionInterfaces.h" 19 #include "mlir/Parser/Parser.h" 20 #include "mlir/Support/LLVM.h" 21 #include "mlir/Transforms/InliningUtils.h" 22 23 #include "llvm/ADT/StringExtras.h" 24 #include "llvm/ADT/TypeSwitch.h" 25 #include "llvm/Support/raw_ostream.h" 26 27 using namespace mlir; 28 using namespace mlir::linalg; 29 30 //===----------------------------------------------------------------------===// 31 // LinalgDialect Dialect Interfaces 32 //===----------------------------------------------------------------------===// 33 34 namespace { 35 36 struct LinalgInlinerInterface : public DialectInlinerInterface { 37 using DialectInlinerInterface::DialectInlinerInterface; 38 39 // We don't have any special restrictions on what can be inlined into 40 // destination regions (e.g. while/conditional bodies). Always allow it. 41 bool isLegalToInline(Region *dest, Region *src, bool wouldBeCloned, 42 BlockAndValueMapping &valueMapping) const final { 43 return true; 44 } 45 // Operations in Linalg dialect are always legal to inline. 46 bool isLegalToInline(Operation *, Region *, bool, 47 BlockAndValueMapping &) const final { 48 return true; 49 } 50 // Handle the given inlined terminator by replacing it with a new operation 51 // as necessary. Required when the region has only one block. 52 void handleTerminator(Operation *op, 53 ArrayRef<Value> valuesToRepl) const final {} 54 }; 55 56 } // namespace 57 58 //===----------------------------------------------------------------------===// 59 // LinalgDialect 60 //===----------------------------------------------------------------------===// 61 62 /// Attribute name used to to memoize indexing maps for named ops. 63 constexpr const ::llvm::StringLiteral 64 LinalgDialect::kMemoizedIndexingMapsAttrName; 65 66 /// Trait to check if T provides a `regionBuilder` method. 67 template <typename T, typename... Args> 68 using has_region_builder = decltype(T::regionBuilder); 69 template <typename T> 70 using detect_has_region_builder = llvm::is_detected<has_region_builder, T>; 71 72 /// SFINAE helper for single C++ class without a `regionBuilder` method (e.g. 73 /// an OpInterface). 74 template <typename OpType, typename = std::enable_if_t< 75 !detect_has_region_builder<OpType>::value>> 76 void addNamedOpBuilderImpl( 77 llvm::StringMap<LinalgDialect::RegionBuilderFunType> &map) { 78 // Do nothing. 79 } 80 81 template <typename OpType, 82 typename = std::enable_if_t<detect_has_region_builder<OpType>::value>, 83 typename = void> 84 void addNamedOpBuilderImpl( 85 llvm::StringMap<LinalgDialect::RegionBuilderFunType> &map) { 86 map.insert(std::make_pair( 87 OpType::getOperationName(), 88 static_cast<LinalgDialect::RegionBuilderFunType>(OpType::regionBuilder))); 89 } 90 91 template <typename... OpTypes> 92 void addNamedOpBuilders( 93 llvm::StringMap<LinalgDialect::RegionBuilderFunType> &map) { 94 (void)std::initializer_list<int>{0, 95 (addNamedOpBuilderImpl<OpTypes>(map), 0)...}; 96 } 97 98 void mlir::linalg::LinalgDialect::initialize() { 99 addAttributes< 100 #define GET_ATTRDEF_LIST 101 #include "mlir/Dialect/Linalg/IR/LinalgOpsAttrDefs.cpp.inc" 102 >(); 103 addOperations< 104 #define GET_OP_LIST 105 #include "mlir/Dialect/Linalg/IR/LinalgOps.cpp.inc" 106 >(); 107 addOperations< 108 #define GET_OP_LIST 109 #include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc" 110 >(); 111 112 // Fill the Linalg-specific OpName to RegionBuilder map. 113 addNamedOpBuilders< 114 #define GET_OP_LIST 115 #include "mlir/Dialect/Linalg/IR/LinalgStructuredOps.cpp.inc" 116 >(namedStructuredOpRegionBuilders); 117 118 addInterfaces<LinalgInlinerInterface>(); 119 } 120 121 LogicalResult LinalgDialect::verifyOperationAttribute(Operation *op, 122 NamedAttribute attr) { 123 using bufferization::BufferizableOpInterface; 124 125 if (attr.getName() == BufferizableOpInterface::kInplaceableAttrName) { 126 if (!attr.getValue().isa<BoolAttr>()) { 127 return op->emitError() 128 << "'" << BufferizableOpInterface::kInplaceableAttrName 129 << "' is expected to be a boolean attribute"; 130 } 131 if (!isa<FunctionOpInterface>(op)) 132 return op->emitError() << "expected " << attr.getName() 133 << " to be used on function-like operations"; 134 return success(); 135 } 136 if (attr.getName() == BufferizableOpInterface::kBufferLayoutAttrName) { 137 if (!attr.getValue().isa<AffineMapAttr>()) { 138 return op->emitError() 139 << "'" << BufferizableOpInterface::kBufferLayoutAttrName 140 << "' is expected to be a affine map attribute"; 141 } 142 if (!isa<FunctionOpInterface>(op)) 143 return op->emitError() << "expected " << attr.getName() 144 << " to be used on function-like operations"; 145 return success(); 146 } 147 if (attr.getName() == LinalgDialect::kMemoizedIndexingMapsAttrName) 148 return success(); 149 return op->emitError() << "attribute '" << attr.getName() 150 << "' not supported by the linalg dialect"; 151 } 152 153 #include "mlir/Dialect/Linalg/IR/LinalgOpsEnums.cpp.inc" 154 155 #define GET_ATTRDEF_CLASSES 156 #include "mlir/Dialect/Linalg/IR/LinalgOpsAttrDefs.cpp.inc" 157 158 #include "mlir/Dialect/Linalg/IR/LinalgOpsDialect.cpp.inc" 159