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