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 "mlir/IR/BlockAndValueMapping.h"
16 #include "mlir/IR/Builders.h"
17 #include "mlir/IR/BuiltinOps.h"
18 #include "mlir/IR/BuiltinTypes.h"
19 #include "mlir/IR/OpImplementation.h"
20 #include "mlir/IR/PatternMatch.h"
21 
22 using namespace mlir;
23 
24 //===----------------------------------------------------------------------===//
25 // Builtin Dialect
26 //===----------------------------------------------------------------------===//
27 
28 #include "mlir/IR/BuiltinDialect.cpp.inc"
29 
30 namespace {
31 struct BuiltinOpAsmDialectInterface : public OpAsmDialectInterface {
32   using OpAsmDialectInterface::OpAsmDialectInterface;
33 
34   AliasResult getAlias(Attribute attr, raw_ostream &os) const override {
35     if (attr.isa<AffineMapAttr>()) {
36       os << "map";
37       return AliasResult::OverridableAlias;
38     }
39     if (attr.isa<IntegerSetAttr>()) {
40       os << "set";
41       return AliasResult::OverridableAlias;
42     }
43     if (attr.isa<LocationAttr>()) {
44       os << "loc";
45       return AliasResult::OverridableAlias;
46     }
47     return AliasResult::NoAlias;
48   }
49 
50   AliasResult getAlias(Type type, raw_ostream &os) const final {
51     if (auto tupleType = type.dyn_cast<TupleType>()) {
52       if (tupleType.size() > 16) {
53         os << "tuple";
54         return AliasResult::OverridableAlias;
55       }
56     }
57     return AliasResult::NoAlias;
58   }
59 };
60 } // namespace
61 
62 void BuiltinDialect::initialize() {
63   registerTypes();
64   registerAttributes();
65   registerLocationAttributes();
66   addOperations<
67 #define GET_OP_LIST
68 #include "mlir/IR/BuiltinOps.cpp.inc"
69       >();
70   addInterfaces<BuiltinOpAsmDialectInterface>();
71 }
72 
73 //===----------------------------------------------------------------------===//
74 // ModuleOp
75 //===----------------------------------------------------------------------===//
76 
77 void ModuleOp::build(OpBuilder &builder, OperationState &state,
78                      Optional<StringRef> name) {
79   state.addRegion()->emplaceBlock();
80   if (name) {
81     state.attributes.push_back(builder.getNamedAttr(
82         mlir::SymbolTable::getSymbolAttrName(), builder.getStringAttr(*name)));
83   }
84 }
85 
86 /// Construct a module from the given context.
87 ModuleOp ModuleOp::create(Location loc, Optional<StringRef> name) {
88   OpBuilder builder(loc->getContext());
89   return builder.create<ModuleOp>(loc, name);
90 }
91 
92 DataLayoutSpecInterface ModuleOp::getDataLayoutSpec() {
93   // Take the first and only (if present) attribute that implements the
94   // interface. This needs a linear search, but is called only once per data
95   // layout object construction that is used for repeated queries.
96   for (NamedAttribute attr : getOperation()->getAttrs())
97     if (auto spec = attr.getValue().dyn_cast<DataLayoutSpecInterface>())
98       return spec;
99   return {};
100 }
101 
102 LogicalResult ModuleOp::verify() {
103   // Check that none of the attributes are non-dialect attributes, except for
104   // the symbol related attributes.
105   for (auto attr : (*this)->getAttrs()) {
106     if (!attr.getName().strref().contains('.') &&
107         !llvm::is_contained(
108             ArrayRef<StringRef>{mlir::SymbolTable::getSymbolAttrName(),
109                                 mlir::SymbolTable::getVisibilityAttrName()},
110             attr.getName().strref()))
111       return emitOpError() << "can only contain attributes with "
112                               "dialect-prefixed names, found: '"
113                            << attr.getName().getValue() << "'";
114   }
115 
116   // Check that there is at most one data layout spec attribute.
117   StringRef layoutSpecAttrName;
118   DataLayoutSpecInterface layoutSpec;
119   for (const NamedAttribute &na : (*this)->getAttrs()) {
120     if (auto spec = na.getValue().dyn_cast<DataLayoutSpecInterface>()) {
121       if (layoutSpec) {
122         InFlightDiagnostic diag =
123             emitOpError() << "expects at most one data layout attribute";
124         diag.attachNote() << "'" << layoutSpecAttrName
125                           << "' is a data layout attribute";
126         diag.attachNote() << "'" << na.getName().getValue()
127                           << "' is a data layout attribute";
128       }
129       layoutSpecAttrName = na.getName().strref();
130       layoutSpec = spec;
131     }
132   }
133 
134   return success();
135 }
136 
137 //===----------------------------------------------------------------------===//
138 // UnrealizedConversionCastOp
139 //===----------------------------------------------------------------------===//
140 
141 LogicalResult
142 UnrealizedConversionCastOp::fold(ArrayRef<Attribute> attrOperands,
143                                  SmallVectorImpl<OpFoldResult> &foldResults) {
144   OperandRange operands = getInputs();
145   ResultRange results = getOutputs();
146 
147   if (operands.getType() == results.getType()) {
148     foldResults.append(operands.begin(), operands.end());
149     return success();
150   }
151 
152   if (operands.empty())
153     return failure();
154 
155   // Check that the input is a cast with results that all feed into this
156   // operation, and operand types that directly match the result types of this
157   // operation.
158   Value firstInput = operands.front();
159   auto inputOp = firstInput.getDefiningOp<UnrealizedConversionCastOp>();
160   if (!inputOp || inputOp.getResults() != operands ||
161       inputOp.getOperandTypes() != results.getTypes())
162     return failure();
163 
164   // If everything matches up, we can fold the passthrough.
165   foldResults.append(inputOp->operand_begin(), inputOp->operand_end());
166   return success();
167 }
168 
169 bool UnrealizedConversionCastOp::areCastCompatible(TypeRange inputs,
170                                                    TypeRange outputs) {
171   // `UnrealizedConversionCastOp` is agnostic of the input/output types.
172   return true;
173 }
174 
175 //===----------------------------------------------------------------------===//
176 // TableGen'd op method definitions
177 //===----------------------------------------------------------------------===//
178 
179 #define GET_OP_CLASSES
180 #include "mlir/IR/BuiltinOps.cpp.inc"
181