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 // CastOp 67 //===----------------------------------------------------------------------===// 68 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 82 LogicalResult emitc::CallOp::verify() { 83 // Callee must not be empty. 84 if (callee().empty()) 85 return emitOpError("callee must not be empty"); 86 87 if (Optional<ArrayAttr> argsAttr = args()) { 88 for (Attribute arg : argsAttr.getValue()) { 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 = template_args()) { 104 for (Attribute tArg : templateArgsAttr.getValue()) { 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. 119 LogicalResult emitc::ConstantOp::verify() { 120 Attribute value = valueAttr(); 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 128 OpFoldResult emitc::ConstantOp::fold(ArrayRef<Attribute> operands) { 129 assert(operands.empty() && "constant has no operands"); 130 return value(); 131 } 132 133 //===----------------------------------------------------------------------===// 134 // IncludeOp 135 //===----------------------------------------------------------------------===// 136 137 void IncludeOp::print(OpAsmPrinter &p) { 138 bool standardInclude = is_standard_include(); 139 140 p << " "; 141 if (standardInclude) 142 p << "<"; 143 p << "\"" << include() << "\""; 144 if (standardInclude) 145 p << ">"; 146 } 147 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. 173 LogicalResult emitc::VariableOp::verify() { 174 Attribute value = valueAttr(); 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 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 210 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 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 246 void emitc::OpaqueType::print(AsmPrinter &printer) const { 247 printer << "<\""; 248 llvm::printEscapedString(getValue(), printer.getStream()); 249 printer << "\">"; 250 } 251