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 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.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(AsmParser &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(parser.getContext(), value);
181 }
182 
183 void emitc::OpaqueAttr::print(AsmPrinter &printer) const {
184   printer << "<\"";
185   llvm::printEscapedString(getValue(), printer.getStream());
186   printer << "\">";
187 }
188 
189 //===----------------------------------------------------------------------===//
190 // EmitC Types
191 //===----------------------------------------------------------------------===//
192 
193 #define GET_TYPEDEF_CLASSES
194 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"
195 
196 Type emitc::OpaqueType::parse(AsmParser &parser) {
197   if (parser.parseLess())
198     return Type();
199   std::string value;
200   llvm::SMLoc loc = parser.getCurrentLocation();
201   if (parser.parseOptionalString(&value) || value.empty()) {
202     parser.emitError(loc) << "expected non empty string";
203     return Type();
204   }
205   if (parser.parseGreater())
206     return Type();
207   return get(parser.getContext(), value);
208 }
209 
210 void emitc::OpaqueType::print(AsmPrinter &printer) const {
211   printer << "<\"";
212   llvm::printEscapedString(getValue(), printer.getStream());
213   printer << "\">";
214 }
215