1 //===- EmitC.cpp - EmitC 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 #include "mlir/Dialect/EmitC/IR/EmitC.h"
10 #include "mlir/IR/Builders.h"
11 #include "mlir/IR/DialectImplementation.h"
12 #include "llvm/ADT/TypeSwitch.h"
13 
14 using namespace mlir;
15 using namespace mlir::emitc;
16 
17 #include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc"
18 
19 //===----------------------------------------------------------------------===//
20 // EmitCDialect
21 //===----------------------------------------------------------------------===//
22 
23 void EmitCDialect::initialize() {
24   addOperations<
25 #define GET_OP_LIST
26 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
27       >();
28   addTypes<
29 #define GET_TYPEDEF_LIST
30 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
31       >();
32   addAttributes<
33 #define GET_ATTRDEF_LIST
34 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
35       >();
36 }
37 
38 /// Materialize a single constant operation from a given attribute value with
39 /// the desired resultant type.
40 Operation *EmitCDialect::materializeConstant(OpBuilder &builder,
41                                              Attribute value, Type type,
42                                              Location loc) {
43   return builder.create<ConstantOp>(loc, type, value);
44 }
45 
46 //===----------------------------------------------------------------------===//
47 // ApplyOp
48 //===----------------------------------------------------------------------===//
49 
50 static LogicalResult verify(ApplyOp op) {
51   StringRef applicableOperator = op.applicableOperator();
52 
53   // Applicable operator must not be empty.
54   if (applicableOperator.empty())
55     return op.emitOpError("applicable operator must not be empty");
56 
57   // Only `*` and `&` are supported.
58   if (applicableOperator != "&" && applicableOperator != "*")
59     return op.emitOpError("applicable operator is illegal");
60 
61   return success();
62 }
63 
64 //===----------------------------------------------------------------------===//
65 // CallOp
66 //===----------------------------------------------------------------------===//
67 
68 static LogicalResult verify(emitc::CallOp op) {
69   // Callee must not be empty.
70   if (op.callee().empty())
71     return op.emitOpError("callee must not be empty");
72 
73   if (Optional<ArrayAttr> argsAttr = op.args()) {
74     for (Attribute arg : argsAttr.getValue()) {
75       if (arg.getType().isa<IndexType>()) {
76         int64_t index = arg.cast<IntegerAttr>().getInt();
77         // Args with elements of type index must be in range
78         // [0..operands.size).
79         if ((index < 0) || (index >= static_cast<int64_t>(op.getNumOperands())))
80           return op.emitOpError("index argument is out of range");
81 
82         // Args with elements of type ArrayAttr must have a type.
83       } else if (arg.isa<ArrayAttr>() && arg.getType().isa<NoneType>()) {
84         return op.emitOpError("array argument has no type");
85       }
86     }
87   }
88 
89   if (Optional<ArrayAttr> templateArgsAttr = op.template_args()) {
90     for (Attribute tArg : templateArgsAttr.getValue()) {
91       if (!tArg.isa<TypeAttr>() && !tArg.isa<IntegerAttr>() &&
92           !tArg.isa<FloatAttr>() && !tArg.isa<emitc::OpaqueAttr>())
93         return op.emitOpError("template argument has invalid type");
94     }
95   }
96 
97   return success();
98 }
99 
100 //===----------------------------------------------------------------------===//
101 // ConstantOp
102 //===----------------------------------------------------------------------===//
103 
104 /// The constant op requires that the attribute's type matches the return type.
105 static LogicalResult verify(emitc::ConstantOp &op) {
106   Attribute value = op.value();
107   Type type = op.getType();
108   if (!value.getType().isa<NoneType>() && type != value.getType())
109     return op.emitOpError() << "requires attribute's type (" << value.getType()
110                             << ") to match op's return type (" << type << ")";
111   return success();
112 }
113 
114 OpFoldResult emitc::ConstantOp::fold(ArrayRef<Attribute> operands) {
115   assert(operands.empty() && "constant has no operands");
116   return value();
117 }
118 
119 //===----------------------------------------------------------------------===//
120 // IncludeOp
121 //===----------------------------------------------------------------------===//
122 
123 static void print(OpAsmPrinter &p, IncludeOp &op) {
124   bool standardInclude = op.is_standard_include();
125 
126   p << " ";
127   if (standardInclude)
128     p << "<";
129   p << "\"" << op.include() << "\"";
130   if (standardInclude)
131     p << ">";
132 }
133 
134 static ParseResult parseIncludeOp(OpAsmParser &parser, OperationState &result) {
135   bool standardInclude = !parser.parseOptionalLess();
136 
137   StringAttr include;
138   OptionalParseResult includeParseResult =
139       parser.parseOptionalAttribute(include, "include", result.attributes);
140   if (!includeParseResult.hasValue())
141     return parser.emitError(parser.getNameLoc()) << "expected string attribute";
142 
143   if (standardInclude && parser.parseOptionalGreater())
144     return parser.emitError(parser.getNameLoc())
145            << "expected trailing '>' for standard include";
146 
147   if (standardInclude)
148     result.addAttribute("is_standard_include",
149                         UnitAttr::get(parser.getBuilder().getContext()));
150 
151   return success();
152 }
153 
154 //===----------------------------------------------------------------------===//
155 // TableGen'd op method definitions
156 //===----------------------------------------------------------------------===//
157 
158 #define GET_OP_CLASSES
159 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
160 
161 //===----------------------------------------------------------------------===//
162 // EmitC Attributes
163 //===----------------------------------------------------------------------===//
164 
165 #define GET_ATTRDEF_CLASSES
166 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
167 
168 Attribute emitc::OpaqueAttr::parse(MLIRContext *context,
169                                    DialectAsmParser &parser, Type type) {
170   if (parser.parseLess())
171     return Attribute();
172   std::string value;
173   llvm::SMLoc loc = parser.getCurrentLocation();
174   if (parser.parseOptionalString(&value)) {
175     parser.emitError(loc) << "expected string";
176     return Attribute();
177   }
178   if (parser.parseGreater())
179     return Attribute();
180   return get(context, value);
181 }
182 
183 Attribute EmitCDialect::parseAttribute(DialectAsmParser &parser,
184                                        Type type) const {
185   llvm::SMLoc typeLoc = parser.getCurrentLocation();
186   StringRef mnemonic;
187   if (parser.parseKeyword(&mnemonic))
188     return Attribute();
189   Attribute genAttr;
190   OptionalParseResult parseResult =
191       generatedAttributeParser(getContext(), parser, mnemonic, type, genAttr);
192   if (parseResult.hasValue())
193     return genAttr;
194   parser.emitError(typeLoc, "unknown attribute in EmitC dialect");
195   return Attribute();
196 }
197 
198 void EmitCDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const {
199   if (failed(generatedAttributePrinter(attr, os)))
200     llvm_unreachable("unexpected 'EmitC' attribute kind");
201 }
202 
203 void emitc::OpaqueAttr::print(DialectAsmPrinter &printer) const {
204   printer << "opaque<\"" << getValue() << "\">";
205 }
206 
207 //===----------------------------------------------------------------------===//
208 // EmitC Types
209 //===----------------------------------------------------------------------===//
210 
211 #define GET_TYPEDEF_CLASSES
212 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
213 
214 Type emitc::OpaqueType::parse(MLIRContext *context, DialectAsmParser &parser) {
215   if (parser.parseLess())
216     return Type();
217   std::string value;
218   llvm::SMLoc loc = parser.getCurrentLocation();
219   if (parser.parseOptionalString(&value) || value.empty()) {
220     parser.emitError(loc) << "expected non empty string";
221     return Type();
222   }
223   if (parser.parseGreater())
224     return Type();
225   return get(context, value);
226 }
227 
228 Type EmitCDialect::parseType(DialectAsmParser &parser) const {
229   llvm::SMLoc typeLoc = parser.getCurrentLocation();
230   StringRef mnemonic;
231   if (parser.parseKeyword(&mnemonic))
232     return Type();
233   Type genType;
234   OptionalParseResult parseResult =
235       generatedTypeParser(getContext(), parser, mnemonic, genType);
236   if (parseResult.hasValue())
237     return genType;
238   parser.emitError(typeLoc, "unknown type in EmitC dialect");
239   return Type();
240 }
241 
242 void EmitCDialect::printType(Type type, DialectAsmPrinter &os) const {
243   if (failed(generatedTypePrinter(type, os)))
244     llvm_unreachable("unexpected 'EmitC' type kind");
245 }
246 
247 void emitc::OpaqueType::print(DialectAsmPrinter &printer) const {
248   printer << "opaque<\"" << getValue() << "\">";
249 }
250