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