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 
initialize()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.
materializeConstant(OpBuilder & builder,Attribute value,Type type,Location loc)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 
verify()51 LogicalResult ApplyOp::verify() {
52   StringRef applicableOperatorStr = getApplicableOperator();
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 // CastOp
67 //===----------------------------------------------------------------------===//
68 
areCastCompatible(TypeRange inputs,TypeRange outputs)69 bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {
70   Type input = inputs.front(), output = outputs.front();
71 
72   return ((input.isa<IntegerType, FloatType, IndexType, emitc::OpaqueType,
73                      emitc::PointerType>()) &&
74           (output.isa<IntegerType, FloatType, IndexType, emitc::OpaqueType,
75                       emitc::PointerType>()));
76 }
77 
78 //===----------------------------------------------------------------------===//
79 // CallOp
80 //===----------------------------------------------------------------------===//
81 
verify()82 LogicalResult emitc::CallOp::verify() {
83   // Callee must not be empty.
84   if (getCallee().empty())
85     return emitOpError("callee must not be empty");
86 
87   if (Optional<ArrayAttr> argsAttr = getArgs()) {
88     for (Attribute arg : *argsAttr) {
89       if (arg.getType().isa<IndexType>()) {
90         int64_t index = arg.cast<IntegerAttr>().getInt();
91         // Args with elements of type index must be in range
92         // [0..operands.size).
93         if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands())))
94           return emitOpError("index argument is out of range");
95 
96         // Args with elements of type ArrayAttr must have a type.
97       } else if (arg.isa<ArrayAttr>() && arg.getType().isa<NoneType>()) {
98         return emitOpError("array argument has no type");
99       }
100     }
101   }
102 
103   if (Optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {
104     for (Attribute tArg : *templateArgsAttr) {
105       if (!tArg.isa<TypeAttr>() && !tArg.isa<IntegerAttr>() &&
106           !tArg.isa<FloatAttr>() && !tArg.isa<emitc::OpaqueAttr>())
107         return emitOpError("template argument has invalid type");
108     }
109   }
110 
111   return success();
112 }
113 
114 //===----------------------------------------------------------------------===//
115 // ConstantOp
116 //===----------------------------------------------------------------------===//
117 
118 /// The constant op requires that the attribute's type matches the return type.
verify()119 LogicalResult emitc::ConstantOp::verify() {
120   Attribute value = getValueAttr();
121   Type type = getType();
122   if (!value.getType().isa<NoneType>() && type != value.getType())
123     return emitOpError() << "requires attribute's type (" << value.getType()
124                          << ") to match op's return type (" << type << ")";
125   return success();
126 }
127 
fold(ArrayRef<Attribute> operands)128 OpFoldResult emitc::ConstantOp::fold(ArrayRef<Attribute> operands) {
129   assert(operands.empty() && "constant has no operands");
130   return getValue();
131 }
132 
133 //===----------------------------------------------------------------------===//
134 // IncludeOp
135 //===----------------------------------------------------------------------===//
136 
print(OpAsmPrinter & p)137 void IncludeOp::print(OpAsmPrinter &p) {
138   bool standardInclude = getIsStandardInclude();
139 
140   p << " ";
141   if (standardInclude)
142     p << "<";
143   p << "\"" << getInclude() << "\"";
144   if (standardInclude)
145     p << ">";
146 }
147 
parse(OpAsmParser & parser,OperationState & result)148 ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {
149   bool standardInclude = !parser.parseOptionalLess();
150 
151   StringAttr include;
152   OptionalParseResult includeParseResult =
153       parser.parseOptionalAttribute(include, "include", result.attributes);
154   if (!includeParseResult.hasValue())
155     return parser.emitError(parser.getNameLoc()) << "expected string attribute";
156 
157   if (standardInclude && parser.parseOptionalGreater())
158     return parser.emitError(parser.getNameLoc())
159            << "expected trailing '>' for standard include";
160 
161   if (standardInclude)
162     result.addAttribute("is_standard_include",
163                         UnitAttr::get(parser.getContext()));
164 
165   return success();
166 }
167 
168 //===----------------------------------------------------------------------===//
169 // VariableOp
170 //===----------------------------------------------------------------------===//
171 
172 /// The variable op requires that the attribute's type matches the return type.
verify()173 LogicalResult emitc::VariableOp::verify() {
174   Attribute value = getValueAttr();
175   Type type = getType();
176   if (!value.getType().isa<NoneType>() && type != value.getType())
177     return emitOpError() << "requires attribute's type (" << value.getType()
178                          << ") to match op's return type (" << type << ")";
179   return success();
180 }
181 
182 //===----------------------------------------------------------------------===//
183 // TableGen'd op method definitions
184 //===----------------------------------------------------------------------===//
185 
186 #define GET_OP_CLASSES
187 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"
188 
189 //===----------------------------------------------------------------------===//
190 // EmitC Attributes
191 //===----------------------------------------------------------------------===//
192 
193 #define GET_ATTRDEF_CLASSES
194 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"
195 
parse(AsmParser & parser,Type type)196 Attribute emitc::OpaqueAttr::parse(AsmParser &parser, Type type) {
197   if (parser.parseLess())
198     return Attribute();
199   std::string value;
200   SMLoc loc = parser.getCurrentLocation();
201   if (parser.parseOptionalString(&value)) {
202     parser.emitError(loc) << "expected string";
203     return Attribute();
204   }
205   if (parser.parseGreater())
206     return Attribute();
207   return get(parser.getContext(), value);
208 }
209 
print(AsmPrinter & printer) const210 void emitc::OpaqueAttr::print(AsmPrinter &printer) const {
211   printer << "<\"";
212   llvm::printEscapedString(getValue(), printer.getStream());
213   printer << "\">";
214 }
215 
216 //===----------------------------------------------------------------------===//
217 // EmitC Types
218 //===----------------------------------------------------------------------===//
219 
220 #define GET_TYPEDEF_CLASSES
221 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
222 
223 //===----------------------------------------------------------------------===//
224 // OpaqueType
225 //===----------------------------------------------------------------------===//
226 
parse(AsmParser & parser)227 Type emitc::OpaqueType::parse(AsmParser &parser) {
228   if (parser.parseLess())
229     return Type();
230   std::string value;
231   SMLoc loc = parser.getCurrentLocation();
232   if (parser.parseOptionalString(&value) || value.empty()) {
233     parser.emitError(loc) << "expected non empty string in !emitc.opaque type";
234     return Type();
235   }
236   if (value.back() == '*') {
237     parser.emitError(loc) << "pointer not allowed as outer type with "
238                              "!emitc.opaque, use !emitc.ptr instead";
239     return Type();
240   }
241   if (parser.parseGreater())
242     return Type();
243   return get(parser.getContext(), value);
244 }
245 
print(AsmPrinter & printer) const246 void emitc::OpaqueType::print(AsmPrinter &printer) const {
247   printer << "<\"";
248   llvm::printEscapedString(getValue(), printer.getStream());
249   printer << "\">";
250 }
251