brintos

brintos / llvm-project-archived public Read only

0
0
Text · 57.6 KiB · d478220 Raw
1648 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8 9#include "mlir/Dialect/EmitC/IR/EmitC.h"10#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.h"11#include "mlir/IR/Builders.h"12#include "mlir/IR/BuiltinAttributes.h"13#include "mlir/IR/BuiltinTypes.h"14#include "mlir/IR/DialectImplementation.h"15#include "mlir/IR/Types.h"16#include "mlir/Interfaces/FunctionImplementation.h"17#include "mlir/Support/LLVM.h"18#include "llvm/ADT/STLExtras.h"19#include "llvm/ADT/SmallVector.h"20#include "llvm/ADT/TypeSwitch.h"21#include "llvm/Support/Casting.h"22 23using namespace mlir;24using namespace mlir::emitc;25 26#include "mlir/Dialect/EmitC/IR/EmitCDialect.cpp.inc"27 28//===----------------------------------------------------------------------===//29// EmitCDialect30//===----------------------------------------------------------------------===//31 32void EmitCDialect::initialize() {33  addOperations<34#define GET_OP_LIST35#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"36      >();37  addTypes<38#define GET_TYPEDEF_LIST39#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"40      >();41  addAttributes<42#define GET_ATTRDEF_LIST43#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"44      >();45}46 47/// Materialize a single constant operation from a given attribute value with48/// the desired resultant type.49Operation *EmitCDialect::materializeConstant(OpBuilder &builder,50                                             Attribute value, Type type,51                                             Location loc) {52  return emitc::ConstantOp::create(builder, loc, type, value);53}54 55/// Default callback for builders of ops carrying a region. Inserts a yield56/// without arguments.57void mlir::emitc::buildTerminatedBody(OpBuilder &builder, Location loc) {58  emitc::YieldOp::create(builder, loc);59}60 61bool mlir::emitc::isSupportedEmitCType(Type type) {62  if (llvm::isa<emitc::OpaqueType>(type))63    return true;64  if (auto ptrType = llvm::dyn_cast<emitc::PointerType>(type))65    return isSupportedEmitCType(ptrType.getPointee());66  if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(type)) {67    auto elemType = arrayType.getElementType();68    return !llvm::isa<emitc::ArrayType>(elemType) &&69           isSupportedEmitCType(elemType);70  }71  if (type.isIndex() || emitc::isPointerWideType(type))72    return true;73  if (llvm::isa<IntegerType>(type))74    return isSupportedIntegerType(type);75  if (llvm::isa<FloatType>(type))76    return isSupportedFloatType(type);77  if (auto tensorType = llvm::dyn_cast<TensorType>(type)) {78    if (!tensorType.hasStaticShape()) {79      return false;80    }81    auto elemType = tensorType.getElementType();82    if (llvm::isa<emitc::ArrayType>(elemType)) {83      return false;84    }85    return isSupportedEmitCType(elemType);86  }87  if (auto tupleType = llvm::dyn_cast<TupleType>(type)) {88    return llvm::all_of(tupleType.getTypes(), [](Type type) {89      return !llvm::isa<emitc::ArrayType>(type) && isSupportedEmitCType(type);90    });91  }92  return false;93}94 95bool mlir::emitc::isSupportedIntegerType(Type type) {96  if (auto intType = llvm::dyn_cast<IntegerType>(type)) {97    switch (intType.getWidth()) {98    case 1:99    case 8:100    case 16:101    case 32:102    case 64:103      return true;104    default:105      return false;106    }107  }108  return false;109}110 111bool mlir::emitc::isIntegerIndexOrOpaqueType(Type type) {112  return llvm::isa<IndexType, emitc::OpaqueType>(type) ||113         isSupportedIntegerType(type) || isPointerWideType(type);114}115 116bool mlir::emitc::isSupportedFloatType(Type type) {117  if (auto floatType = llvm::dyn_cast<FloatType>(type)) {118    switch (floatType.getWidth()) {119    case 16:120      return llvm::isa<Float16Type, BFloat16Type>(type);121    case 32:122    case 64:123      return true;124    default:125      return false;126    }127  }128  return false;129}130 131bool mlir::emitc::isPointerWideType(Type type) {132  return isa<emitc::SignedSizeTType, emitc::SizeTType, emitc::PtrDiffTType>(133      type);134}135 136bool mlir::emitc::isFundamentalType(Type type) {137  return llvm::isa<IndexType>(type) || isPointerWideType(type) ||138         isSupportedIntegerType(type) || isSupportedFloatType(type) ||139         isa<emitc::PointerType>(type);140}141 142/// Check that the type of the initial value is compatible with the operations143/// result type.144static LogicalResult verifyInitializationAttribute(Operation *op,145                                                   Attribute value) {146  assert(op->getNumResults() == 1 && "operation must have 1 result");147 148  if (llvm::isa<emitc::OpaqueAttr>(value))149    return success();150 151  if (llvm::isa<StringAttr>(value))152    return op->emitOpError()153           << "string attributes are not supported, use #emitc.opaque instead";154 155  Type resultType = op->getResult(0).getType();156  if (auto lType = dyn_cast<LValueType>(resultType))157    resultType = lType.getValueType();158  Type attrType = cast<TypedAttr>(value).getType();159 160  if (isPointerWideType(resultType) && attrType.isIndex())161    return success();162 163  if (resultType != attrType)164    return op->emitOpError()165           << "requires attribute to either be an #emitc.opaque attribute or "166              "it's type ("167           << attrType << ") to match the op's result type (" << resultType168           << ")";169 170  return success();171}172 173/// Parse a format string and return a list of its parts.174/// A part is either a StringRef that has to be printed as-is, or175/// a Placeholder which requires printing the next operand of the VerbatimOp.176/// In the format string, all `{}` are replaced by Placeholders, except if the177/// `{` is escaped by `{{` - then it doesn't start a placeholder.178template <class ArgType>179FailureOr<SmallVector<ReplacementItem>> parseFormatString(180    StringRef toParse, ArgType fmtArgs,181    llvm::function_ref<mlir::InFlightDiagnostic()> emitError = {}) {182  SmallVector<ReplacementItem> items;183 184  // If there are not operands, the format string is not interpreted.185  if (fmtArgs.empty()) {186    items.push_back(toParse);187    return items;188  }189 190  while (!toParse.empty()) {191    size_t idx = toParse.find('{');192    if (idx == StringRef::npos) {193      // No '{'194      items.push_back(toParse);195      break;196    }197    if (idx > 0) {198      // Take all chars excluding the '{'.199      items.push_back(toParse.take_front(idx));200      toParse = toParse.drop_front(idx);201      continue;202    }203    if (toParse.size() < 2) {204      return emitError() << "expected '}' after unescaped '{' at end of string";205    }206    // toParse contains at least two characters and starts with `{`.207    char nextChar = toParse[1];208    if (nextChar == '{') {209      // Double '{{' -> '{' (escaping).210      items.push_back(toParse.take_front(1));211      toParse = toParse.drop_front(2);212      continue;213    }214    if (nextChar == '}') {215      items.push_back(Placeholder{});216      toParse = toParse.drop_front(2);217      continue;218    }219 220    if (emitError) {221      return emitError() << "expected '}' after unescaped '{'";222    }223    return failure();224  }225  return items;226}227 228//===----------------------------------------------------------------------===//229// AddOp230//===----------------------------------------------------------------------===//231 232LogicalResult AddOp::verify() {233  Type lhsType = getLhs().getType();234  Type rhsType = getRhs().getType();235 236  if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType))237    return emitOpError("requires that at most one operand is a pointer");238 239  if ((isa<emitc::PointerType>(lhsType) &&240       !isa<IntegerType, emitc::OpaqueType>(rhsType)) ||241      (isa<emitc::PointerType>(rhsType) &&242       !isa<IntegerType, emitc::OpaqueType>(lhsType)))243    return emitOpError("requires that one operand is an integer or of opaque "244                       "type if the other is a pointer");245 246  return success();247}248 249//===----------------------------------------------------------------------===//250// ApplyOp251//===----------------------------------------------------------------------===//252 253LogicalResult ApplyOp::verify() {254  StringRef applicableOperatorStr = getApplicableOperator();255 256  // Applicable operator must not be empty.257  if (applicableOperatorStr.empty())258    return emitOpError("applicable operator must not be empty");259 260  // Only `*` and `&` are supported.261  if (applicableOperatorStr != "&" && applicableOperatorStr != "*")262    return emitOpError("applicable operator is illegal");263 264  Type operandType = getOperand().getType();265  Type resultType = getResult().getType();266  if (applicableOperatorStr == "&") {267    if (!llvm::isa<emitc::LValueType>(operandType))268      return emitOpError("operand type must be an lvalue when applying `&`");269    if (!llvm::isa<emitc::PointerType>(resultType))270      return emitOpError("result type must be a pointer when applying `&`");271  } else {272    if (!llvm::isa<emitc::PointerType>(operandType))273      return emitOpError("operand type must be a pointer when applying `*`");274  }275 276  return success();277}278 279//===----------------------------------------------------------------------===//280// AssignOp281//===----------------------------------------------------------------------===//282 283/// The assign op requires that the assigned value's type matches the284/// assigned-to variable type.285LogicalResult emitc::AssignOp::verify() {286  TypedValue<emitc::LValueType> variable = getVar();287 288  if (!variable.getDefiningOp())289    return emitOpError() << "cannot assign to block argument";290 291  Type valueType = getValue().getType();292  Type variableType = variable.getType().getValueType();293  if (variableType != valueType)294    return emitOpError() << "requires value's type (" << valueType295                         << ") to match variable's type (" << variableType296                         << ")\n  variable: " << variable297                         << "\n  value: " << getValue() << "\n";298  return success();299}300 301//===----------------------------------------------------------------------===//302// CastOp303//===----------------------------------------------------------------------===//304 305bool CastOp::areCastCompatible(TypeRange inputs, TypeRange outputs) {306  Type input = inputs.front(), output = outputs.front();307 308  if (auto arrayType = dyn_cast<emitc::ArrayType>(input)) {309    if (auto pointerType = dyn_cast<emitc::PointerType>(output)) {310      return (arrayType.getElementType() == pointerType.getPointee()) &&311             arrayType.getShape().size() == 1 && arrayType.getShape()[0] >= 1;312    }313    return false;314  }315 316  return (317      (emitc::isIntegerIndexOrOpaqueType(input) ||318       emitc::isSupportedFloatType(input) || isa<emitc::PointerType>(input)) &&319      (emitc::isIntegerIndexOrOpaqueType(output) ||320       emitc::isSupportedFloatType(output) || isa<emitc::PointerType>(output)));321}322 323//===----------------------------------------------------------------------===//324// CallOpaqueOp325//===----------------------------------------------------------------------===//326 327LogicalResult emitc::CallOpaqueOp::verify() {328  // Callee must not be empty.329  if (getCallee().empty())330    return emitOpError("callee must not be empty");331 332  if (std::optional<ArrayAttr> argsAttr = getArgs()) {333    for (Attribute arg : *argsAttr) {334      auto intAttr = llvm::dyn_cast<IntegerAttr>(arg);335      if (intAttr && llvm::isa<IndexType>(intAttr.getType())) {336        int64_t index = intAttr.getInt();337        // Args with elements of type index must be in range338        // [0..operands.size).339        if ((index < 0) || (index >= static_cast<int64_t>(getNumOperands())))340          return emitOpError("index argument is out of range");341 342        // Args with elements of type ArrayAttr must have a type.343      } else if (llvm::isa<ArrayAttr>(344                     arg) /*&& llvm::isa<NoneType>(arg.getType())*/) {345        // FIXME: Array attributes never have types346        return emitOpError("array argument has no type");347      }348    }349  }350 351  if (std::optional<ArrayAttr> templateArgsAttr = getTemplateArgs()) {352    for (Attribute tArg : *templateArgsAttr) {353      if (!llvm::isa<TypeAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(tArg))354        return emitOpError("template argument has invalid type");355    }356  }357 358  if (llvm::any_of(getResultTypes(), llvm::IsaPred<ArrayType>)) {359    return emitOpError() << "cannot return array type";360  }361 362  return success();363}364 365//===----------------------------------------------------------------------===//366// ConstantOp367//===----------------------------------------------------------------------===//368 369LogicalResult emitc::ConstantOp::verify() {370  Attribute value = getValueAttr();371  if (failed(verifyInitializationAttribute(getOperation(), value)))372    return failure();373  if (auto opaqueValue = llvm::dyn_cast<emitc::OpaqueAttr>(value)) {374    if (opaqueValue.getValue().empty())375      return emitOpError() << "value must not be empty";376  }377  return success();378}379 380OpFoldResult emitc::ConstantOp::fold(FoldAdaptor adaptor) { return getValue(); }381 382//===----------------------------------------------------------------------===//383// ExpressionOp384//===----------------------------------------------------------------------===//385 386ParseResult ExpressionOp::parse(OpAsmParser &parser, OperationState &result) {387  SmallVector<OpAsmParser::UnresolvedOperand> operands;388  if (parser.parseOperandList(operands))389    return parser.emitError(parser.getCurrentLocation()) << "expected operands";390  if (succeeded(parser.parseOptionalKeyword("noinline")))391    result.addAttribute(ExpressionOp::getDoNotInlineAttrName(result.name),392                        parser.getBuilder().getUnitAttr());393  Type type;394  if (parser.parseColonType(type))395    return parser.emitError(parser.getCurrentLocation(),396                            "expected function type");397  auto fnType = llvm::dyn_cast<FunctionType>(type);398  if (!fnType)399    return parser.emitError(parser.getCurrentLocation(),400                            "expected function type");401  if (parser.resolveOperands(operands, fnType.getInputs(),402                             parser.getCurrentLocation(), result.operands))403    return failure();404  if (fnType.getNumResults() != 1)405    return parser.emitError(parser.getCurrentLocation(),406                            "expected single return type");407  result.addTypes(fnType.getResults());408  Region *body = result.addRegion();409  SmallVector<OpAsmParser::Argument> argsInfo;410  for (auto [unresolvedOperand, operandType] :411       llvm::zip(operands, fnType.getInputs())) {412    OpAsmParser::Argument argInfo;413    argInfo.ssaName = unresolvedOperand;414    argInfo.type = operandType;415    argsInfo.push_back(argInfo);416  }417  if (parser.parseRegion(*body, argsInfo, /*enableNameShadowing=*/true))418    return failure();419  return success();420}421 422void emitc::ExpressionOp::print(OpAsmPrinter &p) {423  p << ' ';424  p.printOperands(getDefs());425  p << " : ";426  p.printFunctionalType(getOperation());427  p.shadowRegionArgs(getRegion(), getDefs());428  p << ' ';429  p.printRegion(getRegion(), /*printEntryBlockArgs=*/false);430}431 432Operation *ExpressionOp::getRootOp() {433  auto yieldOp = cast<YieldOp>(getBody()->getTerminator());434  Value yieldedValue = yieldOp.getResult();435  return yieldedValue.getDefiningOp();436}437 438LogicalResult ExpressionOp::verify() {439  Type resultType = getResult().getType();440  Region &region = getRegion();441 442  Block &body = region.front();443 444  if (!body.mightHaveTerminator())445    return emitOpError("must yield a value at termination");446 447  auto yield = cast<YieldOp>(body.getTerminator());448  Value yieldResult = yield.getResult();449 450  if (!yieldResult)451    return emitOpError("must yield a value at termination");452 453  Operation *rootOp = yieldResult.getDefiningOp();454 455  if (!rootOp)456    return emitOpError("yielded value has no defining op");457 458  if (rootOp->getParentOp() != getOperation())459    return emitOpError("yielded value not defined within expression");460 461  Type yieldType = yieldResult.getType();462 463  if (resultType != yieldType)464    return emitOpError("requires yielded type to match return type");465 466  for (Operation &op : region.front().without_terminator()) {467    auto expressionInterface = dyn_cast<emitc::CExpressionInterface>(op);468    if (!expressionInterface)469      return emitOpError("contains an unsupported operation");470    if (op.getNumResults() != 1)471      return emitOpError("requires exactly one result for each operation");472    Value result = op.getResult(0);473    if (result.use_empty())474      return emitOpError("contains an unused operation");475  }476 477  // Make sure any operation with side effect is only reachable once from478  // the root op, otherwise emission will be replicating side effects.479  SmallPtrSet<Operation *, 16> visited;480  SmallVector<Operation *> worklist;481  worklist.push_back(rootOp);482  while (!worklist.empty()) {483    Operation *op = worklist.back();484    worklist.pop_back();485    if (visited.contains(op)) {486      if (cast<CExpressionInterface>(op).hasSideEffects())487        return emitOpError(488            "requires exactly one use for operations with side effects");489    }490    visited.insert(op);491    for (Value operand : op->getOperands())492      if (Operation *def = operand.getDefiningOp()) {493        worklist.push_back(def);494      }495  }496 497  return success();498}499 500//===----------------------------------------------------------------------===//501// ForOp502//===----------------------------------------------------------------------===//503 504void ForOp::build(OpBuilder &builder, OperationState &result, Value lb,505                  Value ub, Value step, BodyBuilderFn bodyBuilder) {506  OpBuilder::InsertionGuard g(builder);507  result.addOperands({lb, ub, step});508  Type t = lb.getType();509  Region *bodyRegion = result.addRegion();510  Block *bodyBlock = builder.createBlock(bodyRegion);511  bodyBlock->addArgument(t, result.location);512 513  // Create the default terminator if the builder is not provided.514  if (!bodyBuilder) {515    ForOp::ensureTerminator(*bodyRegion, builder, result.location);516  } else {517    OpBuilder::InsertionGuard guard(builder);518    builder.setInsertionPointToStart(bodyBlock);519    bodyBuilder(builder, result.location, bodyBlock->getArgument(0));520  }521}522 523void ForOp::getCanonicalizationPatterns(RewritePatternSet &, MLIRContext *) {}524 525ParseResult ForOp::parse(OpAsmParser &parser, OperationState &result) {526  Builder &builder = parser.getBuilder();527  Type type;528 529  OpAsmParser::Argument inductionVariable;530  OpAsmParser::UnresolvedOperand lb, ub, step;531 532  // Parse the induction variable followed by '='.533  if (parser.parseOperand(inductionVariable.ssaName) || parser.parseEqual() ||534      // Parse loop bounds.535      parser.parseOperand(lb) || parser.parseKeyword("to") ||536      parser.parseOperand(ub) || parser.parseKeyword("step") ||537      parser.parseOperand(step))538    return failure();539 540  // Parse the optional initial iteration arguments.541  SmallVector<OpAsmParser::Argument, 4> regionArgs;542  regionArgs.push_back(inductionVariable);543 544  // Parse optional type, else assume Index.545  if (parser.parseOptionalColon())546    type = builder.getIndexType();547  else if (parser.parseType(type))548    return failure();549 550  // Resolve input operands.551  regionArgs.front().type = type;552  if (parser.resolveOperand(lb, type, result.operands) ||553      parser.resolveOperand(ub, type, result.operands) ||554      parser.resolveOperand(step, type, result.operands))555    return failure();556 557  // Parse the body region.558  Region *body = result.addRegion();559  if (parser.parseRegion(*body, regionArgs))560    return failure();561 562  ForOp::ensureTerminator(*body, builder, result.location);563 564  // Parse the optional attribute list.565  if (parser.parseOptionalAttrDict(result.attributes))566    return failure();567 568  return success();569}570 571void ForOp::print(OpAsmPrinter &p) {572  p << " " << getInductionVar() << " = " << getLowerBound() << " to "573    << getUpperBound() << " step " << getStep();574 575  p << ' ';576  if (Type t = getInductionVar().getType(); !t.isIndex())577    p << " : " << t << ' ';578  p.printRegion(getRegion(),579                /*printEntryBlockArgs=*/false,580                /*printBlockTerminators=*/false);581  p.printOptionalAttrDict((*this)->getAttrs());582}583 584LogicalResult ForOp::verifyRegions() {585  // Check that the body defines as single block argument for the induction586  // variable.587  if (getBody()->getNumArguments() != 1)588    return emitOpError("expected body to have a single block argument for the "589                       "induction variable");590 591  if (getInductionVar().getType() != getLowerBound().getType())592    return emitOpError(593        "expected induction variable to be same type as bounds and step");594 595  return success();596}597 598//===----------------------------------------------------------------------===//599// CallOp600//===----------------------------------------------------------------------===//601 602LogicalResult CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {603  // Check that the callee attribute was specified.604  auto fnAttr = (*this)->getAttrOfType<FlatSymbolRefAttr>("callee");605  if (!fnAttr)606    return emitOpError("requires a 'callee' symbol reference attribute");607  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);608  if (!fn)609    return emitOpError() << "'" << fnAttr.getValue()610                         << "' does not reference a valid function";611 612  // Verify that the operand and result types match the callee.613  auto fnType = fn.getFunctionType();614  if (fnType.getNumInputs() != getNumOperands())615    return emitOpError("incorrect number of operands for callee");616 617  for (unsigned i = 0, e = fnType.getNumInputs(); i != e; ++i)618    if (getOperand(i).getType() != fnType.getInput(i))619      return emitOpError("operand type mismatch: expected operand type ")620             << fnType.getInput(i) << ", but provided "621             << getOperand(i).getType() << " for operand number " << i;622 623  if (fnType.getNumResults() != getNumResults())624    return emitOpError("incorrect number of results for callee");625 626  for (unsigned i = 0, e = fnType.getNumResults(); i != e; ++i)627    if (getResult(i).getType() != fnType.getResult(i)) {628      auto diag = emitOpError("result type mismatch at index ") << i;629      diag.attachNote() << "      op result types: " << getResultTypes();630      diag.attachNote() << "function result types: " << fnType.getResults();631      return diag;632    }633 634  return success();635}636 637FunctionType CallOp::getCalleeType() {638  return FunctionType::get(getContext(), getOperandTypes(), getResultTypes());639}640 641//===----------------------------------------------------------------------===//642// DeclareFuncOp643//===----------------------------------------------------------------------===//644 645LogicalResult646DeclareFuncOp::verifySymbolUses(SymbolTableCollection &symbolTable) {647  // Check that the sym_name attribute was specified.648  auto fnAttr = getSymNameAttr();649  if (!fnAttr)650    return emitOpError("requires a 'sym_name' symbol reference attribute");651  FuncOp fn = symbolTable.lookupNearestSymbolFrom<FuncOp>(*this, fnAttr);652  if (!fn)653    return emitOpError() << "'" << fnAttr.getValue()654                         << "' does not reference a valid function";655 656  return success();657}658 659//===----------------------------------------------------------------------===//660// FuncOp661//===----------------------------------------------------------------------===//662 663void FuncOp::build(OpBuilder &builder, OperationState &state, StringRef name,664                   FunctionType type, ArrayRef<NamedAttribute> attrs,665                   ArrayRef<DictionaryAttr> argAttrs) {666  state.addAttribute(SymbolTable::getSymbolAttrName(),667                     builder.getStringAttr(name));668  state.addAttribute(getFunctionTypeAttrName(state.name), TypeAttr::get(type));669  state.attributes.append(attrs.begin(), attrs.end());670  state.addRegion();671 672  if (argAttrs.empty())673    return;674  assert(type.getNumInputs() == argAttrs.size());675  call_interface_impl::addArgAndResultAttrs(676      builder, state, argAttrs, /*resultAttrs=*/{},677      getArgAttrsAttrName(state.name), getResAttrsAttrName(state.name));678}679 680ParseResult FuncOp::parse(OpAsmParser &parser, OperationState &result) {681  auto buildFuncType =682      [](Builder &builder, ArrayRef<Type> argTypes, ArrayRef<Type> results,683         function_interface_impl::VariadicFlag,684         std::string &) { return builder.getFunctionType(argTypes, results); };685 686  return function_interface_impl::parseFunctionOp(687      parser, result, /*allowVariadic=*/false,688      getFunctionTypeAttrName(result.name), buildFuncType,689      getArgAttrsAttrName(result.name), getResAttrsAttrName(result.name));690}691 692void FuncOp::print(OpAsmPrinter &p) {693  function_interface_impl::printFunctionOp(694      p, *this, /*isVariadic=*/false, getFunctionTypeAttrName(),695      getArgAttrsAttrName(), getResAttrsAttrName());696}697 698LogicalResult FuncOp::verify() {699  if (llvm::any_of(getArgumentTypes(), llvm::IsaPred<LValueType>)) {700    return emitOpError("cannot have lvalue type as argument");701  }702 703  if (getNumResults() > 1)704    return emitOpError("requires zero or exactly one result, but has ")705           << getNumResults();706 707  if (getNumResults() == 1 && isa<ArrayType>(getResultTypes()[0]))708    return emitOpError("cannot return array type");709 710  return success();711}712 713//===----------------------------------------------------------------------===//714// ReturnOp715//===----------------------------------------------------------------------===//716 717LogicalResult ReturnOp::verify() {718  auto function = cast<FuncOp>((*this)->getParentOp());719 720  // The operand number and types must match the function signature.721  if (getNumOperands() != function.getNumResults())722    return emitOpError("has ")723           << getNumOperands() << " operands, but enclosing function (@"724           << function.getName() << ") returns " << function.getNumResults();725 726  if (function.getNumResults() == 1)727    if (getOperand().getType() != function.getResultTypes()[0])728      return emitError() << "type of the return operand ("729                         << getOperand().getType()730                         << ") doesn't match function result type ("731                         << function.getResultTypes()[0] << ")"732                         << " in function @" << function.getName();733  return success();734}735 736//===----------------------------------------------------------------------===//737// IfOp738//===----------------------------------------------------------------------===//739 740void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,741                 bool addThenBlock, bool addElseBlock) {742  assert((!addElseBlock || addThenBlock) &&743         "must not create else block w/o then block");744  result.addOperands(cond);745 746  // Add regions and blocks.747  OpBuilder::InsertionGuard guard(builder);748  Region *thenRegion = result.addRegion();749  if (addThenBlock)750    builder.createBlock(thenRegion);751  Region *elseRegion = result.addRegion();752  if (addElseBlock)753    builder.createBlock(elseRegion);754}755 756void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,757                 bool withElseRegion) {758  result.addOperands(cond);759 760  // Build then region.761  OpBuilder::InsertionGuard guard(builder);762  Region *thenRegion = result.addRegion();763  builder.createBlock(thenRegion);764 765  // Build else region.766  Region *elseRegion = result.addRegion();767  if (withElseRegion) {768    builder.createBlock(elseRegion);769  }770}771 772void IfOp::build(OpBuilder &builder, OperationState &result, Value cond,773                 function_ref<void(OpBuilder &, Location)> thenBuilder,774                 function_ref<void(OpBuilder &, Location)> elseBuilder) {775  assert(thenBuilder && "the builder callback for 'then' must be present");776  result.addOperands(cond);777 778  // Build then region.779  OpBuilder::InsertionGuard guard(builder);780  Region *thenRegion = result.addRegion();781  builder.createBlock(thenRegion);782  thenBuilder(builder, result.location);783 784  // Build else region.785  Region *elseRegion = result.addRegion();786  if (elseBuilder) {787    builder.createBlock(elseRegion);788    elseBuilder(builder, result.location);789  }790}791 792ParseResult IfOp::parse(OpAsmParser &parser, OperationState &result) {793  // Create the regions for 'then'.794  result.regions.reserve(2);795  Region *thenRegion = result.addRegion();796  Region *elseRegion = result.addRegion();797 798  Builder &builder = parser.getBuilder();799  OpAsmParser::UnresolvedOperand cond;800  Type i1Type = builder.getIntegerType(1);801  if (parser.parseOperand(cond) ||802      parser.resolveOperand(cond, i1Type, result.operands))803    return failure();804  // Parse the 'then' region.805  if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))806    return failure();807  IfOp::ensureTerminator(*thenRegion, parser.getBuilder(), result.location);808 809  // If we find an 'else' keyword then parse the 'else' region.810  if (!parser.parseOptionalKeyword("else")) {811    if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))812      return failure();813    IfOp::ensureTerminator(*elseRegion, parser.getBuilder(), result.location);814  }815 816  // Parse the optional attribute list.817  if (parser.parseOptionalAttrDict(result.attributes))818    return failure();819  return success();820}821 822void IfOp::print(OpAsmPrinter &p) {823  bool printBlockTerminators = false;824 825  p << " " << getCondition();826  p << ' ';827  p.printRegion(getThenRegion(),828                /*printEntryBlockArgs=*/false,829                /*printBlockTerminators=*/printBlockTerminators);830 831  // Print the 'else' regions if it exists and has a block.832  Region &elseRegion = getElseRegion();833  if (!elseRegion.empty()) {834    p << " else ";835    p.printRegion(elseRegion,836                  /*printEntryBlockArgs=*/false,837                  /*printBlockTerminators=*/printBlockTerminators);838  }839 840  p.printOptionalAttrDict((*this)->getAttrs());841}842 843/// Given the region at `index`, or the parent operation if `index` is None,844/// return the successor regions. These are the regions that may be selected845/// during the flow of control. `operands` is a set of optional attributes846/// that correspond to a constant value for each operand, or null if that847/// operand is not a constant.848void IfOp::getSuccessorRegions(RegionBranchPoint point,849                               SmallVectorImpl<RegionSuccessor> &regions) {850  // The `then` and the `else` region branch back to the parent operation.851  if (!point.isParent()) {852    regions.push_back(853        RegionSuccessor(getOperation(), getOperation()->getResults()));854    return;855  }856 857  regions.push_back(RegionSuccessor(&getThenRegion()));858 859  // Don't consider the else region if it is empty.860  Region *elseRegion = &this->getElseRegion();861  if (elseRegion->empty())862    regions.push_back(863        RegionSuccessor(getOperation(), getOperation()->getResults()));864  else865    regions.push_back(RegionSuccessor(elseRegion));866}867 868void IfOp::getEntrySuccessorRegions(ArrayRef<Attribute> operands,869                                    SmallVectorImpl<RegionSuccessor> &regions) {870  FoldAdaptor adaptor(operands, *this);871  auto boolAttr = dyn_cast_or_null<BoolAttr>(adaptor.getCondition());872  if (!boolAttr || boolAttr.getValue())873    regions.emplace_back(&getThenRegion());874 875  // If the else region is empty, execution continues after the parent op.876  if (!boolAttr || !boolAttr.getValue()) {877    if (!getElseRegion().empty())878      regions.emplace_back(&getElseRegion());879    else880      regions.emplace_back(getOperation(), getOperation()->getResults());881  }882}883 884void IfOp::getRegionInvocationBounds(885    ArrayRef<Attribute> operands,886    SmallVectorImpl<InvocationBounds> &invocationBounds) {887  if (auto cond = llvm::dyn_cast_or_null<BoolAttr>(operands[0])) {888    // If the condition is known, then one region is known to be executed once889    // and the other zero times.890    invocationBounds.emplace_back(0, cond.getValue() ? 1 : 0);891    invocationBounds.emplace_back(0, cond.getValue() ? 0 : 1);892  } else {893    // Non-constant condition. Each region may be executed 0 or 1 times.894    invocationBounds.assign(2, {0, 1});895  }896}897 898//===----------------------------------------------------------------------===//899// IncludeOp900//===----------------------------------------------------------------------===//901 902void IncludeOp::print(OpAsmPrinter &p) {903  bool standardInclude = getIsStandardInclude();904 905  p << " ";906  if (standardInclude)907    p << "<";908  p << "\"" << getInclude() << "\"";909  if (standardInclude)910    p << ">";911}912 913ParseResult IncludeOp::parse(OpAsmParser &parser, OperationState &result) {914  bool standardInclude = !parser.parseOptionalLess();915 916  StringAttr include;917  OptionalParseResult includeParseResult =918      parser.parseOptionalAttribute(include, "include", result.attributes);919  if (!includeParseResult.has_value())920    return parser.emitError(parser.getNameLoc()) << "expected string attribute";921 922  if (standardInclude && parser.parseOptionalGreater())923    return parser.emitError(parser.getNameLoc())924           << "expected trailing '>' for standard include";925 926  if (standardInclude)927    result.addAttribute("is_standard_include",928                        UnitAttr::get(parser.getContext()));929 930  return success();931}932 933//===----------------------------------------------------------------------===//934// LiteralOp935//===----------------------------------------------------------------------===//936 937/// The literal op requires a non-empty value.938LogicalResult emitc::LiteralOp::verify() {939  if (getValue().empty())940    return emitOpError() << "value must not be empty";941  return success();942}943//===----------------------------------------------------------------------===//944// SubOp945//===----------------------------------------------------------------------===//946 947LogicalResult SubOp::verify() {948  Type lhsType = getLhs().getType();949  Type rhsType = getRhs().getType();950  Type resultType = getResult().getType();951 952  if (isa<emitc::PointerType>(rhsType) && !isa<emitc::PointerType>(lhsType))953    return emitOpError("rhs can only be a pointer if lhs is a pointer");954 955  if (isa<emitc::PointerType>(lhsType) &&956      !isa<IntegerType, emitc::OpaqueType, emitc::PointerType>(rhsType))957    return emitOpError("requires that rhs is an integer, pointer or of opaque "958                       "type if lhs is a pointer");959 960  if (isa<emitc::PointerType>(lhsType) && isa<emitc::PointerType>(rhsType) &&961      !isa<IntegerType, emitc::PtrDiffTType, emitc::OpaqueType>(resultType))962    return emitOpError("requires that the result is an integer, ptrdiff_t or "963                       "of opaque type if lhs and rhs are pointers");964  return success();965}966 967//===----------------------------------------------------------------------===//968// VariableOp969//===----------------------------------------------------------------------===//970 971LogicalResult emitc::VariableOp::verify() {972  return verifyInitializationAttribute(getOperation(), getValueAttr());973}974 975//===----------------------------------------------------------------------===//976// YieldOp977//===----------------------------------------------------------------------===//978 979LogicalResult emitc::YieldOp::verify() {980  Value result = getResult();981  Operation *containingOp = getOperation()->getParentOp();982 983  if (!isa<DoOp>(containingOp) && result && containingOp->getNumResults() != 1)984    return emitOpError() << "yields a value not returned by parent";985 986  if (!isa<DoOp>(containingOp) && !result && containingOp->getNumResults() != 0)987    return emitOpError() << "does not yield a value to be returned by parent";988 989  return success();990}991 992//===----------------------------------------------------------------------===//993// SubscriptOp994//===----------------------------------------------------------------------===//995 996LogicalResult emitc::SubscriptOp::verify() {997  // Checks for array operand.998  if (auto arrayType = llvm::dyn_cast<emitc::ArrayType>(getValue().getType())) {999    // Check number of indices.1000    if (getIndices().size() != (size_t)arrayType.getRank()) {1001      return emitOpError() << "on array operand requires number of indices ("1002                           << getIndices().size()1003                           << ") to match the rank of the array type ("1004                           << arrayType.getRank() << ")";1005    }1006    // Check types of index operands.1007    for (unsigned i = 0, e = getIndices().size(); i != e; ++i) {1008      Type type = getIndices()[i].getType();1009      if (!isIntegerIndexOrOpaqueType(type)) {1010        return emitOpError() << "on array operand requires index operand " << i1011                             << " to be integer-like, but got " << type;1012      }1013    }1014    // Check element type.1015    Type elementType = arrayType.getElementType();1016    Type resultType = getType().getValueType();1017    if (elementType != resultType) {1018      return emitOpError() << "on array operand requires element type ("1019                           << elementType << ") and result type (" << resultType1020                           << ") to match";1021    }1022    return success();1023  }1024 1025  // Checks for pointer operand.1026  if (auto pointerType =1027          llvm::dyn_cast<emitc::PointerType>(getValue().getType())) {1028    // Check number of indices.1029    if (getIndices().size() != 1) {1030      return emitOpError()1031             << "on pointer operand requires one index operand, but got "1032             << getIndices().size();1033    }1034    // Check types of index operand.1035    Type type = getIndices()[0].getType();1036    if (!isIntegerIndexOrOpaqueType(type)) {1037      return emitOpError() << "on pointer operand requires index operand to be "1038                              "integer-like, but got "1039                           << type;1040    }1041    // Check pointee type.1042    Type pointeeType = pointerType.getPointee();1043    Type resultType = getType().getValueType();1044    if (pointeeType != resultType) {1045      return emitOpError() << "on pointer operand requires pointee type ("1046                           << pointeeType << ") and result type (" << resultType1047                           << ") to match";1048    }1049    return success();1050  }1051 1052  // The operand has opaque type, so we can't assume anything about the number1053  // or types of index operands.1054  return success();1055}1056 1057//===----------------------------------------------------------------------===//1058// VerbatimOp1059//===----------------------------------------------------------------------===//1060 1061LogicalResult emitc::VerbatimOp::verify() {1062  auto errorCallback = [&]() -> InFlightDiagnostic {1063    return this->emitOpError();1064  };1065  FailureOr<SmallVector<ReplacementItem>> fmt =1066      ::parseFormatString(getValue(), getFmtArgs(), errorCallback);1067  if (failed(fmt))1068    return failure();1069 1070  size_t numPlaceholders = llvm::count_if(*fmt, [](ReplacementItem &item) {1071    return std::holds_alternative<Placeholder>(item);1072  });1073 1074  if (numPlaceholders != getFmtArgs().size()) {1075    return emitOpError()1076           << "requires operands for each placeholder in the format string";1077  }1078  return success();1079}1080 1081FailureOr<SmallVector<ReplacementItem>> emitc::VerbatimOp::parseFormatString() {1082  // Error checking is done in verify.1083  return ::parseFormatString(getValue(), getFmtArgs());1084}1085 1086//===----------------------------------------------------------------------===//1087// EmitC Enums1088//===----------------------------------------------------------------------===//1089 1090#include "mlir/Dialect/EmitC/IR/EmitCEnums.cpp.inc"1091 1092//===----------------------------------------------------------------------===//1093// EmitC Attributes1094//===----------------------------------------------------------------------===//1095 1096#define GET_ATTRDEF_CLASSES1097#include "mlir/Dialect/EmitC/IR/EmitCAttributes.cpp.inc"1098 1099//===----------------------------------------------------------------------===//1100// EmitC Types1101//===----------------------------------------------------------------------===//1102 1103#define GET_TYPEDEF_CLASSES1104#include "mlir/Dialect/EmitC/IR/EmitCTypes.cpp.inc"1105 1106//===----------------------------------------------------------------------===//1107// ArrayType1108//===----------------------------------------------------------------------===//1109 1110Type emitc::ArrayType::parse(AsmParser &parser) {1111  if (parser.parseLess())1112    return Type();1113 1114  SmallVector<int64_t, 4> dimensions;1115  if (parser.parseDimensionList(dimensions, /*allowDynamic=*/false,1116                                /*withTrailingX=*/true))1117    return Type();1118  // Parse the element type.1119  auto typeLoc = parser.getCurrentLocation();1120  Type elementType;1121  if (parser.parseType(elementType))1122    return Type();1123 1124  // Check that array is formed from allowed types.1125  if (!isValidElementType(elementType))1126    return parser.emitError(typeLoc, "invalid array element type '")1127               << elementType << "'",1128           Type();1129  if (parser.parseGreater())1130    return Type();1131  return parser.getChecked<ArrayType>(dimensions, elementType);1132}1133 1134void emitc::ArrayType::print(AsmPrinter &printer) const {1135  printer << "<";1136  for (int64_t dim : getShape()) {1137    printer << dim << 'x';1138  }1139  printer.printType(getElementType());1140  printer << ">";1141}1142 1143LogicalResult emitc::ArrayType::verify(1144    ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,1145    ::llvm::ArrayRef<int64_t> shape, Type elementType) {1146  if (shape.empty())1147    return emitError() << "shape must not be empty";1148 1149  for (int64_t dim : shape) {1150    if (dim < 0)1151      return emitError() << "dimensions must have non-negative size";1152  }1153 1154  if (!elementType)1155    return emitError() << "element type must not be none";1156 1157  if (!isValidElementType(elementType))1158    return emitError() << "invalid array element type";1159 1160  return success();1161}1162 1163emitc::ArrayType1164emitc::ArrayType::cloneWith(std::optional<ArrayRef<int64_t>> shape,1165                            Type elementType) const {1166  if (!shape)1167    return emitc::ArrayType::get(getShape(), elementType);1168  return emitc::ArrayType::get(*shape, elementType);1169}1170 1171//===----------------------------------------------------------------------===//1172// LValueType1173//===----------------------------------------------------------------------===//1174 1175LogicalResult mlir::emitc::LValueType::verify(1176    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,1177    mlir::Type value) {1178  // Check that the wrapped type is valid. This especially forbids nested1179  // lvalue types.1180  if (!isSupportedEmitCType(value))1181    return emitError()1182           << "!emitc.lvalue must wrap supported emitc type, but got " << value;1183 1184  if (llvm::isa<emitc::ArrayType>(value))1185    return emitError() << "!emitc.lvalue cannot wrap !emitc.array type";1186 1187  return success();1188}1189 1190//===----------------------------------------------------------------------===//1191// OpaqueType1192//===----------------------------------------------------------------------===//1193 1194LogicalResult mlir::emitc::OpaqueType::verify(1195    llvm::function_ref<mlir::InFlightDiagnostic()> emitError,1196    llvm::StringRef value) {1197  if (value.empty()) {1198    return emitError() << "expected non empty string in !emitc.opaque type";1199  }1200  if (value.back() == '*') {1201    return emitError() << "pointer not allowed as outer type with "1202                          "!emitc.opaque, use !emitc.ptr instead";1203  }1204  return success();1205}1206 1207//===----------------------------------------------------------------------===//1208// PointerType1209//===----------------------------------------------------------------------===//1210 1211LogicalResult mlir::emitc::PointerType::verify(1212    llvm::function_ref<mlir::InFlightDiagnostic()> emitError, Type value) {1213  if (llvm::isa<emitc::LValueType>(value))1214    return emitError() << "pointers to lvalues are not allowed";1215 1216  return success();1217}1218 1219//===----------------------------------------------------------------------===//1220// GlobalOp1221//===----------------------------------------------------------------------===//1222static void printEmitCGlobalOpTypeAndInitialValue(OpAsmPrinter &p, GlobalOp op,1223                                                  TypeAttr type,1224                                                  Attribute initialValue) {1225  p << type;1226  if (initialValue) {1227    p << " = ";1228    p.printAttributeWithoutType(initialValue);1229  }1230}1231 1232static Type getInitializerTypeForGlobal(Type type) {1233  if (auto array = llvm::dyn_cast<ArrayType>(type))1234    return RankedTensorType::get(array.getShape(), array.getElementType());1235  return type;1236}1237 1238static ParseResult1239parseEmitCGlobalOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr,1240                                      Attribute &initialValue) {1241  Type type;1242  if (parser.parseType(type))1243    return failure();1244 1245  typeAttr = TypeAttr::get(type);1246 1247  if (parser.parseOptionalEqual())1248    return success();1249 1250  if (parser.parseAttribute(initialValue, getInitializerTypeForGlobal(type)))1251    return failure();1252 1253  if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(1254          initialValue))1255    return parser.emitError(parser.getNameLoc())1256           << "initial value should be a integer, float, elements or opaque "1257              "attribute";1258  return success();1259}1260 1261LogicalResult GlobalOp::verify() {1262  if (!isSupportedEmitCType(getType())) {1263    return emitOpError("expected valid emitc type");1264  }1265  if (getInitialValue().has_value()) {1266    Attribute initValue = getInitialValue().value();1267    // Check that the type of the initial value is compatible with the type of1268    // the global variable.1269    if (auto elementsAttr = llvm::dyn_cast<ElementsAttr>(initValue)) {1270      auto arrayType = llvm::dyn_cast<ArrayType>(getType());1271      if (!arrayType)1272        return emitOpError("expected array type, but got ") << getType();1273 1274      Type initType = elementsAttr.getType();1275      Type tensorType = getInitializerTypeForGlobal(getType());1276      if (initType != tensorType) {1277        return emitOpError("initial value expected to be of type ")1278               << getType() << ", but was of type " << initType;1279      }1280    } else if (auto intAttr = dyn_cast<IntegerAttr>(initValue)) {1281      if (intAttr.getType() != getType()) {1282        return emitOpError("initial value expected to be of type ")1283               << getType() << ", but was of type " << intAttr.getType();1284      }1285    } else if (auto floatAttr = dyn_cast<FloatAttr>(initValue)) {1286      if (floatAttr.getType() != getType()) {1287        return emitOpError("initial value expected to be of type ")1288               << getType() << ", but was of type " << floatAttr.getType();1289      }1290    } else if (!isa<emitc::OpaqueAttr>(initValue)) {1291      return emitOpError("initial value should be a integer, float, elements "1292                         "or opaque attribute, but got ")1293             << initValue;1294    }1295  }1296  if (getStaticSpecifier() && getExternSpecifier()) {1297    return emitOpError("cannot have both static and extern specifiers");1298  }1299  return success();1300}1301 1302//===----------------------------------------------------------------------===//1303// GetGlobalOp1304//===----------------------------------------------------------------------===//1305 1306LogicalResult1307GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {1308  // Verify that the type matches the type of the global variable.1309  auto global =1310      symbolTable.lookupNearestSymbolFrom<GlobalOp>(*this, getNameAttr());1311  if (!global)1312    return emitOpError("'")1313           << getName() << "' does not reference a valid emitc.global";1314 1315  Type resultType = getResult().getType();1316  Type globalType = global.getType();1317 1318  // global has array type1319  if (llvm::isa<ArrayType>(globalType)) {1320    if (globalType != resultType)1321      return emitOpError("on array type expects result type ")1322             << resultType << " to match type " << globalType1323             << " of the global @" << getName();1324    return success();1325  }1326 1327  // global has non-array type1328  auto lvalueType = dyn_cast<LValueType>(resultType);1329  if (!lvalueType)1330    return emitOpError("on non-array type expects result type to be an "1331                       "lvalue type for the global @")1332           << getName();1333  if (lvalueType.getValueType() != globalType)1334    return emitOpError("on non-array type expects result inner type ")1335           << lvalueType.getValueType() << " to match type " << globalType1336           << " of the global @" << getName();1337  return success();1338}1339 1340//===----------------------------------------------------------------------===//1341// SwitchOp1342//===----------------------------------------------------------------------===//1343 1344/// Parse the case regions and values.1345static ParseResult1346parseSwitchCases(OpAsmParser &parser, DenseI64ArrayAttr &cases,1347                 SmallVectorImpl<std::unique_ptr<Region>> &caseRegions) {1348  SmallVector<int64_t> caseValues;1349  while (succeeded(parser.parseOptionalKeyword("case"))) {1350    int64_t value;1351    Region &region = *caseRegions.emplace_back(std::make_unique<Region>());1352    if (parser.parseInteger(value) ||1353        parser.parseRegion(region, /*arguments=*/{}))1354      return failure();1355    caseValues.push_back(value);1356  }1357  cases = parser.getBuilder().getDenseI64ArrayAttr(caseValues);1358  return success();1359}1360 1361/// Print the case regions and values.1362static void printSwitchCases(OpAsmPrinter &p, Operation *op,1363                             DenseI64ArrayAttr cases, RegionRange caseRegions) {1364  for (auto [value, region] : llvm::zip(cases.asArrayRef(), caseRegions)) {1365    p.printNewline();1366    p << "case " << value << ' ';1367    p.printRegion(*region, /*printEntryBlockArgs=*/false);1368  }1369}1370 1371static LogicalResult verifyRegion(emitc::SwitchOp op, Region &region,1372                                  const Twine &name) {1373  auto yield = dyn_cast<emitc::YieldOp>(region.front().back());1374  if (!yield)1375    return op.emitOpError("expected region to end with emitc.yield, but got ")1376           << region.front().back().getName();1377 1378  if (yield.getNumOperands() != 0) {1379    return (op.emitOpError("expected each region to return ")1380            << "0 values, but " << name << " returns "1381            << yield.getNumOperands())1382               .attachNote(yield.getLoc())1383           << "see yield operation here";1384  }1385 1386  return success();1387}1388 1389LogicalResult emitc::SwitchOp::verify() {1390  if (!isIntegerIndexOrOpaqueType(getArg().getType()))1391    return emitOpError("unsupported type ") << getArg().getType();1392 1393  if (getCases().size() != getCaseRegions().size()) {1394    return emitOpError("has ")1395           << getCaseRegions().size() << " case regions but "1396           << getCases().size() << " case values";1397  }1398 1399  DenseSet<int64_t> valueSet;1400  for (int64_t value : getCases())1401    if (!valueSet.insert(value).second)1402      return emitOpError("has duplicate case value: ") << value;1403 1404  if (failed(verifyRegion(*this, getDefaultRegion(), "default region")))1405    return failure();1406 1407  for (auto [idx, caseRegion] : llvm::enumerate(getCaseRegions()))1408    if (failed(verifyRegion(*this, caseRegion, "case region #" + Twine(idx))))1409      return failure();1410 1411  return success();1412}1413 1414unsigned emitc::SwitchOp::getNumCases() { return getCases().size(); }1415 1416Block &emitc::SwitchOp::getDefaultBlock() { return getDefaultRegion().front(); }1417 1418Block &emitc::SwitchOp::getCaseBlock(unsigned idx) {1419  assert(idx < getNumCases() && "case index out-of-bounds");1420  return getCaseRegions()[idx].front();1421}1422 1423void SwitchOp::getSuccessorRegions(1424    RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &successors) {1425  llvm::append_range(successors, getRegions());1426}1427 1428void SwitchOp::getEntrySuccessorRegions(1429    ArrayRef<Attribute> operands,1430    SmallVectorImpl<RegionSuccessor> &successors) {1431  FoldAdaptor adaptor(operands, *this);1432 1433  // If a constant was not provided, all regions are possible successors.1434  auto arg = dyn_cast_or_null<IntegerAttr>(adaptor.getArg());1435  if (!arg) {1436    llvm::append_range(successors, getRegions());1437    return;1438  }1439 1440  // Otherwise, try to find a case with a matching value. If not, the1441  // default region is the only successor.1442  for (auto [caseValue, caseRegion] : llvm::zip(getCases(), getCaseRegions())) {1443    if (caseValue == arg.getInt()) {1444      successors.emplace_back(&caseRegion);1445      return;1446    }1447  }1448  successors.emplace_back(&getDefaultRegion());1449}1450 1451void SwitchOp::getRegionInvocationBounds(1452    ArrayRef<Attribute> operands, SmallVectorImpl<InvocationBounds> &bounds) {1453  auto operandValue = llvm::dyn_cast_or_null<IntegerAttr>(operands.front());1454  if (!operandValue) {1455    // All regions are invoked at most once.1456    bounds.append(getNumRegions(), InvocationBounds(/*lb=*/0, /*ub=*/1));1457    return;1458  }1459 1460  unsigned liveIndex = getNumRegions() - 1;1461  const auto *iteratorToInt = llvm::find(getCases(), operandValue.getInt());1462 1463  liveIndex = iteratorToInt != getCases().end()1464                  ? std::distance(getCases().begin(), iteratorToInt)1465                  : liveIndex;1466 1467  for (unsigned regIndex = 0, regNum = getNumRegions(); regIndex < regNum;1468       ++regIndex)1469    bounds.emplace_back(/*lb=*/0, /*ub=*/regIndex == liveIndex);1470}1471 1472//===----------------------------------------------------------------------===//1473// FileOp1474//===----------------------------------------------------------------------===//1475void FileOp::build(OpBuilder &builder, OperationState &state, StringRef id) {1476  state.addRegion()->emplaceBlock();1477  state.attributes.push_back(1478      builder.getNamedAttr("id", builder.getStringAttr(id)));1479}1480 1481//===----------------------------------------------------------------------===//1482// FieldOp1483//===----------------------------------------------------------------------===//1484 1485static void printEmitCFieldOpTypeAndInitialValue(OpAsmPrinter &p, FieldOp op,1486                                                 TypeAttr type,1487                                                 Attribute initialValue) {1488  p << type;1489  if (initialValue) {1490    p << " = ";1491    p.printAttributeWithoutType(initialValue);1492  }1493}1494 1495static Type getInitializerTypeForField(Type type) {1496  if (auto array = llvm::dyn_cast<ArrayType>(type))1497    return RankedTensorType::get(array.getShape(), array.getElementType());1498  return type;1499}1500 1501static ParseResult1502parseEmitCFieldOpTypeAndInitialValue(OpAsmParser &parser, TypeAttr &typeAttr,1503                                     Attribute &initialValue) {1504  Type type;1505  if (parser.parseType(type))1506    return failure();1507 1508  typeAttr = TypeAttr::get(type);1509 1510  if (parser.parseOptionalEqual())1511    return success();1512 1513  if (parser.parseAttribute(initialValue, getInitializerTypeForField(type)))1514    return failure();1515 1516  if (!llvm::isa<ElementsAttr, IntegerAttr, FloatAttr, emitc::OpaqueAttr>(1517          initialValue))1518    return parser.emitError(parser.getNameLoc())1519           << "initial value should be a integer, float, elements or opaque "1520              "attribute";1521  return success();1522}1523 1524LogicalResult FieldOp::verify() {1525  if (!isSupportedEmitCType(getType()))1526    return emitOpError("expected valid emitc type");1527 1528  Operation *parentOp = getOperation()->getParentOp();1529  if (!parentOp || !isa<emitc::ClassOp>(parentOp))1530    return emitOpError("field must be nested within an emitc.class operation");1531 1532  StringAttr symName = getSymNameAttr();1533  if (!symName || symName.getValue().empty())1534    return emitOpError("field must have a non-empty symbol name");1535 1536  return success();1537}1538 1539//===----------------------------------------------------------------------===//1540// GetFieldOp1541//===----------------------------------------------------------------------===//1542 1543LogicalResult GetFieldOp::verify() {1544  auto parentClassOp = getOperation()->getParentOfType<emitc::ClassOp>();1545  if (!parentClassOp.getOperation())1546    return emitOpError(" must be nested within an emitc.class operation");1547 1548  return success();1549}1550 1551LogicalResult GetFieldOp::verifySymbolUses(SymbolTableCollection &symbolTable) {1552  mlir::FlatSymbolRefAttr fieldNameAttr = getFieldNameAttr();1553  FieldOp fieldOp =1554      symbolTable.lookupNearestSymbolFrom<FieldOp>(*this, fieldNameAttr);1555  if (!fieldOp)1556    return emitOpError("field '")1557           << fieldNameAttr << "' not found in the class";1558 1559  Type getFieldResultType = getResult().getType();1560  Type fieldType = fieldOp.getType();1561 1562  if (fieldType != getFieldResultType)1563    return emitOpError("result type ")1564           << getFieldResultType << " does not match field '" << fieldNameAttr1565           << "' type " << fieldType;1566 1567  return success();1568}1569 1570//===----------------------------------------------------------------------===//1571// DoOp1572//===----------------------------------------------------------------------===//1573 1574void DoOp::print(OpAsmPrinter &p) {1575  p << ' ';1576  p.printRegion(getBodyRegion(), /*printEntryBlockArgs=*/false);1577  p << " while ";1578  p.printRegion(getConditionRegion());1579  p.printOptionalAttrDictWithKeyword(getOperation()->getAttrs());1580}1581 1582LogicalResult emitc::DoOp::verify() {1583  Block &condBlock = getConditionRegion().front();1584 1585  if (condBlock.getOperations().size() != 2)1586    return emitOpError(1587               "condition region must contain exactly two operations: "1588               "'emitc.expression' followed by 'emitc.yield', but found ")1589           << condBlock.getOperations().size() << " operations";1590 1591  Operation &first = condBlock.front();1592  auto exprOp = dyn_cast<emitc::ExpressionOp>(first);1593  if (!exprOp)1594    return emitOpError("expected first op in condition region to be "1595                       "'emitc.expression', but got ")1596           << first.getName();1597 1598  if (!exprOp.getResult().getType().isInteger(1))1599    return emitOpError("emitc.expression in condition region must return "1600                       "'i1', but returns ")1601           << exprOp.getResult().getType();1602 1603  Operation &last = condBlock.back();1604  auto condYield = dyn_cast<emitc::YieldOp>(last);1605  if (!condYield)1606    return emitOpError("expected last op in condition region to be "1607                       "'emitc.yield', but got ")1608           << last.getName();1609 1610  if (condYield.getNumOperands() != 1)1611    return emitOpError("expected condition region to return 1 value, but "1612                       "it returns ")1613           << condYield.getNumOperands() << " values";1614 1615  if (condYield.getOperand(0) != exprOp.getResult())1616    return emitError("'emitc.yield' must return result of "1617                     "'emitc.expression' from this condition region");1618 1619  Block &bodyBlock = getBodyRegion().front();1620  if (bodyBlock.mightHaveTerminator())1621    return emitOpError("body region must not contain terminator");1622 1623  return success();1624}1625 1626ParseResult DoOp::parse(OpAsmParser &parser, OperationState &result) {1627  Region *bodyRegion = result.addRegion();1628  Region *condRegion = result.addRegion();1629 1630  if (parser.parseRegion(*bodyRegion) || parser.parseKeyword("while") ||1631      parser.parseRegion(*condRegion))1632    return failure();1633 1634  if (bodyRegion->empty())1635    bodyRegion->emplaceBlock();1636 1637  return parser.parseOptionalAttrDictWithKeyword(result.attributes);1638}1639 1640//===----------------------------------------------------------------------===//1641// TableGen'd op method definitions1642//===----------------------------------------------------------------------===//1643 1644#include "mlir/Dialect/EmitC/IR/EmitCInterfaces.cpp.inc"1645 1646#define GET_OP_CLASSES1647#include "mlir/Dialect/EmitC/IR/EmitC.cpp.inc"1648