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