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<emitc::ConstantOp>(loc, type, value);
45 }
46 
47 //===----------------------------------------------------------------------===//
48 // ApplyOp
49 //===----------------------------------------------------------------------===//
50 
51 LogicalResult ApplyOp::verify() {
52   StringRef applicableOperatorStr = applicableOperator();
53 
54   // Applicable operator must not be empty.
55   if (applicableOperatorStr.empty())
56     return emitOpError("applicable operator must not be empty");
57 
58   // Only `*` and `&` are supported.
59   if (applicableOperatorStr != "&" && applicableOperatorStr != "*")
60     return emitOpError("applicable operator is illegal");
61 
62   return success();
63 }
64 
65 //===----------------------------------------------------------------------===//
66 // CallOp
67 //===----------------------------------------------------------------------===//
68 
69 LogicalResult emitc::CallOp::verify() {
70   // Callee must not be empty.
71   if (callee().empty())
72     return emitOpError("callee must not be empty");
73 
74   if (Optional<ArrayAttr> argsAttr = 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>(getNumOperands())))
81           return 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 emitOpError("array argument has no type");
86       }
87     }
88   }
89 
90   if (Optional<ArrayAttr> templateArgsAttr = 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 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 LogicalResult emitc::ConstantOp::verify() {
107   Attribute value = valueAttr();
108   Type type = getType();
109   if (!value.getType().isa<NoneType>() && type != value.getType())
110     return 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 void IncludeOp::print(OpAsmPrinter &p) {
125   bool standardInclude = is_standard_include();
126 
127   p << " ";
128   if (standardInclude)
129     p << "<";
130   p << "\"" << include() << "\"";
131   if (standardInclude)
132     p << ">";
133 }
134 
135 ParseResult IncludeOp::parse(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.getContext()));
151 
152   return success();
153 }
154 
155 //===----------------------------------------------------------------------===//
156 // VariableOp
157 //===----------------------------------------------------------------------===//
158 
159 /// The variable op requires that the attribute's type matches the return type.
160 LogicalResult emitc::VariableOp::verify() {
161   Attribute value = valueAttr();
162   Type type = getType();
163   if (!value.getType().isa<NoneType>() && type != value.getType())
164     return emitOpError() << "requires attribute's type (" << value.getType()
165                          << ") to match op's return type (" << type << ")";
166   return success();
167 }
168 
169 //===----------------------------------------------------------------------===//
170 // TableGen'd op method definitions
171 //===----------------------------------------------------------------------===//
172 
173 #define GET_OP_CLASSES
174 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
175 
176 //===----------------------------------------------------------------------===//
177 // EmitC Attributes
178 //===----------------------------------------------------------------------===//
179 
180 #define GET_ATTRDEF_CLASSES
181 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
182 
183 Attribute emitc::OpaqueAttr::parse(AsmParser &parser, Type type) {
184   if (parser.parseLess())
185     return Attribute();
186   std::string value;
187   SMLoc loc = parser.getCurrentLocation();
188   if (parser.parseOptionalString(&value)) {
189     parser.emitError(loc) << "expected string";
190     return Attribute();
191   }
192   if (parser.parseGreater())
193     return Attribute();
194   return get(parser.getContext(), value);
195 }
196 
197 void emitc::OpaqueAttr::print(AsmPrinter &printer) const {
198   printer << "<\"";
199   llvm::printEscapedString(getValue(), printer.getStream());
200   printer << "\">";
201 }
202 
203 //===----------------------------------------------------------------------===//
204 // EmitC Types
205 //===----------------------------------------------------------------------===//
206 
207 #define GET_TYPEDEF_CLASSES
208 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
209 
210 //===----------------------------------------------------------------------===//
211 // OpaqueType
212 //===----------------------------------------------------------------------===//
213 
214 Type emitc::OpaqueType::parse(AsmParser &parser) {
215   if (parser.parseLess())
216     return Type();
217   std::string value;
218   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(parser.getContext(), value);
226 }
227 
228 void emitc::OpaqueType::print(AsmPrinter &printer) const {
229   printer << "<\"";
230   llvm::printEscapedString(getValue(), printer.getStream());
231   printer << "\">";
232 }
233