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/TypeSwitch.h" 13 14 using namespace mlir; 15 using namespace mlir::emitc; 16 17 #include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc" 18 19 //===----------------------------------------------------------------------===// 20 // EmitCDialect 21 //===----------------------------------------------------------------------===// 22 23 void EmitCDialect::initialize() { 24 addOperations< 25 #define GET_OP_LIST 26 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc" 27 >(); 28 addTypes< 29 #define GET_TYPEDEF_LIST 30 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc" 31 >(); 32 addAttributes< 33 #define GET_ATTRDEF_LIST 34 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc" 35 >(); 36 } 37 38 /// Materialize a single constant operation from a given attribute value with 39 /// the desired resultant type. 40 Operation *EmitCDialect::materializeConstant(OpBuilder &builder, 41 Attribute value, Type type, 42 Location loc) { 43 return builder.create<ConstantOp>(loc, type, value); 44 } 45 46 //===----------------------------------------------------------------------===// 47 // ApplyOp 48 //===----------------------------------------------------------------------===// 49 50 static LogicalResult verify(ApplyOp op) { 51 StringRef applicableOperator = op.applicableOperator(); 52 53 // Applicable operator must not be empty. 54 if (applicableOperator.empty()) 55 return op.emitOpError("applicable operator must not be empty"); 56 57 // Only `*` and `&` are supported. 58 if (applicableOperator != "&" && applicableOperator != "*") 59 return op.emitOpError("applicable operator is illegal"); 60 61 return success(); 62 } 63 64 //===----------------------------------------------------------------------===// 65 // CallOp 66 //===----------------------------------------------------------------------===// 67 68 static LogicalResult verify(emitc::CallOp op) { 69 // Callee must not be empty. 70 if (op.callee().empty()) 71 return op.emitOpError("callee must not be empty"); 72 73 if (Optional<ArrayAttr> argsAttr = op.args()) { 74 for (Attribute arg : argsAttr.getValue()) { 75 if (arg.getType().isa<IndexType>()) { 76 int64_t index = arg.cast<IntegerAttr>().getInt(); 77 // Args with elements of type index must be in range 78 // [0..operands.size). 79 if ((index < 0) || (index >= static_cast<int64_t>(op.getNumOperands()))) 80 return op.emitOpError("index argument is out of range"); 81 82 // Args with elements of type ArrayAttr must have a type. 83 } else if (arg.isa<ArrayAttr>() && arg.getType().isa<NoneType>()) { 84 return op.emitOpError("array argument has no type"); 85 } 86 } 87 } 88 89 if (Optional<ArrayAttr> templateArgsAttr = op.template_args()) { 90 for (Attribute tArg : templateArgsAttr.getValue()) { 91 if (!tArg.isa<TypeAttr>() && !tArg.isa<IntegerAttr>() && 92 !tArg.isa<FloatAttr>() && !tArg.isa<emitc::OpaqueAttr>()) 93 return op.emitOpError("template argument has invalid type"); 94 } 95 } 96 97 return success(); 98 } 99 100 //===----------------------------------------------------------------------===// 101 // ConstantOp 102 //===----------------------------------------------------------------------===// 103 104 /// The constant op requires that the attribute's type matches the return type. 105 static LogicalResult verify(emitc::ConstantOp &op) { 106 Attribute value = op.value(); 107 Type type = op.getType(); 108 if (!value.getType().isa<NoneType>() && type != value.getType()) 109 return op.emitOpError() << "requires attribute's type (" << value.getType() 110 << ") to match op's return type (" << type << ")"; 111 return success(); 112 } 113 114 OpFoldResult emitc::ConstantOp::fold(ArrayRef<Attribute> operands) { 115 assert(operands.empty() && "constant has no operands"); 116 return value(); 117 } 118 119 //===----------------------------------------------------------------------===// 120 // IncludeOp 121 //===----------------------------------------------------------------------===// 122 123 static void print(OpAsmPrinter &p, IncludeOp &op) { 124 bool standardInclude = op.is_standard_include(); 125 126 p << " "; 127 if (standardInclude) 128 p << "<"; 129 p << "\"" << op.include() << "\""; 130 if (standardInclude) 131 p << ">"; 132 } 133 134 static ParseResult parseIncludeOp(OpAsmParser &parser, OperationState &result) { 135 bool standardInclude = !parser.parseOptionalLess(); 136 137 StringAttr include; 138 OptionalParseResult includeParseResult = 139 parser.parseOptionalAttribute(include, "include", result.attributes); 140 if (!includeParseResult.hasValue()) 141 return parser.emitError(parser.getNameLoc()) << "expected string attribute"; 142 143 if (standardInclude && parser.parseOptionalGreater()) 144 return parser.emitError(parser.getNameLoc()) 145 << "expected trailing '>' for standard include"; 146 147 if (standardInclude) 148 result.addAttribute("is_standard_include", 149 UnitAttr::get(parser.getBuilder().getContext())); 150 151 return success(); 152 } 153 154 //===----------------------------------------------------------------------===// 155 // TableGen'd op method definitions 156 //===----------------------------------------------------------------------===// 157 158 #define GET_OP_CLASSES 159 #include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc" 160 161 //===----------------------------------------------------------------------===// 162 // EmitC Attributes 163 //===----------------------------------------------------------------------===// 164 165 #define GET_ATTRDEF_CLASSES 166 #include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc" 167 168 Attribute emitc::OpaqueAttr::parse(MLIRContext *context, 169 DialectAsmParser &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(context, value); 181 } 182 183 Attribute EmitCDialect::parseAttribute(DialectAsmParser &parser, 184 Type type) const { 185 llvm::SMLoc typeLoc = parser.getCurrentLocation(); 186 StringRef mnemonic; 187 if (parser.parseKeyword(&mnemonic)) 188 return Attribute(); 189 Attribute genAttr; 190 OptionalParseResult parseResult = 191 generatedAttributeParser(getContext(), parser, mnemonic, type, genAttr); 192 if (parseResult.hasValue()) 193 return genAttr; 194 parser.emitError(typeLoc, "unknown attribute in EmitC dialect"); 195 return Attribute(); 196 } 197 198 void EmitCDialect::printAttribute(Attribute attr, DialectAsmPrinter &os) const { 199 if (failed(generatedAttributePrinter(attr, os))) 200 llvm_unreachable("unexpected 'EmitC' attribute kind"); 201 } 202 203 void emitc::OpaqueAttr::print(DialectAsmPrinter &printer) const { 204 printer << "opaque<\"" << getValue() << "\">"; 205 } 206 207 //===----------------------------------------------------------------------===// 208 // EmitC Types 209 //===----------------------------------------------------------------------===// 210 211 #define GET_TYPEDEF_CLASSES 212 #include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc" 213 214 Type emitc::OpaqueType::parse(MLIRContext *context, DialectAsmParser &parser) { 215 if (parser.parseLess()) 216 return Type(); 217 std::string value; 218 llvm::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(context, value); 226 } 227 228 Type EmitCDialect::parseType(DialectAsmParser &parser) const { 229 llvm::SMLoc typeLoc = parser.getCurrentLocation(); 230 StringRef mnemonic; 231 if (parser.parseKeyword(&mnemonic)) 232 return Type(); 233 Type genType; 234 OptionalParseResult parseResult = 235 generatedTypeParser(getContext(), parser, mnemonic, genType); 236 if (parseResult.hasValue()) 237 return genType; 238 parser.emitError(typeLoc, "unknown type in EmitC dialect"); 239 return Type(); 240 } 241 242 void EmitCDialect::printType(Type type, DialectAsmPrinter &os) const { 243 if (failed(generatedTypePrinter(type, os))) 244 llvm_unreachable("unexpected 'EmitC' type kind"); 245 } 246 247 void emitc::OpaqueType::print(DialectAsmPrinter &printer) const { 248 printer << "opaque<\"" << getValue() << "\">"; 249 } 250