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.
46   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.
51   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.
57   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>>
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>
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>
97 void addNamedOpBuilders(
98     llvm::StringMap<LinalgDialect::RegionBuilderFunType> &map) {
99   (void)std::initializer_list<int>{0,
100                                    (addNamedOpBuilderImpl<OpTypes>(map), 0)...};
101 }
102 
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 
126 LogicalResult LinalgDialect::verifyOperationAttribute(Operation *op,
127                                                       NamedAttribute attr) {
128   using bufferization::BufferizableOpInterface;
129 
130   if (attr.getName() == BufferizableOpInterface::kInplaceableAttrName) {
131     if (!attr.getValue().isa<BoolAttr>()) {
132       return op->emitError()
133              << "'" << BufferizableOpInterface::kInplaceableAttrName
134              << "' is expected to be a boolean attribute";
135     }
136     if (!isa<FunctionOpInterface>(op))
137       return op->emitError() << "expected " << attr.getName()
138                              << " to be used on function-like operations";
139     return success();
140   }
141   if (attr.getName() == LinalgDialect::kMemoizedIndexingMapsAttrName)
142     return success();
143   return op->emitError() << "attribute '" << attr.getName()
144                          << "' not supported by the linalg dialect";
145 }
146 
147 #include "mlir/Dialect/Linalg/IR/LinalgOpsEnums.cpp.inc"
148 
149 #define GET_ATTRDEF_CLASSES
150 #include "mlir/Dialect/Linalg/IR/LinalgOpsAttrDefs.cpp.inc"
151 
152 #include "mlir/Dialect/Linalg/IR/LinalgOpsDialect.cpp.inc"
153