1 | //===- BuiltinDialect.cpp - MLIR Builtin 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 contains the Builtin dialect that contains all of the attributes, |
10 | // operations, and types that are necessary for the validity of the IR. |
11 | // |
12 | //===----------------------------------------------------------------------===// |
13 | |
14 | #include "mlir/IR/BuiltinDialect.h" |
15 | #include "BuiltinDialectBytecode.h" |
16 | #include "mlir/IR/Builders.h" |
17 | #include "mlir/IR/BuiltinOps.h" |
18 | #include "mlir/IR/BuiltinTypes.h" |
19 | #include "mlir/IR/DialectResourceBlobManager.h" |
20 | #include "mlir/IR/IRMapping.h" |
21 | #include "mlir/IR/OpImplementation.h" |
22 | #include "mlir/IR/PatternMatch.h" |
23 | #include "mlir/IR/TypeRange.h" |
24 | |
25 | using namespace mlir; |
26 | |
27 | //===----------------------------------------------------------------------===// |
28 | // TableGen'erated dialect |
29 | //===----------------------------------------------------------------------===// |
30 | |
31 | #include "mlir/IR/BuiltinDialect.cpp.inc" |
32 | |
33 | //===----------------------------------------------------------------------===// |
34 | // BuiltinBlobManagerInterface |
35 | //===----------------------------------------------------------------------===// |
36 | |
37 | using BuiltinBlobManagerInterface = |
38 | ResourceBlobManagerDialectInterfaceBase<DenseResourceElementsHandle>; |
39 | |
40 | //===----------------------------------------------------------------------===// |
41 | // BuiltinOpAsmDialectInterface |
42 | //===----------------------------------------------------------------------===// |
43 | |
44 | namespace { |
45 | struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface { |
46 | BuiltinOpAsmDialectInterface(Dialect *dialect, |
47 | BuiltinBlobManagerInterface &mgr) |
48 | : OpAsmDialectInterface(dialect), blobManager(mgr) {} |
49 | |
50 | AliasResult getAlias(Attribute attr, raw_ostream &os) const override { |
51 | if (llvm::isa<AffineMapAttr>(Val: attr)) { |
52 | os << "map" ; |
53 | return AliasResult::OverridableAlias; |
54 | } |
55 | if (llvm::isa<IntegerSetAttr>(Val: attr)) { |
56 | os << "set" ; |
57 | return AliasResult::OverridableAlias; |
58 | } |
59 | if (llvm::isa<LocationAttr>(Val: attr)) { |
60 | os << "loc" ; |
61 | return AliasResult::OverridableAlias; |
62 | } |
63 | if (auto distinct = llvm::dyn_cast<DistinctAttr>(attr)) |
64 | if (!llvm::isa<UnitAttr>(Val: distinct.getReferencedAttr())) { |
65 | os << "distinct" ; |
66 | return AliasResult::OverridableAlias; |
67 | } |
68 | return AliasResult::NoAlias; |
69 | } |
70 | |
71 | AliasResult getAlias(Type type, raw_ostream &os) const final { |
72 | if (auto tupleType = llvm::dyn_cast<TupleType>(type)) { |
73 | if (tupleType.size() > 16) { |
74 | os << "tuple" ; |
75 | return AliasResult::OverridableAlias; |
76 | } |
77 | } |
78 | return AliasResult::NoAlias; |
79 | } |
80 | |
81 | //===------------------------------------------------------------------===// |
82 | // Resources |
83 | //===------------------------------------------------------------------===// |
84 | |
85 | std::string |
86 | getResourceKey(const AsmDialectResourceHandle &handle) const override { |
87 | return cast<DenseResourceElementsHandle>(Val: handle).getKey().str(); |
88 | } |
89 | FailureOr<AsmDialectResourceHandle> |
90 | declareResource(StringRef key) const final { |
91 | return blobManager.insert(name: key); |
92 | } |
93 | LogicalResult parseResource(AsmParsedResourceEntry &entry) const final { |
94 | FailureOr<AsmResourceBlob> blob = entry.parseAsBlob(); |
95 | if (failed(result: blob)) |
96 | return failure(); |
97 | |
98 | // Update the blob for this entry. |
99 | blobManager.update(name: entry.getKey(), newBlob: std::move(*blob)); |
100 | return success(); |
101 | } |
102 | void |
103 | buildResources(Operation *op, |
104 | const SetVector<AsmDialectResourceHandle> &referencedResources, |
105 | AsmResourceBuilder &provider) const final { |
106 | blobManager.buildResources(provider, referencedResources: referencedResources.getArrayRef()); |
107 | } |
108 | |
109 | private: |
110 | /// The blob manager for the dialect. |
111 | BuiltinBlobManagerInterface &blobManager; |
112 | }; |
113 | } // namespace |
114 | |
115 | void BuiltinDialect::initialize() { |
116 | registerTypes(); |
117 | registerAttributes(); |
118 | registerLocationAttributes(); |
119 | addOperations< |
120 | #define GET_OP_LIST |
121 | #include "mlir/IR/BuiltinOps.cpp.inc" |
122 | >(); |
123 | |
124 | auto &blobInterface = addInterface<BuiltinBlobManagerInterface>(); |
125 | addInterface<BuiltinOpAsmDialectInterface>(blobInterface); |
126 | builtin_dialect_detail::addBytecodeInterface(this); |
127 | } |
128 | |
129 | //===----------------------------------------------------------------------===// |
130 | // ModuleOp |
131 | //===----------------------------------------------------------------------===// |
132 | |
133 | void ModuleOp::build(OpBuilder &builder, OperationState &state, |
134 | std::optional<StringRef> name) { |
135 | state.addRegion()->emplaceBlock(); |
136 | if (name) { |
137 | state.attributes.push_back(builder.getNamedAttr( |
138 | mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name))); |
139 | } |
140 | } |
141 | |
142 | /// Construct a module from the given context. |
143 | ModuleOp ModuleOp::create(Location loc, std::optional<StringRef> name) { |
144 | OpBuilder builder(loc->getContext()); |
145 | return builder.create<ModuleOp>(loc, name); |
146 | } |
147 | |
148 | DataLayoutSpecInterface ModuleOp::getDataLayoutSpec() { |
149 | // Take the first and only (if present) attribute that implements the |
150 | // interface. This needs a linear search, but is called only once per data |
151 | // layout object construction that is used for repeated queries. |
152 | for (NamedAttribute attr : getOperation()->getAttrs()) |
153 | if (auto spec = llvm::dyn_cast<DataLayoutSpecInterface>(attr.getValue())) |
154 | return spec; |
155 | return {}; |
156 | } |
157 | |
158 | LogicalResult ModuleOp::verify() { |
159 | // Check that none of the attributes are non-dialect attributes, except for |
160 | // the symbol related attributes. |
161 | for (auto attr : (*this)->getAttrs()) { |
162 | if (!attr.getName().strref().contains('.') && |
163 | !llvm::is_contained( |
164 | ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(), |
165 | mlir::SymbolTable::getVisibilityAttrName()}, |
166 | attr.getName().strref())) |
167 | return emitOpError() << "can only contain attributes with " |
168 | "dialect-prefixed names, found: '" |
169 | << attr.getName().getValue() << "'" ; |
170 | } |
171 | |
172 | // Check that there is at most one data layout spec attribute. |
173 | StringRef layoutSpecAttrName; |
174 | DataLayoutSpecInterface layoutSpec; |
175 | for (const NamedAttribute &na : (*this)->getAttrs()) { |
176 | if (auto spec = llvm::dyn_cast<DataLayoutSpecInterface>(na.getValue())) { |
177 | if (layoutSpec) { |
178 | InFlightDiagnostic diag = |
179 | emitOpError() << "expects at most one data layout attribute" ; |
180 | diag.attachNote() << "'" << layoutSpecAttrName |
181 | << "' is a data layout attribute" ; |
182 | diag.attachNote() << "'" << na.getName().getValue() |
183 | << "' is a data layout attribute" ; |
184 | } |
185 | layoutSpecAttrName = na.getName().strref(); |
186 | layoutSpec = spec; |
187 | } |
188 | } |
189 | |
190 | return success(); |
191 | } |
192 | |
193 | //===----------------------------------------------------------------------===// |
194 | // UnrealizedConversionCastOp |
195 | //===----------------------------------------------------------------------===// |
196 | |
197 | LogicalResult |
198 | UnrealizedConversionCastOp::fold(FoldAdaptor adaptor, |
199 | SmallVectorImpl<OpFoldResult> &foldResults) { |
200 | OperandRange operands = getInputs(); |
201 | ResultRange results = getOutputs(); |
202 | |
203 | if (operands.getType() == results.getType()) { |
204 | foldResults.append(operands.begin(), operands.end()); |
205 | return success(); |
206 | } |
207 | |
208 | if (operands.empty()) |
209 | return failure(); |
210 | |
211 | // Check that the input is a cast with results that all feed into this |
212 | // operation, and operand types that directly match the result types of this |
213 | // operation. |
214 | Value firstInput = operands.front(); |
215 | auto inputOp = firstInput.getDefiningOp<UnrealizedConversionCastOp>(); |
216 | if (!inputOp || inputOp.getResults() != operands || |
217 | inputOp.getOperandTypes() != results.getTypes()) |
218 | return failure(); |
219 | |
220 | // If everything matches up, we can fold the passthrough. |
221 | foldResults.append(inputOp->operand_begin(), inputOp->operand_end()); |
222 | return success(); |
223 | } |
224 | |
225 | LogicalResult UnrealizedConversionCastOp::verify() { |
226 | // TODO: The verifier of external models is not called. This op verifier can |
227 | // be removed when that is fixed. |
228 | if (getNumResults() == 0) |
229 | return emitOpError() << "expected at least one result for cast operation" ; |
230 | return success(); |
231 | } |
232 | |
233 | //===----------------------------------------------------------------------===// |
234 | // TableGen'd op method definitions |
235 | //===----------------------------------------------------------------------===// |
236 | |
237 | #define GET_OP_CLASSES |
238 | #include "mlir/IR/BuiltinOps.cpp.inc" |
239 | |