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