MLIR  21.0.0git
BufferizationDialect.cpp
Go to the documentation of this file.
1 //===----------------------------------------------------------------------===//
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 
15 #include "mlir/IR/BuiltinTypes.h"
18 
19 using namespace mlir;
20 using namespace mlir::bufferization;
21 
22 #include "mlir/Dialect/Bufferization/IR/BufferizationOpsDialect.cpp.inc"
23 
24 /// Attribute name used to mark function arguments who's buffers can be written
25 /// to during One-Shot Module Bufferize.
26 constexpr const ::llvm::StringLiteral BufferizationDialect::kWritableAttrName;
27 
28 /// Attribute name used to mark the bufferization layout for region arguments
29 /// during One-Shot Module Bufferize.
30 constexpr const ::llvm::StringLiteral
31  BufferizationDialect::kBufferLayoutAttrName;
32 
33 /// An attribute that can be attached to ops with an allocation and/or
34 /// deallocation side effect. It indicates that the op is under a "manual
35 /// deallocation" scheme. In the case of an allocation op, the returned
36 /// value is *not* an automatically managed allocation and assigned an
37 /// ownership of "false". Furthermore, only deallocation ops that are
38 /// guaranteed to deallocate a buffer under "manual deallocation" are
39 /// allowed to have this attribute. (Deallocation ops without this
40 /// attribute are rejected by the ownership-based buffer deallocation pass.)
41 constexpr const ::llvm::StringLiteral BufferizationDialect::kManualDeallocation;
42 
43 //===----------------------------------------------------------------------===//
44 // Bufferization Dialect Interfaces
45 //===----------------------------------------------------------------------===//
46 
47 namespace {
48 struct BufferizationInlinerInterface : public DialectInlinerInterface {
50 
51  /// Operations in Bufferization dialect are always legal to inline.
52  bool isLegalToInline(Operation *, Region *, bool, IRMapping &) const final {
53  return true;
54  }
55 };
56 
57 template <typename Tensor>
58 struct BuiltinTensorExternalModel
59  : TensorLikeType::ExternalModel<BuiltinTensorExternalModel<Tensor>,
60  Tensor> {
61  llvm::FailureOr<BufferLikeType> getBufferType(
64  auto tensorType = cast<TensorType>(tensor);
65  auto memSpace = options.defaultMemorySpaceFn(tensorType);
66  if (!memSpace.has_value())
67  return emitError() << "could not infer memory space";
68 
69  return cast<BufferLikeType>(
70  getMemRefType(tensorType, options, /*layout=*/{}, *memSpace));
71  }
72 
73  mlir::LogicalResult verifyCompatibleBufferType(
74  mlir::Type tensor, BufferLikeType bufferType,
76  assert(isa<TensorType>(tensor) && "expected tensor type");
77  assert(isa<BaseMemRefType>(bufferType) && "expected memref type");
78 
79  auto tensorType = cast<ShapedType>(tensor);
80  auto memrefType = cast<ShapedType>(bufferType);
81 
82  if (tensorType.getShape() != memrefType.getShape())
83  return emitError() << "shapes do not match";
84 
85  if (tensorType.getElementType() != memrefType.getElementType())
86  return emitError() << "element types do not match";
87 
88  return mlir::success();
89  }
90 };
91 
92 template <typename MemRef>
93 struct BuiltinMemRefExternalModel
94  : BufferLikeType::ExternalModel<BuiltinMemRefExternalModel<MemRef>,
95  MemRef> {};
96 } // namespace
97 
98 //===----------------------------------------------------------------------===//
99 // Bufferization Dialect
100 //===----------------------------------------------------------------------===//
101 
102 void mlir::bufferization::BufferizationDialect::initialize() {
103  addOperations<
104 #define GET_OP_LIST
105 #include "mlir/Dialect/Bufferization/IR/BufferizationOps.cpp.inc"
106  >();
107  addInterfaces<BufferizationInlinerInterface>();
108 
109  // Note: Unlike with other external models, declaring bufferization's
110  // "promised interfaces" in builtins for TensorLike and BufferLike type
111  // interfaces is not possible (due to builtins being independent of
112  // bufferization). Thus, the compromise is to attach these interfaces directly
113  // during dialect initialization.
114  RankedTensorType::attachInterface<
115  BuiltinTensorExternalModel<RankedTensorType>>(*getContext());
116  UnrankedTensorType::attachInterface<
117  BuiltinTensorExternalModel<UnrankedTensorType>>(*getContext());
118  MemRefType::attachInterface<BuiltinMemRefExternalModel<MemRefType>>(
119  *getContext());
120  UnrankedMemRefType::attachInterface<
121  BuiltinMemRefExternalModel<UnrankedMemRefType>>(*getContext());
122 }
123 
124 LogicalResult BufferizationDialect::verifyRegionArgAttribute(
125  Operation *op, unsigned /*regionIndex*/, unsigned argIndex,
126  NamedAttribute attr) {
127  if (attr.getName() == kWritableAttrName) {
128  if (!llvm::isa<BoolAttr>(attr.getValue())) {
129  return op->emitError() << "'" << kWritableAttrName
130  << "' is expected to be a boolean attribute";
131  }
132  if (!isa<FunctionOpInterface>(op))
133  return op->emitError() << "expected '" << kWritableAttrName
134  << "' to be used on function-like operations";
135  if (cast<FunctionOpInterface>(op).isExternal())
136  return op->emitError() << "'" << kWritableAttrName
137  << "' is invalid on external functions";
138  return success();
139  }
140  if (attr.getName() == kBufferAccessAttrName) {
141  if (!llvm::isa<StringAttr>(attr.getValue())) {
142  return op->emitError() << "'" << kBufferAccessAttrName
143  << "' is expected to be a string attribute";
144  }
145  StringRef str = llvm::cast<StringAttr>(attr.getValue()).getValue();
146  if (str != "none" && str != "read" && str != "write" && str != "read-write")
147  return op->emitError()
148  << "invalid value for '" << kBufferAccessAttrName << "'";
149  if (!isa<FunctionOpInterface>(op))
150  return op->emitError() << "expected '" << kBufferAccessAttrName
151  << "' to be used on function-like operations";
152  return success();
153  }
154  if (attr.getName() == kBufferLayoutAttrName) {
155  if (!llvm::isa<MemRefLayoutAttrInterface>(attr.getValue())) {
156  return op->emitError() << "'" << kBufferLayoutAttrName
157  << "' is expected to be a memref layout attribute";
158  }
159  if (!isa<FunctionOpInterface>(op))
160  return op->emitError() << "expected '" << kBufferLayoutAttrName
161  << "' to be used on function-like operations";
162  return success();
163  }
164  return op->emitError() << "attribute '" << kBufferLayoutAttrName
165  << "' not supported as a region arg attribute by the "
166  "bufferization dialect";
167 }
168 
169 LogicalResult
170 BufferizationDialect::verifyOperationAttribute(Operation *op,
171  NamedAttribute attr) {
172  using bufferization::BufferizableOpInterface;
173 
174  if (attr.getName() == kManualDeallocation) {
175  if (!mlir::hasEffect<MemoryEffects::Allocate>(op) &&
176  !mlir::hasEffect<MemoryEffects::Free>(op))
177  return op->emitOpError("attribute '")
178  << kManualDeallocation
179  << "' can be used only on ops that have an allocation and/or free "
180  "side effect";
181  return success();
182  }
183 
184  return op->emitError()
185  << "attribute '" << attr.getName()
186  << "' not supported as an op attribute by the bufferization dialect";
187 }
static MLIRContext * getContext(OpFoldResult val)
static bool isLegalToInline(InlinerInterface &interface, Region *src, Region *insertRegion, bool shouldCloneInlinedRegion, IRMapping &valueMapping)
Utility to check that all of the operations within 'src' can be inlined.
static llvm::ManagedStatic< PassManagerOptions > options
This is the interface that must be implemented by the dialects of operations to be inlined.
Definition: InliningUtils.h:44
DialectInlinerInterface(Dialect *dialect)
Definition: InliningUtils.h:46
This is a utility class for mapping one set of IR entities to another.
Definition: IRMapping.h:26
This class represents a diagnostic that is inflight and set to be reported.
Definition: Diagnostics.h:314
NamedAttribute represents a combination of a name and an Attribute value.
Definition: Attributes.h:164
StringAttr getName() const
Return the name of the attribute.
Definition: Attributes.cpp:55
Attribute getValue() const
Return the value of the attribute.
Definition: Attributes.h:179
Operation is the basic unit of execution within MLIR.
Definition: Operation.h:88
InFlightDiagnostic emitError(const Twine &message={})
Emit an error about fatal conditions with this operation, reporting up to any diagnostic handlers tha...
Definition: Operation.cpp:268
InFlightDiagnostic emitOpError(const Twine &message={})
Emit an error with the op name prefixed, like "'dim' op " which is convenient for verifiers.
Definition: Operation.cpp:673
This class contains a list of basic blocks and a link to the parent operation it is attached to.
Definition: Region.h:26
Instances of the Type class are uniqued, have an immutable identifier and an optional mutable compone...
Definition: Types.h:74
BaseMemRefType getMemRefType(TensorType tensorType, const BufferizationOptions &options, MemRefLayoutAttrInterface layout={}, Attribute memorySpace=nullptr)
Return a MemRefType to which the TensorType can be bufferized.
FailureOr< BufferLikeType > getBufferType(Value value, const BufferizationOptions &options, const BufferizationState &state)
Return the buffer type for a given Value (tensor) after bufferization without bufferizing any IR.
Include the generated interface declarations.
InFlightDiagnostic emitError(Location loc)
Utility method to emit an error message using this location.
Options for BufferizableOpInterface-based bufferization.