brintos

brintos / llvm-project-archived public Read only

0
0
Text · 120.0 KiB · 9fada0b Raw
3402 lines · cpp
1//===- CIRDialect.cpp - MLIR CIR ops implementation -----------------------===//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// This file implements the CIR dialect and its operations.10//11//===----------------------------------------------------------------------===//12 13#include "clang/CIR/Dialect/IR/CIRDialect.h"14 15#include "clang/CIR/Dialect/IR/CIRAttrs.h"16#include "clang/CIR/Dialect/IR/CIROpsEnums.h"17#include "clang/CIR/Dialect/IR/CIRTypes.h"18 19#include "mlir/IR/Attributes.h"20#include "mlir/IR/DialectImplementation.h"21#include "mlir/Interfaces/ControlFlowInterfaces.h"22#include "mlir/Interfaces/FunctionImplementation.h"23#include "mlir/Support/LLVM.h"24 25#include "clang/CIR/Dialect/IR/CIROpsDialect.cpp.inc"26#include "clang/CIR/Dialect/IR/CIROpsEnums.cpp.inc"27#include "clang/CIR/MissingFeatures.h"28#include "llvm/ADT/SetOperations.h"29#include "llvm/ADT/SmallSet.h"30#include "llvm/Support/LogicalResult.h"31 32using namespace mlir;33using namespace cir;34 35//===----------------------------------------------------------------------===//36// CIR Dialect37//===----------------------------------------------------------------------===//38namespace {39struct CIROpAsmDialectInterface : public OpAsmDialectInterface {40  using OpAsmDialectInterface::OpAsmDialectInterface;41 42  AliasResult getAlias(Type type, raw_ostream &os) const final {43    if (auto recordType = dyn_cast<cir::RecordType>(type)) {44      StringAttr nameAttr = recordType.getName();45      if (!nameAttr)46        os << "rec_anon_" << recordType.getKindAsStr();47      else48        os << "rec_" << nameAttr.getValue();49      return AliasResult::OverridableAlias;50    }51    if (auto intType = dyn_cast<cir::IntType>(type)) {52      // We only provide alias for standard integer types (i.e. integer types53      // whose width is a power of 2 and at least 8).54      unsigned width = intType.getWidth();55      if (width < 8 || !llvm::isPowerOf2_32(width))56        return AliasResult::NoAlias;57      os << intType.getAlias();58      return AliasResult::OverridableAlias;59    }60    if (auto voidType = dyn_cast<cir::VoidType>(type)) {61      os << voidType.getAlias();62      return AliasResult::OverridableAlias;63    }64 65    return AliasResult::NoAlias;66  }67 68  AliasResult getAlias(Attribute attr, raw_ostream &os) const final {69    if (auto boolAttr = mlir::dyn_cast<cir::BoolAttr>(attr)) {70      os << (boolAttr.getValue() ? "true" : "false");71      return AliasResult::FinalAlias;72    }73    if (auto bitfield = mlir::dyn_cast<cir::BitfieldInfoAttr>(attr)) {74      os << "bfi_" << bitfield.getName().str();75      return AliasResult::FinalAlias;76    }77    if (auto dynCastInfoAttr = mlir::dyn_cast<cir::DynamicCastInfoAttr>(attr)) {78      os << dynCastInfoAttr.getAlias();79      return AliasResult::FinalAlias;80    }81    return AliasResult::NoAlias;82  }83};84} // namespace85 86void cir::CIRDialect::initialize() {87  registerTypes();88  registerAttributes();89  addOperations<90#define GET_OP_LIST91#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"92      >();93  addInterfaces<CIROpAsmDialectInterface>();94}95 96Operation *cir::CIRDialect::materializeConstant(mlir::OpBuilder &builder,97                                                mlir::Attribute value,98                                                mlir::Type type,99                                                mlir::Location loc) {100  return cir::ConstantOp::create(builder, loc, type,101                                 mlir::cast<mlir::TypedAttr>(value));102}103 104//===----------------------------------------------------------------------===//105// Helpers106//===----------------------------------------------------------------------===//107 108// Parses one of the keywords provided in the list `keywords` and returns the109// position of the parsed keyword in the list. If none of the keywords from the110// list is parsed, returns -1.111static int parseOptionalKeywordAlternative(AsmParser &parser,112                                           ArrayRef<llvm::StringRef> keywords) {113  for (auto en : llvm::enumerate(keywords)) {114    if (succeeded(parser.parseOptionalKeyword(en.value())))115      return en.index();116  }117  return -1;118}119 120namespace {121template <typename Ty> struct EnumTraits {};122 123#define REGISTER_ENUM_TYPE(Ty)                                                 \124  template <> struct EnumTraits<cir::Ty> {                                     \125    static llvm::StringRef stringify(cir::Ty value) {                          \126      return stringify##Ty(value);                                             \127    }                                                                          \128    static unsigned getMaxEnumVal() { return cir::getMaxEnumValFor##Ty(); }    \129  }130 131REGISTER_ENUM_TYPE(GlobalLinkageKind);132REGISTER_ENUM_TYPE(VisibilityKind);133REGISTER_ENUM_TYPE(SideEffect);134} // namespace135 136/// Parse an enum from the keyword, or default to the provided default value.137/// The return type is the enum type by default, unless overriden with the138/// second template argument.139template <typename EnumTy, typename RetTy = EnumTy>140static RetTy parseOptionalCIRKeyword(AsmParser &parser, EnumTy defaultValue) {141  llvm::SmallVector<llvm::StringRef, 10> names;142  for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i)143    names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));144 145  int index = parseOptionalKeywordAlternative(parser, names);146  if (index == -1)147    return static_cast<RetTy>(defaultValue);148  return static_cast<RetTy>(index);149}150 151/// Parse an enum from the keyword, return failure if the keyword is not found.152template <typename EnumTy, typename RetTy = EnumTy>153static ParseResult parseCIRKeyword(AsmParser &parser, RetTy &result) {154  llvm::SmallVector<llvm::StringRef, 10> names;155  for (unsigned i = 0, e = EnumTraits<EnumTy>::getMaxEnumVal(); i <= e; ++i)156    names.push_back(EnumTraits<EnumTy>::stringify(static_cast<EnumTy>(i)));157 158  int index = parseOptionalKeywordAlternative(parser, names);159  if (index == -1)160    return failure();161  result = static_cast<RetTy>(index);162  return success();163}164 165// Check if a region's termination omission is valid and, if so, creates and166// inserts the omitted terminator into the region.167static LogicalResult ensureRegionTerm(OpAsmParser &parser, Region &region,168                                      SMLoc errLoc) {169  Location eLoc = parser.getEncodedSourceLoc(parser.getCurrentLocation());170  OpBuilder builder(parser.getBuilder().getContext());171 172  // Insert empty block in case the region is empty to ensure the terminator173  // will be inserted174  if (region.empty())175    builder.createBlock(&region);176 177  Block &block = region.back();178  // Region is properly terminated: nothing to do.179  if (!block.empty() && block.back().hasTrait<OpTrait::IsTerminator>())180    return success();181 182  // Check for invalid terminator omissions.183  if (!region.hasOneBlock())184    return parser.emitError(errLoc,185                            "multi-block region must not omit terminator");186 187  // Terminator was omitted correctly: recreate it.188  builder.setInsertionPointToEnd(&block);189  cir::YieldOp::create(builder, eLoc);190  return success();191}192 193// True if the region's terminator should be omitted.194static bool omitRegionTerm(mlir::Region &r) {195  const auto singleNonEmptyBlock = r.hasOneBlock() && !r.back().empty();196  const auto yieldsNothing = [&r]() {197    auto y = dyn_cast<cir::YieldOp>(r.back().getTerminator());198    return y && y.getArgs().empty();199  };200  return singleNonEmptyBlock && yieldsNothing();201}202 203void printVisibilityAttr(OpAsmPrinter &printer,204                         cir::VisibilityAttr &visibility) {205  switch (visibility.getValue()) {206  case cir::VisibilityKind::Hidden:207    printer << "hidden";208    break;209  case cir::VisibilityKind::Protected:210    printer << "protected";211    break;212  case cir::VisibilityKind::Default:213    break;214  }215}216 217void parseVisibilityAttr(OpAsmParser &parser, cir::VisibilityAttr &visibility) {218  cir::VisibilityKind visibilityKind =219      parseOptionalCIRKeyword(parser, cir::VisibilityKind::Default);220  visibility = cir::VisibilityAttr::get(parser.getContext(), visibilityKind);221}222 223//===----------------------------------------------------------------------===//224// CIR Custom Parsers/Printers225//===----------------------------------------------------------------------===//226 227static mlir::ParseResult parseOmittedTerminatorRegion(mlir::OpAsmParser &parser,228                                                      mlir::Region &region) {229  auto regionLoc = parser.getCurrentLocation();230  if (parser.parseRegion(region))231    return failure();232  if (ensureRegionTerm(parser, region, regionLoc).failed())233    return failure();234  return success();235}236 237static void printOmittedTerminatorRegion(mlir::OpAsmPrinter &printer,238                                         cir::ScopeOp &op,239                                         mlir::Region &region) {240  printer.printRegion(region,241                      /*printEntryBlockArgs=*/false,242                      /*printBlockTerminators=*/!omitRegionTerm(region));243}244 245//===----------------------------------------------------------------------===//246// AllocaOp247//===----------------------------------------------------------------------===//248 249void cir::AllocaOp::build(mlir::OpBuilder &odsBuilder,250                          mlir::OperationState &odsState, mlir::Type addr,251                          mlir::Type allocaType, llvm::StringRef name,252                          mlir::IntegerAttr alignment) {253  odsState.addAttribute(getAllocaTypeAttrName(odsState.name),254                        mlir::TypeAttr::get(allocaType));255  odsState.addAttribute(getNameAttrName(odsState.name),256                        odsBuilder.getStringAttr(name));257  if (alignment) {258    odsState.addAttribute(getAlignmentAttrName(odsState.name), alignment);259  }260  odsState.addTypes(addr);261}262 263//===----------------------------------------------------------------------===//264// BreakOp265//===----------------------------------------------------------------------===//266 267LogicalResult cir::BreakOp::verify() {268  assert(!cir::MissingFeatures::switchOp());269  if (!getOperation()->getParentOfType<LoopOpInterface>() &&270      !getOperation()->getParentOfType<SwitchOp>())271    return emitOpError("must be within a loop");272  return success();273}274 275//===----------------------------------------------------------------------===//276// ConditionOp277//===----------------------------------------------------------------------===//278 279//===----------------------------------280// BranchOpTerminatorInterface Methods281//===----------------------------------282 283void cir::ConditionOp::getSuccessorRegions(284    ArrayRef<Attribute> operands, SmallVectorImpl<RegionSuccessor> &regions) {285  // TODO(cir): The condition value may be folded to a constant, narrowing286  // down its list of possible successors.287 288  // Parent is a loop: condition may branch to the body or to the parent op.289  if (auto loopOp = dyn_cast<LoopOpInterface>(getOperation()->getParentOp())) {290    regions.emplace_back(&loopOp.getBody(), loopOp.getBody().getArguments());291    regions.emplace_back(getOperation(), loopOp->getResults());292  }293 294  // Parent is an await: condition may branch to resume or suspend regions.295  auto await = cast<AwaitOp>(getOperation()->getParentOp());296  regions.emplace_back(&await.getResume(), await.getResume().getArguments());297  regions.emplace_back(&await.getSuspend(), await.getSuspend().getArguments());298}299 300MutableOperandRange301cir::ConditionOp::getMutableSuccessorOperands(RegionSuccessor point) {302  // No values are yielded to the successor region.303  return MutableOperandRange(getOperation(), 0, 0);304}305 306LogicalResult cir::ConditionOp::verify() {307  if (!isa<LoopOpInterface, AwaitOp>(getOperation()->getParentOp()))308    return emitOpError("condition must be within a conditional region");309  return success();310}311 312//===----------------------------------------------------------------------===//313// ConstantOp314//===----------------------------------------------------------------------===//315 316static LogicalResult checkConstantTypes(mlir::Operation *op, mlir::Type opType,317                                        mlir::Attribute attrType) {318  if (isa<cir::ConstPtrAttr>(attrType)) {319    if (!mlir::isa<cir::PointerType>(opType))320      return op->emitOpError(321          "pointer constant initializing a non-pointer type");322    return success();323  }324 325  if (isa<cir::ZeroAttr>(attrType)) {326    if (isa<cir::RecordType, cir::ArrayType, cir::VectorType, cir::ComplexType>(327            opType))328      return success();329    return op->emitOpError(330        "zero expects struct, array, vector, or complex type");331  }332 333  if (mlir::isa<cir::UndefAttr>(attrType)) {334    if (!mlir::isa<cir::VoidType>(opType))335      return success();336    return op->emitOpError("undef expects non-void type");337  }338 339  if (mlir::isa<cir::BoolAttr>(attrType)) {340    if (!mlir::isa<cir::BoolType>(opType))341      return op->emitOpError("result type (")342             << opType << ") must be '!cir.bool' for '" << attrType << "'";343    return success();344  }345 346  if (mlir::isa<cir::IntAttr, cir::FPAttr>(attrType)) {347    auto at = cast<TypedAttr>(attrType);348    if (at.getType() != opType) {349      return op->emitOpError("result type (")350             << opType << ") does not match value type (" << at.getType()351             << ")";352    }353    return success();354  }355 356  if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,357                cir::ConstComplexAttr, cir::ConstRecordAttr,358                cir::GlobalViewAttr, cir::PoisonAttr, cir::TypeInfoAttr,359                cir::VTableAttr>(attrType))360    return success();361 362  assert(isa<TypedAttr>(attrType) && "What else could we be looking at here?");363  return op->emitOpError("global with type ")364         << cast<TypedAttr>(attrType).getType() << " not yet supported";365}366 367LogicalResult cir::ConstantOp::verify() {368  // ODS already generates checks to make sure the result type is valid. We just369  // need to additionally check that the value's attribute type is consistent370  // with the result type.371  return checkConstantTypes(getOperation(), getType(), getValue());372}373 374OpFoldResult cir::ConstantOp::fold(FoldAdaptor /*adaptor*/) {375  return getValue();376}377 378//===----------------------------------------------------------------------===//379// ContinueOp380//===----------------------------------------------------------------------===//381 382LogicalResult cir::ContinueOp::verify() {383  if (!getOperation()->getParentOfType<LoopOpInterface>())384    return emitOpError("must be within a loop");385  return success();386}387 388//===----------------------------------------------------------------------===//389// CastOp390//===----------------------------------------------------------------------===//391 392LogicalResult cir::CastOp::verify() {393  mlir::Type resType = getType();394  mlir::Type srcType = getSrc().getType();395 396  // Verify address space casts for pointer types. given that397  // casts for within a different address space are illegal.398  auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);399  auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);400  if (srcPtrTy && resPtrTy && (getKind() != cir::CastKind::address_space))401    if (srcPtrTy.getAddrSpace() != resPtrTy.getAddrSpace()) {402      return emitOpError() << "result type address space does not match the "403                              "address space of the operand";404    }405 406  if (mlir::isa<cir::VectorType>(srcType) &&407      mlir::isa<cir::VectorType>(resType)) {408    // Use the element type of the vector to verify the cast kind. (Except for409    // bitcast, see below.)410    srcType = mlir::dyn_cast<cir::VectorType>(srcType).getElementType();411    resType = mlir::dyn_cast<cir::VectorType>(resType).getElementType();412  }413 414  switch (getKind()) {415  case cir::CastKind::int_to_bool: {416    if (!mlir::isa<cir::BoolType>(resType))417      return emitOpError() << "requires !cir.bool type for result";418    if (!mlir::isa<cir::IntType>(srcType))419      return emitOpError() << "requires !cir.int type for source";420    return success();421  }422  case cir::CastKind::ptr_to_bool: {423    if (!mlir::isa<cir::BoolType>(resType))424      return emitOpError() << "requires !cir.bool type for result";425    if (!mlir::isa<cir::PointerType>(srcType))426      return emitOpError() << "requires !cir.ptr type for source";427    return success();428  }429  case cir::CastKind::integral: {430    if (!mlir::isa<cir::IntType>(resType))431      return emitOpError() << "requires !cir.int type for result";432    if (!mlir::isa<cir::IntType>(srcType))433      return emitOpError() << "requires !cir.int type for source";434    return success();435  }436  case cir::CastKind::array_to_ptrdecay: {437    const auto arrayPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);438    const auto flatPtrTy = mlir::dyn_cast<cir::PointerType>(resType);439    if (!arrayPtrTy || !flatPtrTy)440      return emitOpError() << "requires !cir.ptr type for source and result";441 442    // TODO(CIR): Make sure the AddrSpace of both types are equals443    return success();444  }445  case cir::CastKind::bitcast: {446    // Handle the pointer types first.447    auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);448    auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);449 450    if (srcPtrTy && resPtrTy) {451      return success();452    }453 454    return success();455  }456  case cir::CastKind::floating: {457    if (!mlir::isa<cir::FPTypeInterface>(srcType) ||458        !mlir::isa<cir::FPTypeInterface>(resType))459      return emitOpError() << "requires !cir.float type for source and result";460    return success();461  }462  case cir::CastKind::float_to_int: {463    if (!mlir::isa<cir::FPTypeInterface>(srcType))464      return emitOpError() << "requires !cir.float type for source";465    if (!mlir::dyn_cast<cir::IntType>(resType))466      return emitOpError() << "requires !cir.int type for result";467    return success();468  }469  case cir::CastKind::int_to_ptr: {470    if (!mlir::dyn_cast<cir::IntType>(srcType))471      return emitOpError() << "requires !cir.int type for source";472    if (!mlir::dyn_cast<cir::PointerType>(resType))473      return emitOpError() << "requires !cir.ptr type for result";474    return success();475  }476  case cir::CastKind::ptr_to_int: {477    if (!mlir::dyn_cast<cir::PointerType>(srcType))478      return emitOpError() << "requires !cir.ptr type for source";479    if (!mlir::dyn_cast<cir::IntType>(resType))480      return emitOpError() << "requires !cir.int type for result";481    return success();482  }483  case cir::CastKind::float_to_bool: {484    if (!mlir::isa<cir::FPTypeInterface>(srcType))485      return emitOpError() << "requires !cir.float type for source";486    if (!mlir::isa<cir::BoolType>(resType))487      return emitOpError() << "requires !cir.bool type for result";488    return success();489  }490  case cir::CastKind::bool_to_int: {491    if (!mlir::isa<cir::BoolType>(srcType))492      return emitOpError() << "requires !cir.bool type for source";493    if (!mlir::isa<cir::IntType>(resType))494      return emitOpError() << "requires !cir.int type for result";495    return success();496  }497  case cir::CastKind::int_to_float: {498    if (!mlir::isa<cir::IntType>(srcType))499      return emitOpError() << "requires !cir.int type for source";500    if (!mlir::isa<cir::FPTypeInterface>(resType))501      return emitOpError() << "requires !cir.float type for result";502    return success();503  }504  case cir::CastKind::bool_to_float: {505    if (!mlir::isa<cir::BoolType>(srcType))506      return emitOpError() << "requires !cir.bool type for source";507    if (!mlir::isa<cir::FPTypeInterface>(resType))508      return emitOpError() << "requires !cir.float type for result";509    return success();510  }511  case cir::CastKind::address_space: {512    auto srcPtrTy = mlir::dyn_cast<cir::PointerType>(srcType);513    auto resPtrTy = mlir::dyn_cast<cir::PointerType>(resType);514    if (!srcPtrTy || !resPtrTy)515      return emitOpError() << "requires !cir.ptr type for source and result";516    if (srcPtrTy.getPointee() != resPtrTy.getPointee())517      return emitOpError() << "requires two types differ in addrspace only";518    return success();519  }520  case cir::CastKind::float_to_complex: {521    if (!mlir::isa<cir::FPTypeInterface>(srcType))522      return emitOpError() << "requires !cir.float type for source";523    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);524    if (!resComplexTy)525      return emitOpError() << "requires !cir.complex type for result";526    if (srcType != resComplexTy.getElementType())527      return emitOpError() << "requires source type match result element type";528    return success();529  }530  case cir::CastKind::int_to_complex: {531    if (!mlir::isa<cir::IntType>(srcType))532      return emitOpError() << "requires !cir.int type for source";533    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);534    if (!resComplexTy)535      return emitOpError() << "requires !cir.complex type for result";536    if (srcType != resComplexTy.getElementType())537      return emitOpError() << "requires source type match result element type";538    return success();539  }540  case cir::CastKind::float_complex_to_real: {541    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);542    if (!srcComplexTy)543      return emitOpError() << "requires !cir.complex type for source";544    if (!mlir::isa<cir::FPTypeInterface>(resType))545      return emitOpError() << "requires !cir.float type for result";546    if (srcComplexTy.getElementType() != resType)547      return emitOpError() << "requires source element type match result type";548    return success();549  }550  case cir::CastKind::int_complex_to_real: {551    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);552    if (!srcComplexTy)553      return emitOpError() << "requires !cir.complex type for source";554    if (!mlir::isa<cir::IntType>(resType))555      return emitOpError() << "requires !cir.int type for result";556    if (srcComplexTy.getElementType() != resType)557      return emitOpError() << "requires source element type match result type";558    return success();559  }560  case cir::CastKind::float_complex_to_bool: {561    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);562    if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex())563      return emitOpError()564             << "requires floating point !cir.complex type for source";565    if (!mlir::isa<cir::BoolType>(resType))566      return emitOpError() << "requires !cir.bool type for result";567    return success();568  }569  case cir::CastKind::int_complex_to_bool: {570    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);571    if (!srcComplexTy || !srcComplexTy.isIntegerComplex())572      return emitOpError()573             << "requires floating point !cir.complex type for source";574    if (!mlir::isa<cir::BoolType>(resType))575      return emitOpError() << "requires !cir.bool type for result";576    return success();577  }578  case cir::CastKind::float_complex: {579    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);580    if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex())581      return emitOpError()582             << "requires floating point !cir.complex type for source";583    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);584    if (!resComplexTy || !resComplexTy.isFloatingPointComplex())585      return emitOpError()586             << "requires floating point !cir.complex type for result";587    return success();588  }589  case cir::CastKind::float_complex_to_int_complex: {590    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);591    if (!srcComplexTy || !srcComplexTy.isFloatingPointComplex())592      return emitOpError()593             << "requires floating point !cir.complex type for source";594    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);595    if (!resComplexTy || !resComplexTy.isIntegerComplex())596      return emitOpError() << "requires integer !cir.complex type for result";597    return success();598  }599  case cir::CastKind::int_complex: {600    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);601    if (!srcComplexTy || !srcComplexTy.isIntegerComplex())602      return emitOpError() << "requires integer !cir.complex type for source";603    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);604    if (!resComplexTy || !resComplexTy.isIntegerComplex())605      return emitOpError() << "requires integer !cir.complex type for result";606    return success();607  }608  case cir::CastKind::int_complex_to_float_complex: {609    auto srcComplexTy = mlir::dyn_cast<cir::ComplexType>(srcType);610    if (!srcComplexTy || !srcComplexTy.isIntegerComplex())611      return emitOpError() << "requires integer !cir.complex type for source";612    auto resComplexTy = mlir::dyn_cast<cir::ComplexType>(resType);613    if (!resComplexTy || !resComplexTy.isFloatingPointComplex())614      return emitOpError()615             << "requires floating point !cir.complex type for result";616    return success();617  }618  default:619    llvm_unreachable("Unknown CastOp kind?");620  }621}622 623static bool isIntOrBoolCast(cir::CastOp op) {624  auto kind = op.getKind();625  return kind == cir::CastKind::bool_to_int ||626         kind == cir::CastKind::int_to_bool || kind == cir::CastKind::integral;627}628 629static Value tryFoldCastChain(cir::CastOp op) {630  cir::CastOp head = op, tail = op;631 632  while (op) {633    if (!isIntOrBoolCast(op))634      break;635    head = op;636    op = head.getSrc().getDefiningOp<cir::CastOp>();637  }638 639  if (head == tail)640    return {};641 642  // if bool_to_int -> ...  -> int_to_bool: take the bool643  // as we had it was before all casts644  if (head.getKind() == cir::CastKind::bool_to_int &&645      tail.getKind() == cir::CastKind::int_to_bool)646    return head.getSrc();647 648  // if int_to_bool -> ...  -> int_to_bool: take the result649  // of the first one, as no other casts (and ext casts as well)650  // don't change the first result651  if (head.getKind() == cir::CastKind::int_to_bool &&652      tail.getKind() == cir::CastKind::int_to_bool)653    return head.getResult();654 655  return {};656}657 658OpFoldResult cir::CastOp::fold(FoldAdaptor adaptor) {659  if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getSrc())) {660    // Propagate poison value661    return cir::PoisonAttr::get(getContext(), getType());662  }663 664  if (getSrc().getType() == getType()) {665    switch (getKind()) {666    case cir::CastKind::integral: {667      // TODO: for sign differences, it's possible in certain conditions to668      // create a new attribute that's capable of representing the source.669      llvm::SmallVector<mlir::OpFoldResult, 1> foldResults;670      auto foldOrder = getSrc().getDefiningOp()->fold(foldResults);671      if (foldOrder.succeeded() && mlir::isa<mlir::Attribute>(foldResults[0]))672        return mlir::cast<mlir::Attribute>(foldResults[0]);673      return {};674    }675    case cir::CastKind::bitcast:676    case cir::CastKind::address_space:677    case cir::CastKind::float_complex:678    case cir::CastKind::int_complex: {679      return getSrc();680    }681    default:682      return {};683    }684  }685  return tryFoldCastChain(*this);686}687 688//===----------------------------------------------------------------------===//689// CallOp690//===----------------------------------------------------------------------===//691 692mlir::OperandRange cir::CallOp::getArgOperands() {693  if (isIndirect())694    return getArgs().drop_front(1);695  return getArgs();696}697 698mlir::MutableOperandRange cir::CallOp::getArgOperandsMutable() {699  mlir::MutableOperandRange args = getArgsMutable();700  if (isIndirect())701    return args.slice(1, args.size() - 1);702  return args;703}704 705mlir::Value cir::CallOp::getIndirectCall() {706  assert(isIndirect());707  return getOperand(0);708}709 710/// Return the operand at index 'i'.711Value cir::CallOp::getArgOperand(unsigned i) {712  if (isIndirect())713    ++i;714  return getOperand(i);715}716 717/// Return the number of operands.718unsigned cir::CallOp::getNumArgOperands() {719  if (isIndirect())720    return this->getOperation()->getNumOperands() - 1;721  return this->getOperation()->getNumOperands();722}723 724static mlir::ParseResult725parseTryCallDestinations(mlir::OpAsmParser &parser,726                         mlir::OperationState &result) {727  mlir::Block *normalDestSuccessor;728  if (parser.parseSuccessor(normalDestSuccessor))729    return mlir::failure();730 731  if (parser.parseComma())732    return mlir::failure();733 734  mlir::Block *unwindDestSuccessor;735  if (parser.parseSuccessor(unwindDestSuccessor))736    return mlir::failure();737 738  result.addSuccessors(normalDestSuccessor);739  result.addSuccessors(unwindDestSuccessor);740  return mlir::success();741}742 743static mlir::ParseResult parseCallCommon(mlir::OpAsmParser &parser,744                                         mlir::OperationState &result,745                                         bool hasDestinationBlocks = false) {746  llvm::SmallVector<mlir::OpAsmParser::UnresolvedOperand, 4> ops;747  llvm::SMLoc opsLoc;748  mlir::FlatSymbolRefAttr calleeAttr;749  llvm::ArrayRef<mlir::Type> allResultTypes;750 751  // If we cannot parse a string callee, it means this is an indirect call.752  if (!parser753           .parseOptionalAttribute(calleeAttr, CIRDialect::getCalleeAttrName(),754                                   result.attributes)755           .has_value()) {756    OpAsmParser::UnresolvedOperand indirectVal;757    // Do not resolve right now, since we need to figure out the type758    if (parser.parseOperand(indirectVal).failed())759      return failure();760    ops.push_back(indirectVal);761  }762 763  if (parser.parseLParen())764    return mlir::failure();765 766  opsLoc = parser.getCurrentLocation();767  if (parser.parseOperandList(ops))768    return mlir::failure();769  if (parser.parseRParen())770    return mlir::failure();771 772  if (hasDestinationBlocks &&773      parseTryCallDestinations(parser, result).failed()) {774    return ::mlir::failure();775  }776 777  if (parser.parseOptionalKeyword("nothrow").succeeded())778    result.addAttribute(CIRDialect::getNoThrowAttrName(),779                        mlir::UnitAttr::get(parser.getContext()));780 781  if (parser.parseOptionalKeyword("side_effect").succeeded()) {782    if (parser.parseLParen().failed())783      return failure();784    cir::SideEffect sideEffect;785    if (parseCIRKeyword<cir::SideEffect>(parser, sideEffect).failed())786      return failure();787    if (parser.parseRParen().failed())788      return failure();789    auto attr = cir::SideEffectAttr::get(parser.getContext(), sideEffect);790    result.addAttribute(CIRDialect::getSideEffectAttrName(), attr);791  }792 793  if (parser.parseOptionalAttrDict(result.attributes))794    return ::mlir::failure();795 796  if (parser.parseColon())797    return ::mlir::failure();798 799  mlir::FunctionType opsFnTy;800  if (parser.parseType(opsFnTy))801    return mlir::failure();802 803  allResultTypes = opsFnTy.getResults();804  result.addTypes(allResultTypes);805 806  if (parser.resolveOperands(ops, opsFnTy.getInputs(), opsLoc, result.operands))807    return mlir::failure();808 809  return mlir::success();810}811 812static void printCallCommon(mlir::Operation *op,813                            mlir::FlatSymbolRefAttr calleeSym,814                            mlir::Value indirectCallee,815                            mlir::OpAsmPrinter &printer, bool isNothrow,816                            cir::SideEffect sideEffect,817                            mlir::Block *normalDest = nullptr,818                            mlir::Block *unwindDest = nullptr) {819  printer << ' ';820 821  auto callLikeOp = mlir::cast<cir::CIRCallOpInterface>(op);822  auto ops = callLikeOp.getArgOperands();823 824  if (calleeSym) {825    // Direct calls826    printer.printAttributeWithoutType(calleeSym);827  } else {828    // Indirect calls829    assert(indirectCallee);830    printer << indirectCallee;831  }832 833  printer << "(" << ops << ")";834 835  if (normalDest) {836    assert(unwindDest && "expected two successors");837    auto tryCall = cast<cir::TryCallOp>(op);838    printer << ' ' << tryCall.getNormalDest();839    printer << ",";840    printer << ' ';841    printer << tryCall.getUnwindDest();842  }843 844  if (isNothrow)845    printer << " nothrow";846 847  if (sideEffect != cir::SideEffect::All) {848    printer << " side_effect(";849    printer << stringifySideEffect(sideEffect);850    printer << ")";851  }852 853  llvm::SmallVector<::llvm::StringRef> elidedAttrs = {854      CIRDialect::getCalleeAttrName(), CIRDialect::getNoThrowAttrName(),855      CIRDialect::getSideEffectAttrName(),856      CIRDialect::getOperandSegmentSizesAttrName()};857  printer.printOptionalAttrDict(op->getAttrs(), elidedAttrs);858  printer << " : ";859  printer.printFunctionalType(op->getOperands().getTypes(),860                              op->getResultTypes());861}862 863mlir::ParseResult cir::CallOp::parse(mlir::OpAsmParser &parser,864                                     mlir::OperationState &result) {865  return parseCallCommon(parser, result);866}867 868void cir::CallOp::print(mlir::OpAsmPrinter &p) {869  mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;870  cir::SideEffect sideEffect = getSideEffect();871  printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getNothrow(),872                  sideEffect);873}874 875static LogicalResult876verifyCallCommInSymbolUses(mlir::Operation *op,877                           SymbolTableCollection &symbolTable) {878  auto fnAttr =879      op->getAttrOfType<FlatSymbolRefAttr>(CIRDialect::getCalleeAttrName());880  if (!fnAttr) {881    // This is an indirect call, thus we don't have to check the symbol uses.882    return mlir::success();883  }884 885  auto fn = symbolTable.lookupNearestSymbolFrom<cir::FuncOp>(op, fnAttr);886  if (!fn)887    return op->emitOpError() << "'" << fnAttr.getValue()888                             << "' does not reference a valid function";889 890  auto callIf = dyn_cast<cir::CIRCallOpInterface>(op);891  assert(callIf && "expected CIR call interface to be always available");892 893  // Verify that the operand and result types match the callee. Note that894  // argument-checking is disabled for functions without a prototype.895  auto fnType = fn.getFunctionType();896  if (!fn.getNoProto()) {897    unsigned numCallOperands = callIf.getNumArgOperands();898    unsigned numFnOpOperands = fnType.getNumInputs();899 900    if (!fnType.isVarArg() && numCallOperands != numFnOpOperands)901      return op->emitOpError("incorrect number of operands for callee");902    if (fnType.isVarArg() && numCallOperands < numFnOpOperands)903      return op->emitOpError("too few operands for callee");904 905    for (unsigned i = 0, e = numFnOpOperands; i != e; ++i)906      if (callIf.getArgOperand(i).getType() != fnType.getInput(i))907        return op->emitOpError("operand type mismatch: expected operand type ")908               << fnType.getInput(i) << ", but provided "909               << op->getOperand(i).getType() << " for operand number " << i;910  }911 912  assert(!cir::MissingFeatures::opCallCallConv());913 914  // Void function must not return any results.915  if (fnType.hasVoidReturn() && op->getNumResults() != 0)916    return op->emitOpError("callee returns void but call has results");917 918  // Non-void function calls must return exactly one result.919  if (!fnType.hasVoidReturn() && op->getNumResults() != 1)920    return op->emitOpError("incorrect number of results for callee");921 922  // Parent function and return value types must match.923  if (!fnType.hasVoidReturn() &&924      op->getResultTypes().front() != fnType.getReturnType()) {925    return op->emitOpError("result type mismatch: expected ")926           << fnType.getReturnType() << ", but provided "927           << op->getResult(0).getType();928  }929 930  return mlir::success();931}932 933LogicalResult934cir::CallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {935  return verifyCallCommInSymbolUses(*this, symbolTable);936}937 938//===----------------------------------------------------------------------===//939// TryCallOp940//===----------------------------------------------------------------------===//941 942mlir::OperandRange cir::TryCallOp::getArgOperands() {943  if (isIndirect())944    return getArgs().drop_front(1);945  return getArgs();946}947 948mlir::MutableOperandRange cir::TryCallOp::getArgOperandsMutable() {949  mlir::MutableOperandRange args = getArgsMutable();950  if (isIndirect())951    return args.slice(1, args.size() - 1);952  return args;953}954 955mlir::Value cir::TryCallOp::getIndirectCall() {956  assert(isIndirect());957  return getOperand(0);958}959 960/// Return the operand at index 'i'.961Value cir::TryCallOp::getArgOperand(unsigned i) {962  if (isIndirect())963    ++i;964  return getOperand(i);965}966 967/// Return the number of operands.968unsigned cir::TryCallOp::getNumArgOperands() {969  if (isIndirect())970    return this->getOperation()->getNumOperands() - 1;971  return this->getOperation()->getNumOperands();972}973 974LogicalResult975cir::TryCallOp::verifySymbolUses(SymbolTableCollection &symbolTable) {976  return verifyCallCommInSymbolUses(*this, symbolTable);977}978 979mlir::ParseResult cir::TryCallOp::parse(mlir::OpAsmParser &parser,980                                        mlir::OperationState &result) {981  return parseCallCommon(parser, result, /*hasDestinationBlocks=*/true);982}983 984void cir::TryCallOp::print(::mlir::OpAsmPrinter &p) {985  mlir::Value indirectCallee = isIndirect() ? getIndirectCall() : nullptr;986  cir::SideEffect sideEffect = getSideEffect();987  printCallCommon(*this, getCalleeAttr(), indirectCallee, p, getNothrow(),988                  sideEffect, getNormalDest(), getUnwindDest());989}990 991//===----------------------------------------------------------------------===//992// ReturnOp993//===----------------------------------------------------------------------===//994 995static mlir::LogicalResult checkReturnAndFunction(cir::ReturnOp op,996                                                  cir::FuncOp function) {997  // ReturnOps currently only have a single optional operand.998  if (op.getNumOperands() > 1)999    return op.emitOpError() << "expects at most 1 return operand";1000 1001  // Ensure returned type matches the function signature.1002  auto expectedTy = function.getFunctionType().getReturnType();1003  auto actualTy =1004      (op.getNumOperands() == 0 ? cir::VoidType::get(op.getContext())1005                                : op.getOperand(0).getType());1006  if (actualTy != expectedTy)1007    return op.emitOpError() << "returns " << actualTy1008                            << " but enclosing function returns " << expectedTy;1009 1010  return mlir::success();1011}1012 1013mlir::LogicalResult cir::ReturnOp::verify() {1014  // Returns can be present in multiple different scopes, get the1015  // wrapping function and start from there.1016  auto *fnOp = getOperation()->getParentOp();1017  while (!isa<cir::FuncOp>(fnOp))1018    fnOp = fnOp->getParentOp();1019 1020  // Make sure return types match function return type.1021  if (checkReturnAndFunction(*this, cast<cir::FuncOp>(fnOp)).failed())1022    return failure();1023 1024  return success();1025}1026 1027//===----------------------------------------------------------------------===//1028// IfOp1029//===----------------------------------------------------------------------===//1030 1031ParseResult cir::IfOp::parse(OpAsmParser &parser, OperationState &result) {1032  // create the regions for 'then'.1033  result.regions.reserve(2);1034  Region *thenRegion = result.addRegion();1035  Region *elseRegion = result.addRegion();1036 1037  mlir::Builder &builder = parser.getBuilder();1038  OpAsmParser::UnresolvedOperand cond;1039  Type boolType = cir::BoolType::get(builder.getContext());1040 1041  if (parser.parseOperand(cond) ||1042      parser.resolveOperand(cond, boolType, result.operands))1043    return failure();1044 1045  // Parse 'then' region.1046  mlir::SMLoc parseThenLoc = parser.getCurrentLocation();1047  if (parser.parseRegion(*thenRegion, /*arguments=*/{}, /*argTypes=*/{}))1048    return failure();1049 1050  if (ensureRegionTerm(parser, *thenRegion, parseThenLoc).failed())1051    return failure();1052 1053  // If we find an 'else' keyword, parse the 'else' region.1054  if (!parser.parseOptionalKeyword("else")) {1055    mlir::SMLoc parseElseLoc = parser.getCurrentLocation();1056    if (parser.parseRegion(*elseRegion, /*arguments=*/{}, /*argTypes=*/{}))1057      return failure();1058    if (ensureRegionTerm(parser, *elseRegion, parseElseLoc).failed())1059      return failure();1060  }1061 1062  // Parse the optional attribute list.1063  if (parser.parseOptionalAttrDict(result.attributes))1064    return failure();1065  return success();1066}1067 1068void cir::IfOp::print(OpAsmPrinter &p) {1069  p << " " << getCondition() << " ";1070  mlir::Region &thenRegion = this->getThenRegion();1071  p.printRegion(thenRegion,1072                /*printEntryBlockArgs=*/false,1073                /*printBlockTerminators=*/!omitRegionTerm(thenRegion));1074 1075  // Print the 'else' regions if it exists and has a block.1076  mlir::Region &elseRegion = this->getElseRegion();1077  if (!elseRegion.empty()) {1078    p << " else ";1079    p.printRegion(elseRegion,1080                  /*printEntryBlockArgs=*/false,1081                  /*printBlockTerminators=*/!omitRegionTerm(elseRegion));1082  }1083 1084  p.printOptionalAttrDict(getOperation()->getAttrs());1085}1086 1087/// Default callback for IfOp builders.1088void cir::buildTerminatedBody(OpBuilder &builder, Location loc) {1089  // add cir.yield to end of the block1090  cir::YieldOp::create(builder, loc);1091}1092 1093/// Given the region at `index`, or the parent operation if `index` is None,1094/// return the successor regions. These are the regions that may be selected1095/// during the flow of control. `operands` is a set of optional attributes that1096/// correspond to a constant value for each operand, or null if that operand is1097/// not a constant.1098void cir::IfOp::getSuccessorRegions(mlir::RegionBranchPoint point,1099                                    SmallVectorImpl<RegionSuccessor> &regions) {1100  // The `then` and the `else` region branch back to the parent operation.1101  if (!point.isParent()) {1102    regions.push_back(1103        RegionSuccessor(getOperation(), getOperation()->getResults()));1104    return;1105  }1106 1107  // Don't consider the else region if it is empty.1108  Region *elseRegion = &this->getElseRegion();1109  if (elseRegion->empty())1110    elseRegion = nullptr;1111 1112  // If the condition isn't constant, both regions may be executed.1113  regions.push_back(RegionSuccessor(&getThenRegion()));1114  // If the else region does not exist, it is not a viable successor.1115  if (elseRegion)1116    regions.push_back(RegionSuccessor(elseRegion));1117 1118  return;1119}1120 1121void cir::IfOp::build(OpBuilder &builder, OperationState &result, Value cond,1122                      bool withElseRegion, BuilderCallbackRef thenBuilder,1123                      BuilderCallbackRef elseBuilder) {1124  assert(thenBuilder && "the builder callback for 'then' must be present");1125  result.addOperands(cond);1126 1127  OpBuilder::InsertionGuard guard(builder);1128  Region *thenRegion = result.addRegion();1129  builder.createBlock(thenRegion);1130  thenBuilder(builder, result.location);1131 1132  Region *elseRegion = result.addRegion();1133  if (!withElseRegion)1134    return;1135 1136  builder.createBlock(elseRegion);1137  elseBuilder(builder, result.location);1138}1139 1140//===----------------------------------------------------------------------===//1141// ScopeOp1142//===----------------------------------------------------------------------===//1143 1144/// Given the region at `index`, or the parent operation if `index` is None,1145/// return the successor regions. These are the regions that may be selected1146/// during the flow of control. `operands` is a set of optional attributes1147/// that correspond to a constant value for each operand, or null if that1148/// operand is not a constant.1149void cir::ScopeOp::getSuccessorRegions(1150    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {1151  // The only region always branch back to the parent operation.1152  if (!point.isParent()) {1153    regions.push_back(RegionSuccessor(getOperation(), getODSResults(0)));1154    return;1155  }1156 1157  // If the condition isn't constant, both regions may be executed.1158  regions.push_back(RegionSuccessor(&getScopeRegion()));1159}1160 1161void cir::ScopeOp::build(1162    OpBuilder &builder, OperationState &result,1163    function_ref<void(OpBuilder &, Type &, Location)> scopeBuilder) {1164  assert(scopeBuilder && "the builder callback for 'then' must be present");1165 1166  OpBuilder::InsertionGuard guard(builder);1167  Region *scopeRegion = result.addRegion();1168  builder.createBlock(scopeRegion);1169  assert(!cir::MissingFeatures::opScopeCleanupRegion());1170 1171  mlir::Type yieldTy;1172  scopeBuilder(builder, yieldTy, result.location);1173 1174  if (yieldTy)1175    result.addTypes(TypeRange{yieldTy});1176}1177 1178void cir::ScopeOp::build(1179    OpBuilder &builder, OperationState &result,1180    function_ref<void(OpBuilder &, Location)> scopeBuilder) {1181  assert(scopeBuilder && "the builder callback for 'then' must be present");1182  OpBuilder::InsertionGuard guard(builder);1183  Region *scopeRegion = result.addRegion();1184  builder.createBlock(scopeRegion);1185  assert(!cir::MissingFeatures::opScopeCleanupRegion());1186  scopeBuilder(builder, result.location);1187}1188 1189LogicalResult cir::ScopeOp::verify() {1190  if (getRegion().empty()) {1191    return emitOpError() << "cir.scope must not be empty since it should "1192                            "include at least an implicit cir.yield ";1193  }1194 1195  mlir::Block &lastBlock = getRegion().back();1196  if (lastBlock.empty() || !lastBlock.mightHaveTerminator() ||1197      !lastBlock.getTerminator()->hasTrait<OpTrait::IsTerminator>())1198    return emitOpError() << "last block of cir.scope must be terminated";1199  return success();1200}1201 1202//===----------------------------------------------------------------------===//1203// BrOp1204//===----------------------------------------------------------------------===//1205 1206mlir::SuccessorOperands cir::BrOp::getSuccessorOperands(unsigned index) {1207  assert(index == 0 && "invalid successor index");1208  return mlir::SuccessorOperands(getDestOperandsMutable());1209}1210 1211Block *cir::BrOp::getSuccessorForOperands(ArrayRef<Attribute>) {1212  return getDest();1213}1214 1215//===----------------------------------------------------------------------===//1216// BrCondOp1217//===----------------------------------------------------------------------===//1218 1219mlir::SuccessorOperands cir::BrCondOp::getSuccessorOperands(unsigned index) {1220  assert(index < getNumSuccessors() && "invalid successor index");1221  return SuccessorOperands(index == 0 ? getDestOperandsTrueMutable()1222                                      : getDestOperandsFalseMutable());1223}1224 1225Block *cir::BrCondOp::getSuccessorForOperands(ArrayRef<Attribute> operands) {1226  if (IntegerAttr condAttr = dyn_cast_if_present<IntegerAttr>(operands.front()))1227    return condAttr.getValue().isOne() ? getDestTrue() : getDestFalse();1228  return nullptr;1229}1230 1231//===----------------------------------------------------------------------===//1232// CaseOp1233//===----------------------------------------------------------------------===//1234 1235void cir::CaseOp::getSuccessorRegions(1236    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {1237  if (!point.isParent()) {1238    regions.push_back(1239        RegionSuccessor(getOperation(), getOperation()->getResults()));1240    return;1241  }1242  regions.push_back(RegionSuccessor(&getCaseRegion()));1243}1244 1245void cir::CaseOp::build(OpBuilder &builder, OperationState &result,1246                        ArrayAttr value, CaseOpKind kind,1247                        OpBuilder::InsertPoint &insertPoint) {1248  OpBuilder::InsertionGuard guardSwitch(builder);1249  result.addAttribute("value", value);1250  result.getOrAddProperties<Properties>().kind =1251      cir::CaseOpKindAttr::get(builder.getContext(), kind);1252  Region *caseRegion = result.addRegion();1253  builder.createBlock(caseRegion);1254 1255  insertPoint = builder.saveInsertionPoint();1256}1257 1258//===----------------------------------------------------------------------===//1259// SwitchOp1260//===----------------------------------------------------------------------===//1261 1262static ParseResult parseSwitchOp(OpAsmParser &parser, mlir::Region &regions,1263                                 mlir::OpAsmParser::UnresolvedOperand &cond,1264                                 mlir::Type &condType) {1265  cir::IntType intCondType;1266 1267  if (parser.parseLParen())1268    return mlir::failure();1269 1270  if (parser.parseOperand(cond))1271    return mlir::failure();1272  if (parser.parseColon())1273    return mlir::failure();1274  if (parser.parseCustomTypeWithFallback(intCondType))1275    return mlir::failure();1276  condType = intCondType;1277 1278  if (parser.parseRParen())1279    return mlir::failure();1280  if (parser.parseRegion(regions, /*arguments=*/{}, /*argTypes=*/{}))1281    return failure();1282 1283  return mlir::success();1284}1285 1286static void printSwitchOp(OpAsmPrinter &p, cir::SwitchOp op,1287                          mlir::Region &bodyRegion, mlir::Value condition,1288                          mlir::Type condType) {1289  p << "(";1290  p << condition;1291  p << " : ";1292  p.printStrippedAttrOrType(condType);1293  p << ")";1294 1295  p << ' ';1296  p.printRegion(bodyRegion, /*printEntryBlockArgs=*/false,1297                /*printBlockTerminators=*/true);1298}1299 1300void cir::SwitchOp::getSuccessorRegions(1301    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &region) {1302  if (!point.isParent()) {1303    region.push_back(1304        RegionSuccessor(getOperation(), getOperation()->getResults()));1305    return;1306  }1307 1308  region.push_back(RegionSuccessor(&getBody()));1309}1310 1311void cir::SwitchOp::build(OpBuilder &builder, OperationState &result,1312                          Value cond, BuilderOpStateCallbackRef switchBuilder) {1313  assert(switchBuilder && "the builder callback for regions must be present");1314  OpBuilder::InsertionGuard guardSwitch(builder);1315  Region *switchRegion = result.addRegion();1316  builder.createBlock(switchRegion);1317  result.addOperands({cond});1318  switchBuilder(builder, result.location, result);1319}1320 1321void cir::SwitchOp::collectCases(llvm::SmallVectorImpl<CaseOp> &cases) {1322  walk<mlir::WalkOrder::PreOrder>([&](mlir::Operation *op) {1323    // Don't walk in nested switch op.1324    if (isa<cir::SwitchOp>(op) && op != *this)1325      return WalkResult::skip();1326 1327    if (auto caseOp = dyn_cast<cir::CaseOp>(op))1328      cases.push_back(caseOp);1329 1330    return WalkResult::advance();1331  });1332}1333 1334bool cir::SwitchOp::isSimpleForm(llvm::SmallVectorImpl<CaseOp> &cases) {1335  collectCases(cases);1336 1337  if (getBody().empty())1338    return false;1339 1340  if (!isa<YieldOp>(getBody().front().back()))1341    return false;1342 1343  if (!llvm::all_of(getBody().front(),1344                    [](Operation &op) { return isa<CaseOp, YieldOp>(op); }))1345    return false;1346 1347  return llvm::all_of(cases, [this](CaseOp op) {1348    return op->getParentOfType<SwitchOp>() == *this;1349  });1350}1351 1352//===----------------------------------------------------------------------===//1353// SwitchFlatOp1354//===----------------------------------------------------------------------===//1355 1356void cir::SwitchFlatOp::build(OpBuilder &builder, OperationState &result,1357                              Value value, Block *defaultDestination,1358                              ValueRange defaultOperands,1359                              ArrayRef<APInt> caseValues,1360                              BlockRange caseDestinations,1361                              ArrayRef<ValueRange> caseOperands) {1362 1363  std::vector<mlir::Attribute> caseValuesAttrs;1364  for (const APInt &val : caseValues)1365    caseValuesAttrs.push_back(cir::IntAttr::get(value.getType(), val));1366  mlir::ArrayAttr attrs = ArrayAttr::get(builder.getContext(), caseValuesAttrs);1367 1368  build(builder, result, value, defaultOperands, caseOperands, attrs,1369        defaultDestination, caseDestinations);1370}1371 1372/// <cases> ::= `[` (case (`,` case )* )? `]`1373/// <case>  ::= integer `:` bb-id (`(` ssa-use-and-type-list `)`)?1374static ParseResult parseSwitchFlatOpCases(1375    OpAsmParser &parser, Type flagType, mlir::ArrayAttr &caseValues,1376    SmallVectorImpl<Block *> &caseDestinations,1377    SmallVectorImpl<llvm::SmallVector<OpAsmParser::UnresolvedOperand>>1378        &caseOperands,1379    SmallVectorImpl<llvm::SmallVector<Type>> &caseOperandTypes) {1380  if (failed(parser.parseLSquare()))1381    return failure();1382  if (succeeded(parser.parseOptionalRSquare()))1383    return success();1384  llvm::SmallVector<mlir::Attribute> values;1385 1386  auto parseCase = [&]() {1387    int64_t value = 0;1388    if (failed(parser.parseInteger(value)))1389      return failure();1390 1391    values.push_back(cir::IntAttr::get(flagType, value));1392 1393    Block *destination;1394    llvm::SmallVector<OpAsmParser::UnresolvedOperand> operands;1395    llvm::SmallVector<Type> operandTypes;1396    if (parser.parseColon() || parser.parseSuccessor(destination))1397      return failure();1398    if (!parser.parseOptionalLParen()) {1399      if (parser.parseOperandList(operands, OpAsmParser::Delimiter::None,1400                                  /*allowResultNumber=*/false) ||1401          parser.parseColonTypeList(operandTypes) || parser.parseRParen())1402        return failure();1403    }1404    caseDestinations.push_back(destination);1405    caseOperands.emplace_back(operands);1406    caseOperandTypes.emplace_back(operandTypes);1407    return success();1408  };1409  if (failed(parser.parseCommaSeparatedList(parseCase)))1410    return failure();1411 1412  caseValues = ArrayAttr::get(flagType.getContext(), values);1413 1414  return parser.parseRSquare();1415}1416 1417static void printSwitchFlatOpCases(OpAsmPrinter &p, cir::SwitchFlatOp op,1418                                   Type flagType, mlir::ArrayAttr caseValues,1419                                   SuccessorRange caseDestinations,1420                                   OperandRangeRange caseOperands,1421                                   const TypeRangeRange &caseOperandTypes) {1422  p << '[';1423  p.printNewline();1424  if (!caseValues) {1425    p << ']';1426    return;1427  }1428 1429  size_t index = 0;1430  llvm::interleave(1431      llvm::zip(caseValues, caseDestinations),1432      [&](auto i) {1433        p << "  ";1434        mlir::Attribute a = std::get<0>(i);1435        p << mlir::cast<cir::IntAttr>(a).getValue();1436        p << ": ";1437        p.printSuccessorAndUseList(std::get<1>(i), caseOperands[index++]);1438      },1439      [&] {1440        p << ',';1441        p.printNewline();1442      });1443  p.printNewline();1444  p << ']';1445}1446 1447//===----------------------------------------------------------------------===//1448// GlobalOp1449//===----------------------------------------------------------------------===//1450 1451static ParseResult parseConstantValue(OpAsmParser &parser,1452                                      mlir::Attribute &valueAttr) {1453  NamedAttrList attr;1454  return parser.parseAttribute(valueAttr, "value", attr);1455}1456 1457static void printConstant(OpAsmPrinter &p, Attribute value) {1458  p.printAttribute(value);1459}1460 1461mlir::LogicalResult cir::GlobalOp::verify() {1462  // Verify that the initial value, if present, is either a unit attribute or1463  // an attribute CIR supports.1464  if (getInitialValue().has_value()) {1465    if (checkConstantTypes(getOperation(), getSymType(), *getInitialValue())1466            .failed())1467      return failure();1468  }1469 1470  // TODO(CIR): Many other checks for properties that haven't been upstreamed1471  // yet.1472 1473  return success();1474}1475 1476void cir::GlobalOp::build(1477    OpBuilder &odsBuilder, OperationState &odsState, llvm::StringRef sym_name,1478    mlir::Type sym_type, bool isConstant, cir::GlobalLinkageKind linkage,1479    function_ref<void(OpBuilder &, Location)> ctorBuilder,1480    function_ref<void(OpBuilder &, Location)> dtorBuilder) {1481  odsState.addAttribute(getSymNameAttrName(odsState.name),1482                        odsBuilder.getStringAttr(sym_name));1483  odsState.addAttribute(getSymTypeAttrName(odsState.name),1484                        mlir::TypeAttr::get(sym_type));1485  if (isConstant)1486    odsState.addAttribute(getConstantAttrName(odsState.name),1487                          odsBuilder.getUnitAttr());1488 1489  cir::GlobalLinkageKindAttr linkageAttr =1490      cir::GlobalLinkageKindAttr::get(odsBuilder.getContext(), linkage);1491  odsState.addAttribute(getLinkageAttrName(odsState.name), linkageAttr);1492 1493  Region *ctorRegion = odsState.addRegion();1494  if (ctorBuilder) {1495    odsBuilder.createBlock(ctorRegion);1496    ctorBuilder(odsBuilder, odsState.location);1497  }1498 1499  Region *dtorRegion = odsState.addRegion();1500  if (dtorBuilder) {1501    odsBuilder.createBlock(dtorRegion);1502    dtorBuilder(odsBuilder, odsState.location);1503  }1504 1505  odsState.addAttribute(getGlobalVisibilityAttrName(odsState.name),1506                        cir::VisibilityAttr::get(odsBuilder.getContext()));1507}1508 1509/// Given the region at `index`, or the parent operation if `index` is None,1510/// return the successor regions. These are the regions that may be selected1511/// during the flow of control. `operands` is a set of optional attributes that1512/// correspond to a constant value for each operand, or null if that operand is1513/// not a constant.1514void cir::GlobalOp::getSuccessorRegions(1515    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {1516  // The `ctor` and `dtor` regions always branch back to the parent operation.1517  if (!point.isParent()) {1518    regions.push_back(1519        RegionSuccessor(getOperation(), getOperation()->getResults()));1520    return;1521  }1522 1523  // Don't consider the ctor region if it is empty.1524  Region *ctorRegion = &this->getCtorRegion();1525  if (ctorRegion->empty())1526    ctorRegion = nullptr;1527 1528  // Don't consider the dtor region if it is empty.1529  Region *dtorRegion = &this->getCtorRegion();1530  if (dtorRegion->empty())1531    dtorRegion = nullptr;1532 1533  // If the condition isn't constant, both regions may be executed.1534  if (ctorRegion)1535    regions.push_back(RegionSuccessor(ctorRegion));1536  if (dtorRegion)1537    regions.push_back(RegionSuccessor(dtorRegion));1538}1539 1540static void printGlobalOpTypeAndInitialValue(OpAsmPrinter &p, cir::GlobalOp op,1541                                             TypeAttr type, Attribute initAttr,1542                                             mlir::Region &ctorRegion,1543                                             mlir::Region &dtorRegion) {1544  auto printType = [&]() { p << ": " << type; };1545  if (!op.isDeclaration()) {1546    p << "= ";1547    if (!ctorRegion.empty()) {1548      p << "ctor ";1549      printType();1550      p << " ";1551      p.printRegion(ctorRegion,1552                    /*printEntryBlockArgs=*/false,1553                    /*printBlockTerminators=*/false);1554    } else {1555      // This also prints the type...1556      if (initAttr)1557        printConstant(p, initAttr);1558    }1559 1560    if (!dtorRegion.empty()) {1561      p << " dtor ";1562      p.printRegion(dtorRegion,1563                    /*printEntryBlockArgs=*/false,1564                    /*printBlockTerminators=*/false);1565    }1566  } else {1567    printType();1568  }1569}1570 1571static ParseResult parseGlobalOpTypeAndInitialValue(OpAsmParser &parser,1572                                                    TypeAttr &typeAttr,1573                                                    Attribute &initialValueAttr,1574                                                    mlir::Region &ctorRegion,1575                                                    mlir::Region &dtorRegion) {1576  mlir::Type opTy;1577  if (parser.parseOptionalEqual().failed()) {1578    // Absence of equal means a declaration, so we need to parse the type.1579    //  cir.global @a : !cir.int<s, 32>1580    if (parser.parseColonType(opTy))1581      return failure();1582  } else {1583    // Parse contructor, example:1584    //  cir.global @rgb = ctor : type { ... }1585    if (!parser.parseOptionalKeyword("ctor")) {1586      if (parser.parseColonType(opTy))1587        return failure();1588      auto parseLoc = parser.getCurrentLocation();1589      if (parser.parseRegion(ctorRegion, /*arguments=*/{}, /*argTypes=*/{}))1590        return failure();1591      if (ensureRegionTerm(parser, ctorRegion, parseLoc).failed())1592        return failure();1593    } else {1594      // Parse constant with initializer, examples:1595      //  cir.global @y = 3.400000e+00 : f321596      //  cir.global @rgb = #cir.const_array<[...] : !cir.array<i8 x 3>>1597      if (parseConstantValue(parser, initialValueAttr).failed())1598        return failure();1599 1600      assert(mlir::isa<mlir::TypedAttr>(initialValueAttr) &&1601             "Non-typed attrs shouldn't appear here.");1602      auto typedAttr = mlir::cast<mlir::TypedAttr>(initialValueAttr);1603      opTy = typedAttr.getType();1604    }1605 1606    // Parse destructor, example:1607    //   dtor { ... }1608    if (!parser.parseOptionalKeyword("dtor")) {1609      auto parseLoc = parser.getCurrentLocation();1610      if (parser.parseRegion(dtorRegion, /*arguments=*/{}, /*argTypes=*/{}))1611        return failure();1612      if (ensureRegionTerm(parser, dtorRegion, parseLoc).failed())1613        return failure();1614    }1615  }1616 1617  typeAttr = TypeAttr::get(opTy);1618  return success();1619}1620 1621//===----------------------------------------------------------------------===//1622// GetGlobalOp1623//===----------------------------------------------------------------------===//1624 1625LogicalResult1626cir::GetGlobalOp::verifySymbolUses(SymbolTableCollection &symbolTable) {1627  // Verify that the result type underlying pointer type matches the type of1628  // the referenced cir.global or cir.func op.1629  mlir::Operation *op =1630      symbolTable.lookupNearestSymbolFrom(*this, getNameAttr());1631  if (op == nullptr || !(isa<GlobalOp>(op) || isa<FuncOp>(op)))1632    return emitOpError("'")1633           << getName()1634           << "' does not reference a valid cir.global or cir.func";1635 1636  mlir::Type symTy;1637  if (auto g = dyn_cast<GlobalOp>(op)) {1638    symTy = g.getSymType();1639    assert(!cir::MissingFeatures::addressSpace());1640    assert(!cir::MissingFeatures::opGlobalThreadLocal());1641  } else if (auto f = dyn_cast<FuncOp>(op)) {1642    symTy = f.getFunctionType();1643  } else {1644    llvm_unreachable("Unexpected operation for GetGlobalOp");1645  }1646 1647  auto resultType = dyn_cast<PointerType>(getAddr().getType());1648  if (!resultType || symTy != resultType.getPointee())1649    return emitOpError("result type pointee type '")1650           << resultType.getPointee() << "' does not match type " << symTy1651           << " of the global @" << getName();1652 1653  return success();1654}1655 1656//===----------------------------------------------------------------------===//1657// VTableAddrPointOp1658//===----------------------------------------------------------------------===//1659 1660LogicalResult1661cir::VTableAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {1662  StringRef name = getName();1663 1664  // Verify that the result type underlying pointer type matches the type of1665  // the referenced cir.global.1666  auto op =1667      symbolTable.lookupNearestSymbolFrom<cir::GlobalOp>(*this, getNameAttr());1668  if (!op)1669    return emitOpError("'")1670           << name << "' does not reference a valid cir.global";1671  std::optional<mlir::Attribute> init = op.getInitialValue();1672  if (!init)1673    return success();1674  if (!isa<cir::VTableAttr>(*init))1675    return emitOpError("Expected #cir.vtable in initializer for global '")1676           << name << "'";1677  return success();1678}1679 1680//===----------------------------------------------------------------------===//1681// VTTAddrPointOp1682//===----------------------------------------------------------------------===//1683 1684LogicalResult1685cir::VTTAddrPointOp::verifySymbolUses(SymbolTableCollection &symbolTable) {1686  // VTT ptr is not coming from a symbol.1687  if (!getName())1688    return success();1689  StringRef name = *getName();1690 1691  // Verify that the result type underlying pointer type matches the type of1692  // the referenced cir.global op.1693  auto op =1694      symbolTable.lookupNearestSymbolFrom<cir::GlobalOp>(*this, getNameAttr());1695  if (!op)1696    return emitOpError("'")1697           << name << "' does not reference a valid cir.global";1698  std::optional<mlir::Attribute> init = op.getInitialValue();1699  if (!init)1700    return success();1701  if (!isa<cir::ConstArrayAttr>(*init))1702    return emitOpError(1703               "Expected constant array in initializer for global VTT '")1704           << name << "'";1705  return success();1706}1707 1708LogicalResult cir::VTTAddrPointOp::verify() {1709  // The operation uses either a symbol or a value to operate, but not both1710  if (getName() && getSymAddr())1711    return emitOpError("should use either a symbol or value, but not both");1712 1713  // If not a symbol, stick with the concrete type used for getSymAddr.1714  if (getSymAddr())1715    return success();1716 1717  mlir::Type resultType = getAddr().getType();1718  mlir::Type resTy = cir::PointerType::get(1719      cir::PointerType::get(cir::VoidType::get(getContext())));1720 1721  if (resultType != resTy)1722    return emitOpError("result type must be ")1723           << resTy << ", but provided result type is " << resultType;1724  return success();1725}1726 1727//===----------------------------------------------------------------------===//1728// FuncOp1729//===----------------------------------------------------------------------===//1730 1731/// Returns the name used for the linkage attribute. This *must* correspond to1732/// the name of the attribute in ODS.1733static llvm::StringRef getLinkageAttrNameString() { return "linkage"; }1734 1735void cir::FuncOp::build(OpBuilder &builder, OperationState &result,1736                        StringRef name, FuncType type,1737                        GlobalLinkageKind linkage) {1738  result.addRegion();1739  result.addAttribute(SymbolTable::getSymbolAttrName(),1740                      builder.getStringAttr(name));1741  result.addAttribute(getFunctionTypeAttrName(result.name),1742                      TypeAttr::get(type));1743  result.addAttribute(1744      getLinkageAttrNameString(),1745      GlobalLinkageKindAttr::get(builder.getContext(), linkage));1746  result.addAttribute(getGlobalVisibilityAttrName(result.name),1747                      cir::VisibilityAttr::get(builder.getContext()));1748}1749 1750ParseResult cir::FuncOp::parse(OpAsmParser &parser, OperationState &state) {1751  llvm::SMLoc loc = parser.getCurrentLocation();1752  mlir::Builder &builder = parser.getBuilder();1753 1754  mlir::StringAttr builtinNameAttr = getBuiltinAttrName(state.name);1755  mlir::StringAttr coroutineNameAttr = getCoroutineAttrName(state.name);1756  mlir::StringAttr lambdaNameAttr = getLambdaAttrName(state.name);1757  mlir::StringAttr noProtoNameAttr = getNoProtoAttrName(state.name);1758  mlir::StringAttr visNameAttr = getSymVisibilityAttrName(state.name);1759  mlir::StringAttr visibilityNameAttr = getGlobalVisibilityAttrName(state.name);1760  mlir::StringAttr dsoLocalNameAttr = getDsoLocalAttrName(state.name);1761  mlir::StringAttr specialMemberAttr = getCxxSpecialMemberAttrName(state.name);1762 1763  if (::mlir::succeeded(parser.parseOptionalKeyword(builtinNameAttr.strref())))1764    state.addAttribute(builtinNameAttr, parser.getBuilder().getUnitAttr());1765  if (::mlir::succeeded(1766          parser.parseOptionalKeyword(coroutineNameAttr.strref())))1767    state.addAttribute(coroutineNameAttr, parser.getBuilder().getUnitAttr());1768  if (::mlir::succeeded(parser.parseOptionalKeyword(lambdaNameAttr.strref())))1769    state.addAttribute(lambdaNameAttr, parser.getBuilder().getUnitAttr());1770  if (parser.parseOptionalKeyword(noProtoNameAttr).succeeded())1771    state.addAttribute(noProtoNameAttr, parser.getBuilder().getUnitAttr());1772 1773  // Default to external linkage if no keyword is provided.1774  state.addAttribute(getLinkageAttrNameString(),1775                     GlobalLinkageKindAttr::get(1776                         parser.getContext(),1777                         parseOptionalCIRKeyword<GlobalLinkageKind>(1778                             parser, GlobalLinkageKind::ExternalLinkage)));1779 1780  ::llvm::StringRef visAttrStr;1781  if (parser.parseOptionalKeyword(&visAttrStr, {"private", "public", "nested"})1782          .succeeded()) {1783    state.addAttribute(visNameAttr,1784                       parser.getBuilder().getStringAttr(visAttrStr));1785  }1786 1787  cir::VisibilityAttr cirVisibilityAttr;1788  parseVisibilityAttr(parser, cirVisibilityAttr);1789  state.addAttribute(visibilityNameAttr, cirVisibilityAttr);1790 1791  if (parser.parseOptionalKeyword(dsoLocalNameAttr).succeeded())1792    state.addAttribute(dsoLocalNameAttr, parser.getBuilder().getUnitAttr());1793 1794  StringAttr nameAttr;1795  if (parser.parseSymbolName(nameAttr, SymbolTable::getSymbolAttrName(),1796                             state.attributes))1797    return failure();1798  llvm::SmallVector<OpAsmParser::Argument, 8> arguments;1799  llvm::SmallVector<mlir::Type> resultTypes;1800  llvm::SmallVector<DictionaryAttr> resultAttrs;1801  bool isVariadic = false;1802  if (function_interface_impl::parseFunctionSignatureWithArguments(1803          parser, /*allowVariadic=*/true, arguments, isVariadic, resultTypes,1804          resultAttrs))1805    return failure();1806  llvm::SmallVector<mlir::Type> argTypes;1807  for (OpAsmParser::Argument &arg : arguments)1808    argTypes.push_back(arg.type);1809 1810  if (resultTypes.size() > 1) {1811    return parser.emitError(1812        loc, "functions with multiple return types are not supported");1813  }1814 1815  mlir::Type returnType =1816      (resultTypes.empty() ? cir::VoidType::get(builder.getContext())1817                           : resultTypes.front());1818 1819  cir::FuncType fnType = cir::FuncType::get(argTypes, returnType, isVariadic);1820  if (!fnType)1821    return failure();1822  state.addAttribute(getFunctionTypeAttrName(state.name),1823                     TypeAttr::get(fnType));1824 1825  bool hasAlias = false;1826  mlir::StringAttr aliaseeNameAttr = getAliaseeAttrName(state.name);1827  if (parser.parseOptionalKeyword("alias").succeeded()) {1828    if (parser.parseLParen().failed())1829      return failure();1830    mlir::StringAttr aliaseeAttr;1831    if (parser.parseOptionalSymbolName(aliaseeAttr).failed())1832      return failure();1833    state.addAttribute(aliaseeNameAttr, FlatSymbolRefAttr::get(aliaseeAttr));1834    if (parser.parseRParen().failed())1835      return failure();1836    hasAlias = true;1837  }1838 1839  auto parseGlobalDtorCtor =1840      [&](StringRef keyword,1841          llvm::function_ref<void(std::optional<int> prio)> createAttr)1842      -> mlir::LogicalResult {1843    if (mlir::succeeded(parser.parseOptionalKeyword(keyword))) {1844      std::optional<int> priority;1845      if (mlir::succeeded(parser.parseOptionalLParen())) {1846        auto parsedPriority = mlir::FieldParser<int>::parse(parser);1847        if (mlir::failed(parsedPriority))1848          return parser.emitError(parser.getCurrentLocation(),1849                                  "failed to parse 'priority', of type 'int'");1850        priority = parsedPriority.value_or(int());1851        // Parse literal ')'1852        if (parser.parseRParen())1853          return failure();1854      }1855      createAttr(priority);1856    }1857    return success();1858  };1859 1860  // Parse CXXSpecialMember attribute1861  if (parser.parseOptionalKeyword("special_member").succeeded()) {1862    cir::CXXCtorAttr ctorAttr;1863    cir::CXXDtorAttr dtorAttr;1864    cir::CXXAssignAttr assignAttr;1865    if (parser.parseLess().failed())1866      return failure();1867    if (parser.parseOptionalAttribute(ctorAttr).has_value())1868      state.addAttribute(specialMemberAttr, ctorAttr);1869    else if (parser.parseOptionalAttribute(dtorAttr).has_value())1870      state.addAttribute(specialMemberAttr, dtorAttr);1871    else if (parser.parseOptionalAttribute(assignAttr).has_value())1872      state.addAttribute(specialMemberAttr, assignAttr);1873    if (parser.parseGreater().failed())1874      return failure();1875  }1876 1877  if (parseGlobalDtorCtor("global_ctor", [&](std::optional<int> priority) {1878        mlir::IntegerAttr globalCtorPriorityAttr =1879            builder.getI32IntegerAttr(priority.value_or(65535));1880        state.addAttribute(getGlobalCtorPriorityAttrName(state.name),1881                           globalCtorPriorityAttr);1882      }).failed())1883    return failure();1884 1885  if (parseGlobalDtorCtor("global_dtor", [&](std::optional<int> priority) {1886        mlir::IntegerAttr globalDtorPriorityAttr =1887            builder.getI32IntegerAttr(priority.value_or(65535));1888        state.addAttribute(getGlobalDtorPriorityAttrName(state.name),1889                           globalDtorPriorityAttr);1890      }).failed())1891    return failure();1892 1893  // Parse optional inline kind: inline(never|always|hint)1894  if (parser.parseOptionalKeyword("inline").succeeded()) {1895    if (parser.parseLParen().failed())1896      return failure();1897 1898    llvm::StringRef inlineKindStr;1899    const std::array<llvm::StringRef, cir::getMaxEnumValForInlineKind()>1900        allowedInlineKindStrs{1901            cir::stringifyInlineKind(cir::InlineKind::NoInline),1902            cir::stringifyInlineKind(cir::InlineKind::AlwaysInline),1903            cir::stringifyInlineKind(cir::InlineKind::InlineHint),1904        };1905    if (parser.parseOptionalKeyword(&inlineKindStr, allowedInlineKindStrs)1906            .failed())1907      return parser.emitError(parser.getCurrentLocation(),1908                              "expected 'never', 'always', or 'hint'");1909 1910    std::optional<InlineKind> inlineKind =1911        cir::symbolizeInlineKind(inlineKindStr);1912    if (!inlineKind)1913      return parser.emitError(parser.getCurrentLocation(),1914                              "invalid inline kind");1915 1916    state.addAttribute(getInlineKindAttrName(state.name),1917                       cir::InlineAttr::get(builder.getContext(), *inlineKind));1918 1919    if (parser.parseRParen().failed())1920      return failure();1921  }1922 1923  // Parse the rest of the attributes.1924  NamedAttrList parsedAttrs;1925  if (parser.parseOptionalAttrDictWithKeyword(parsedAttrs))1926    return failure();1927 1928  for (StringRef disallowed : cir::FuncOp::getAttributeNames()) {1929    if (parsedAttrs.get(disallowed))1930      return parser.emitError(loc, "attribute '")1931             << disallowed1932             << "' should not be specified in the explicit attribute list";1933  }1934 1935  state.attributes.append(parsedAttrs);1936 1937  // Parse the optional function body.1938  auto *body = state.addRegion();1939  OptionalParseResult parseResult = parser.parseOptionalRegion(1940      *body, arguments, /*enableNameShadowing=*/false);1941  if (parseResult.has_value()) {1942    if (hasAlias)1943      return parser.emitError(loc, "function alias shall not have a body");1944    if (failed(*parseResult))1945      return failure();1946    // Function body was parsed, make sure its not empty.1947    if (body->empty())1948      return parser.emitError(loc, "expected non-empty function body");1949  }1950 1951  return success();1952}1953 1954// This function corresponds to `llvm::GlobalValue::isDeclaration` and should1955// have a similar implementation. We don't currently ifuncs or materializable1956// functions, but those should be handled here as they are implemented.1957bool cir::FuncOp::isDeclaration() {1958  assert(!cir::MissingFeatures::supportIFuncAttr());1959 1960  std::optional<StringRef> aliasee = getAliasee();1961  if (!aliasee)1962    return getFunctionBody().empty();1963 1964  // Aliases are always definitions.1965  return false;1966}1967 1968bool cir::FuncOp::isCXXSpecialMemberFunction() {1969  return getCxxSpecialMemberAttr() != nullptr;1970}1971 1972bool cir::FuncOp::isCxxConstructor() {1973  auto attr = getCxxSpecialMemberAttr();1974  return attr && dyn_cast<CXXCtorAttr>(attr);1975}1976 1977bool cir::FuncOp::isCxxDestructor() {1978  auto attr = getCxxSpecialMemberAttr();1979  return attr && dyn_cast<CXXDtorAttr>(attr);1980}1981 1982bool cir::FuncOp::isCxxSpecialAssignment() {1983  auto attr = getCxxSpecialMemberAttr();1984  return attr && dyn_cast<CXXAssignAttr>(attr);1985}1986 1987std::optional<CtorKind> cir::FuncOp::getCxxConstructorKind() {1988  mlir::Attribute attr = getCxxSpecialMemberAttr();1989  if (attr) {1990    if (auto ctor = dyn_cast<CXXCtorAttr>(attr))1991      return ctor.getCtorKind();1992  }1993  return std::nullopt;1994}1995 1996std::optional<AssignKind> cir::FuncOp::getCxxSpecialAssignKind() {1997  mlir::Attribute attr = getCxxSpecialMemberAttr();1998  if (attr) {1999    if (auto assign = dyn_cast<CXXAssignAttr>(attr))2000      return assign.getAssignKind();2001  }2002  return std::nullopt;2003}2004 2005bool cir::FuncOp::isCxxTrivialMemberFunction() {2006  mlir::Attribute attr = getCxxSpecialMemberAttr();2007  if (attr) {2008    if (auto ctor = dyn_cast<CXXCtorAttr>(attr))2009      return ctor.getIsTrivial();2010    if (auto dtor = dyn_cast<CXXDtorAttr>(attr))2011      return dtor.getIsTrivial();2012    if (auto assign = dyn_cast<CXXAssignAttr>(attr))2013      return assign.getIsTrivial();2014  }2015  return false;2016}2017 2018mlir::Region *cir::FuncOp::getCallableRegion() {2019  // TODO(CIR): This function will have special handling for aliases and a2020  // check for an external function, once those features have been upstreamed.2021  return &getBody();2022}2023 2024void cir::FuncOp::print(OpAsmPrinter &p) {2025  if (getBuiltin())2026    p << " builtin";2027 2028  if (getCoroutine())2029    p << " coroutine";2030 2031  if (getLambda())2032    p << " lambda";2033 2034  if (getNoProto())2035    p << " no_proto";2036 2037  if (getComdat())2038    p << " comdat";2039 2040  if (getLinkage() != GlobalLinkageKind::ExternalLinkage)2041    p << ' ' << stringifyGlobalLinkageKind(getLinkage());2042 2043  mlir::SymbolTable::Visibility vis = getVisibility();2044  if (vis != mlir::SymbolTable::Visibility::Public)2045    p << ' ' << vis;2046 2047  cir::VisibilityAttr cirVisibilityAttr = getGlobalVisibilityAttr();2048  if (!cirVisibilityAttr.isDefault()) {2049    p << ' ';2050    printVisibilityAttr(p, cirVisibilityAttr);2051  }2052 2053  if (getDsoLocal())2054    p << " dso_local";2055 2056  p << ' ';2057  p.printSymbolName(getSymName());2058  cir::FuncType fnType = getFunctionType();2059  function_interface_impl::printFunctionSignature(2060      p, *this, fnType.getInputs(), fnType.isVarArg(), fnType.getReturnTypes());2061 2062  if (std::optional<StringRef> aliaseeName = getAliasee()) {2063    p << " alias(";2064    p.printSymbolName(*aliaseeName);2065    p << ")";2066  }2067 2068  if (auto specialMemberAttr = getCxxSpecialMember()) {2069    p << " special_member<";2070    p.printAttribute(*specialMemberAttr);2071    p << '>';2072  }2073 2074  if (auto globalCtorPriority = getGlobalCtorPriority()) {2075    p << " global_ctor";2076    if (globalCtorPriority.value() != 65535)2077      p << "(" << globalCtorPriority.value() << ")";2078  }2079 2080  if (auto globalDtorPriority = getGlobalDtorPriority()) {2081    p << " global_dtor";2082    if (globalDtorPriority.value() != 65535)2083      p << "(" << globalDtorPriority.value() << ")";2084  }2085 2086  if (cir::InlineAttr inlineAttr = getInlineKindAttr()) {2087    p << " inline(" << cir::stringifyInlineKind(inlineAttr.getValue()) << ")";2088  }2089 2090  function_interface_impl::printFunctionAttributes(2091      p, *this, cir::FuncOp::getAttributeNames());2092 2093  // Print the body if this is not an external function.2094  Region &body = getOperation()->getRegion(0);2095  if (!body.empty()) {2096    p << ' ';2097    p.printRegion(body, /*printEntryBlockArgs=*/false,2098                  /*printBlockTerminators=*/true);2099  }2100}2101 2102mlir::LogicalResult cir::FuncOp::verify() {2103 2104  if (!isDeclaration() && getCoroutine()) {2105    bool foundAwait = false;2106    this->walk([&](Operation *op) {2107      if (auto await = dyn_cast<AwaitOp>(op)) {2108        foundAwait = true;2109        return;2110      }2111    });2112    if (!foundAwait)2113      return emitOpError()2114             << "coroutine body must use at least one cir.await op";2115  }2116 2117  llvm::SmallSet<llvm::StringRef, 16> labels;2118  llvm::SmallSet<llvm::StringRef, 16> gotos;2119  llvm::SmallSet<llvm::StringRef, 16> blockAddresses;2120  bool invalidBlockAddress = false;2121  getOperation()->walk([&](mlir::Operation *op) {2122    if (auto lab = dyn_cast<cir::LabelOp>(op)) {2123      labels.insert(lab.getLabel());2124    } else if (auto goTo = dyn_cast<cir::GotoOp>(op)) {2125      gotos.insert(goTo.getLabel());2126    } else if (auto blkAdd = dyn_cast<cir::BlockAddressOp>(op)) {2127      if (blkAdd.getBlockAddrInfoAttr().getFunc().getAttr() != getSymName()) {2128        // Stop the walk early, no need to continue2129        invalidBlockAddress = true;2130        return mlir::WalkResult::interrupt();2131      }2132      blockAddresses.insert(blkAdd.getBlockAddrInfoAttr().getLabel());2133    }2134    return mlir::WalkResult::advance();2135  });2136 2137  if (invalidBlockAddress)2138    return emitOpError() << "blockaddress references a different function";2139 2140  llvm::SmallSet<llvm::StringRef, 16> mismatched;2141  if (!labels.empty() || !gotos.empty()) {2142    mismatched = llvm::set_difference(gotos, labels);2143 2144    if (!mismatched.empty())2145      return emitOpError() << "goto/label mismatch";2146  }2147 2148  mismatched.clear();2149 2150  if (!labels.empty() || !blockAddresses.empty()) {2151    mismatched = llvm::set_difference(blockAddresses, labels);2152 2153    if (!mismatched.empty())2154      return emitOpError()2155             << "expects an existing label target in the referenced function";2156  }2157 2158  return success();2159}2160 2161//===----------------------------------------------------------------------===//2162// BinOp2163//===----------------------------------------------------------------------===//2164LogicalResult cir::BinOp::verify() {2165  bool noWrap = getNoUnsignedWrap() || getNoSignedWrap();2166  bool saturated = getSaturated();2167 2168  if (!isa<cir::IntType>(getType()) && noWrap)2169    return emitError()2170           << "only operations on integer values may have nsw/nuw flags";2171 2172  bool noWrapOps = getKind() == cir::BinOpKind::Add ||2173                   getKind() == cir::BinOpKind::Sub ||2174                   getKind() == cir::BinOpKind::Mul;2175 2176  bool saturatedOps =2177      getKind() == cir::BinOpKind::Add || getKind() == cir::BinOpKind::Sub;2178 2179  if (noWrap && !noWrapOps)2180    return emitError() << "The nsw/nuw flags are applicable to opcodes: 'add', "2181                          "'sub' and 'mul'";2182  if (saturated && !saturatedOps)2183    return emitError() << "The saturated flag is applicable to opcodes: 'add' "2184                          "and 'sub'";2185  if (noWrap && saturated)2186    return emitError() << "The nsw/nuw flags and the saturated flag are "2187                          "mutually exclusive";2188 2189  return mlir::success();2190}2191 2192//===----------------------------------------------------------------------===//2193// TernaryOp2194//===----------------------------------------------------------------------===//2195 2196/// Given the region at `point`, or the parent operation if `point` is None,2197/// return the successor regions. These are the regions that may be selected2198/// during the flow of control. `operands` is a set of optional attributes that2199/// correspond to a constant value for each operand, or null if that operand is2200/// not a constant.2201void cir::TernaryOp::getSuccessorRegions(2202    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {2203  // The `true` and the `false` region branch back to the parent operation.2204  if (!point.isParent()) {2205    regions.push_back(RegionSuccessor(getOperation(), this->getODSResults(0)));2206    return;2207  }2208 2209  // When branching from the parent operation, both the true and false2210  // regions are considered possible successors2211  regions.push_back(RegionSuccessor(&getTrueRegion()));2212  regions.push_back(RegionSuccessor(&getFalseRegion()));2213}2214 2215void cir::TernaryOp::build(2216    OpBuilder &builder, OperationState &result, Value cond,2217    function_ref<void(OpBuilder &, Location)> trueBuilder,2218    function_ref<void(OpBuilder &, Location)> falseBuilder) {2219  result.addOperands(cond);2220  OpBuilder::InsertionGuard guard(builder);2221  Region *trueRegion = result.addRegion();2222  builder.createBlock(trueRegion);2223  trueBuilder(builder, result.location);2224  Region *falseRegion = result.addRegion();2225  builder.createBlock(falseRegion);2226  falseBuilder(builder, result.location);2227 2228  // Get result type from whichever branch has a yield (the other may have2229  // unreachable from a throw expression)2230  auto yield =2231      dyn_cast_or_null<cir::YieldOp>(trueRegion->back().getTerminator());2232  if (!yield)2233    yield = dyn_cast_or_null<cir::YieldOp>(falseRegion->back().getTerminator());2234 2235  assert((yield && yield.getNumOperands() <= 1) &&2236         "expected zero or one result type");2237  if (yield.getNumOperands() == 1)2238    result.addTypes(TypeRange{yield.getOperandTypes().front()});2239}2240 2241//===----------------------------------------------------------------------===//2242// SelectOp2243//===----------------------------------------------------------------------===//2244 2245OpFoldResult cir::SelectOp::fold(FoldAdaptor adaptor) {2246  mlir::Attribute condition = adaptor.getCondition();2247  if (condition) {2248    bool conditionValue = mlir::cast<cir::BoolAttr>(condition).getValue();2249    return conditionValue ? getTrueValue() : getFalseValue();2250  }2251 2252  // cir.select if %0 then x else x -> x2253  mlir::Attribute trueValue = adaptor.getTrueValue();2254  mlir::Attribute falseValue = adaptor.getFalseValue();2255  if (trueValue == falseValue)2256    return trueValue;2257  if (getTrueValue() == getFalseValue())2258    return getTrueValue();2259 2260  return {};2261}2262 2263//===----------------------------------------------------------------------===//2264// ShiftOp2265//===----------------------------------------------------------------------===//2266LogicalResult cir::ShiftOp::verify() {2267  mlir::Operation *op = getOperation();2268  auto op0VecTy = mlir::dyn_cast<cir::VectorType>(op->getOperand(0).getType());2269  auto op1VecTy = mlir::dyn_cast<cir::VectorType>(op->getOperand(1).getType());2270  if (!op0VecTy ^ !op1VecTy)2271    return emitOpError() << "input types cannot be one vector and one scalar";2272 2273  if (op0VecTy) {2274    if (op0VecTy.getSize() != op1VecTy.getSize())2275      return emitOpError() << "input vector types must have the same size";2276 2277    auto opResultTy = mlir::dyn_cast<cir::VectorType>(getType());2278    if (!opResultTy)2279      return emitOpError() << "the type of the result must be a vector "2280                           << "if it is vector shift";2281 2282    auto op0VecEleTy = mlir::cast<cir::IntType>(op0VecTy.getElementType());2283    auto op1VecEleTy = mlir::cast<cir::IntType>(op1VecTy.getElementType());2284    if (op0VecEleTy.getWidth() != op1VecEleTy.getWidth())2285      return emitOpError()2286             << "vector operands do not have the same elements sizes";2287 2288    auto resVecEleTy = mlir::cast<cir::IntType>(opResultTy.getElementType());2289    if (op0VecEleTy.getWidth() != resVecEleTy.getWidth())2290      return emitOpError() << "vector operands and result type do not have the "2291                              "same elements sizes";2292  }2293 2294  return mlir::success();2295}2296 2297//===----------------------------------------------------------------------===//2298// LabelOp Definitions2299//===----------------------------------------------------------------------===//2300 2301LogicalResult cir::LabelOp::verify() {2302  mlir::Operation *op = getOperation();2303  mlir::Block *blk = op->getBlock();2304  if (&blk->front() != op)2305    return emitError() << "must be the first operation in a block";2306 2307  return mlir::success();2308}2309 2310//===----------------------------------------------------------------------===//2311// UnaryOp2312//===----------------------------------------------------------------------===//2313 2314LogicalResult cir::UnaryOp::verify() {2315  switch (getKind()) {2316  case cir::UnaryOpKind::Inc:2317  case cir::UnaryOpKind::Dec:2318  case cir::UnaryOpKind::Plus:2319  case cir::UnaryOpKind::Minus:2320  case cir::UnaryOpKind::Not:2321    // Nothing to verify.2322    return success();2323  }2324 2325  llvm_unreachable("Unknown UnaryOp kind?");2326}2327 2328static bool isBoolNot(cir::UnaryOp op) {2329  return isa<cir::BoolType>(op.getInput().getType()) &&2330         op.getKind() == cir::UnaryOpKind::Not;2331}2332 2333// This folder simplifies the sequential boolean not operations.2334// For instance, the next two unary operations will be eliminated:2335//2336// ```mlir2337// %1 = cir.unary(not, %0) : !cir.bool, !cir.bool2338// %2 = cir.unary(not, %1) : !cir.bool, !cir.bool2339// ```2340//2341// and the argument of the first one (%0) will be used instead.2342OpFoldResult cir::UnaryOp::fold(FoldAdaptor adaptor) {2343  if (auto poison =2344          mlir::dyn_cast_if_present<cir::PoisonAttr>(adaptor.getInput())) {2345    // Propagate poison values2346    return poison;2347  }2348 2349  if (isBoolNot(*this))2350    if (auto previous = getInput().getDefiningOp<cir::UnaryOp>())2351      if (isBoolNot(previous))2352        return previous.getInput();2353 2354  return {};2355}2356//===----------------------------------------------------------------------===//2357// AwaitOp2358//===----------------------------------------------------------------------===//2359 2360void cir::AwaitOp::build(OpBuilder &builder, OperationState &result,2361                         cir::AwaitKind kind, BuilderCallbackRef readyBuilder,2362                         BuilderCallbackRef suspendBuilder,2363                         BuilderCallbackRef resumeBuilder) {2364  result.addAttribute(getKindAttrName(result.name),2365                      cir::AwaitKindAttr::get(builder.getContext(), kind));2366  {2367    OpBuilder::InsertionGuard guard(builder);2368    Region *readyRegion = result.addRegion();2369    builder.createBlock(readyRegion);2370    readyBuilder(builder, result.location);2371  }2372 2373  {2374    OpBuilder::InsertionGuard guard(builder);2375    Region *suspendRegion = result.addRegion();2376    builder.createBlock(suspendRegion);2377    suspendBuilder(builder, result.location);2378  }2379 2380  {2381    OpBuilder::InsertionGuard guard(builder);2382    Region *resumeRegion = result.addRegion();2383    builder.createBlock(resumeRegion);2384    resumeBuilder(builder, result.location);2385  }2386}2387 2388void cir::AwaitOp::getSuccessorRegions(2389    mlir::RegionBranchPoint point, SmallVectorImpl<RegionSuccessor> &regions) {2390  // If any index all the underlying regions branch back to the parent2391  // operation.2392  if (!point.isParent()) {2393    regions.push_back(2394        RegionSuccessor(getOperation(), getOperation()->getResults()));2395    return;2396  }2397 2398  // TODO: retrieve information from the promise and only push the2399  // necessary ones. Example: `std::suspend_never` on initial or final2400  // await's might allow suspend region to be skipped.2401  regions.push_back(RegionSuccessor(&this->getReady()));2402  regions.push_back(RegionSuccessor(&this->getSuspend()));2403  regions.push_back(RegionSuccessor(&this->getResume()));2404}2405 2406LogicalResult cir::AwaitOp::verify() {2407  if (!isa<ConditionOp>(this->getReady().back().getTerminator()))2408    return emitOpError("ready region must end with cir.condition");2409  return success();2410}2411 2412//===----------------------------------------------------------------------===//2413// CopyOp Definitions2414//===----------------------------------------------------------------------===//2415 2416LogicalResult cir::CopyOp::verify() {2417  // A data layout is required for us to know the number of bytes to be copied.2418  if (!getType().getPointee().hasTrait<DataLayoutTypeInterface::Trait>())2419    return emitError() << "missing data layout for pointee type";2420 2421  if (getSrc() == getDst())2422    return emitError() << "source and destination are the same";2423 2424  return mlir::success();2425}2426 2427//===----------------------------------------------------------------------===//2428// GetMemberOp Definitions2429//===----------------------------------------------------------------------===//2430 2431LogicalResult cir::GetMemberOp::verify() {2432  const auto recordTy = dyn_cast<RecordType>(getAddrTy().getPointee());2433  if (!recordTy)2434    return emitError() << "expected pointer to a record type";2435 2436  if (recordTy.getMembers().size() <= getIndex())2437    return emitError() << "member index out of bounds";2438 2439  if (recordTy.getMembers()[getIndex()] != getType().getPointee())2440    return emitError() << "member type mismatch";2441 2442  return mlir::success();2443}2444 2445//===----------------------------------------------------------------------===//2446// VecCreateOp2447//===----------------------------------------------------------------------===//2448 2449OpFoldResult cir::VecCreateOp::fold(FoldAdaptor adaptor) {2450  if (llvm::any_of(getElements(), [](mlir::Value value) {2451        return !value.getDefiningOp<cir::ConstantOp>();2452      }))2453    return {};2454 2455  return cir::ConstVectorAttr::get(2456      getType(), mlir::ArrayAttr::get(getContext(), adaptor.getElements()));2457}2458 2459LogicalResult cir::VecCreateOp::verify() {2460  // Verify that the number of arguments matches the number of elements in the2461  // vector, and that the type of all the arguments matches the type of the2462  // elements in the vector.2463  const cir::VectorType vecTy = getType();2464  if (getElements().size() != vecTy.getSize()) {2465    return emitOpError() << "operand count of " << getElements().size()2466                         << " doesn't match vector type " << vecTy2467                         << " element count of " << vecTy.getSize();2468  }2469 2470  const mlir::Type elementType = vecTy.getElementType();2471  for (const mlir::Value element : getElements()) {2472    if (element.getType() != elementType) {2473      return emitOpError() << "operand type " << element.getType()2474                           << " doesn't match vector element type "2475                           << elementType;2476    }2477  }2478 2479  return success();2480}2481 2482//===----------------------------------------------------------------------===//2483// VecExtractOp2484//===----------------------------------------------------------------------===//2485 2486OpFoldResult cir::VecExtractOp::fold(FoldAdaptor adaptor) {2487  const auto vectorAttr =2488      llvm::dyn_cast_if_present<cir::ConstVectorAttr>(adaptor.getVec());2489  if (!vectorAttr)2490    return {};2491 2492  const auto indexAttr =2493      llvm::dyn_cast_if_present<cir::IntAttr>(adaptor.getIndex());2494  if (!indexAttr)2495    return {};2496 2497  const mlir::ArrayAttr elements = vectorAttr.getElts();2498  const uint64_t index = indexAttr.getUInt();2499  if (index >= elements.size())2500    return {};2501 2502  return elements[index];2503}2504 2505//===----------------------------------------------------------------------===//2506// VecCmpOp2507//===----------------------------------------------------------------------===//2508 2509OpFoldResult cir::VecCmpOp::fold(FoldAdaptor adaptor) {2510  auto lhsVecAttr =2511      mlir::dyn_cast_if_present<cir::ConstVectorAttr>(adaptor.getLhs());2512  auto rhsVecAttr =2513      mlir::dyn_cast_if_present<cir::ConstVectorAttr>(adaptor.getRhs());2514  if (!lhsVecAttr || !rhsVecAttr)2515    return {};2516 2517  mlir::Type inputElemTy =2518      mlir::cast<cir::VectorType>(lhsVecAttr.getType()).getElementType();2519  if (!isAnyIntegerOrFloatingPointType(inputElemTy))2520    return {};2521 2522  cir::CmpOpKind opKind = adaptor.getKind();2523  mlir::ArrayAttr lhsVecElhs = lhsVecAttr.getElts();2524  mlir::ArrayAttr rhsVecElhs = rhsVecAttr.getElts();2525  uint64_t vecSize = lhsVecElhs.size();2526 2527  SmallVector<mlir::Attribute, 16> elements(vecSize);2528  bool isIntAttr = vecSize && mlir::isa<cir::IntAttr>(lhsVecElhs[0]);2529  for (uint64_t i = 0; i < vecSize; i++) {2530    mlir::Attribute lhsAttr = lhsVecElhs[i];2531    mlir::Attribute rhsAttr = rhsVecElhs[i];2532    int cmpResult = 0;2533    switch (opKind) {2534    case cir::CmpOpKind::lt: {2535      if (isIntAttr) {2536        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() <2537                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2538      } else {2539        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() <2540                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2541      }2542      break;2543    }2544    case cir::CmpOpKind::le: {2545      if (isIntAttr) {2546        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() <=2547                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2548      } else {2549        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() <=2550                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2551      }2552      break;2553    }2554    case cir::CmpOpKind::gt: {2555      if (isIntAttr) {2556        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() >2557                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2558      } else {2559        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() >2560                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2561      }2562      break;2563    }2564    case cir::CmpOpKind::ge: {2565      if (isIntAttr) {2566        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() >=2567                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2568      } else {2569        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() >=2570                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2571      }2572      break;2573    }2574    case cir::CmpOpKind::eq: {2575      if (isIntAttr) {2576        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() ==2577                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2578      } else {2579        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() ==2580                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2581      }2582      break;2583    }2584    case cir::CmpOpKind::ne: {2585      if (isIntAttr) {2586        cmpResult = mlir::cast<cir::IntAttr>(lhsAttr).getSInt() !=2587                    mlir::cast<cir::IntAttr>(rhsAttr).getSInt();2588      } else {2589        cmpResult = mlir::cast<cir::FPAttr>(lhsAttr).getValue() !=2590                    mlir::cast<cir::FPAttr>(rhsAttr).getValue();2591      }2592      break;2593    }2594    }2595 2596    elements[i] = cir::IntAttr::get(getType().getElementType(), cmpResult);2597  }2598 2599  return cir::ConstVectorAttr::get(2600      getType(), mlir::ArrayAttr::get(getContext(), elements));2601}2602 2603//===----------------------------------------------------------------------===//2604// VecShuffleOp2605//===----------------------------------------------------------------------===//2606 2607OpFoldResult cir::VecShuffleOp::fold(FoldAdaptor adaptor) {2608  auto vec1Attr =2609      mlir::dyn_cast_if_present<cir::ConstVectorAttr>(adaptor.getVec1());2610  auto vec2Attr =2611      mlir::dyn_cast_if_present<cir::ConstVectorAttr>(adaptor.getVec2());2612  if (!vec1Attr || !vec2Attr)2613    return {};2614 2615  mlir::Type vec1ElemTy =2616      mlir::cast<cir::VectorType>(vec1Attr.getType()).getElementType();2617 2618  mlir::ArrayAttr vec1Elts = vec1Attr.getElts();2619  mlir::ArrayAttr vec2Elts = vec2Attr.getElts();2620  mlir::ArrayAttr indicesElts = adaptor.getIndices();2621 2622  SmallVector<mlir::Attribute, 16> elements;2623  elements.reserve(indicesElts.size());2624 2625  uint64_t vec1Size = vec1Elts.size();2626  for (const auto &idxAttr : indicesElts.getAsRange<cir::IntAttr>()) {2627    if (idxAttr.getSInt() == -1) {2628      elements.push_back(cir::UndefAttr::get(vec1ElemTy));2629      continue;2630    }2631 2632    uint64_t idxValue = idxAttr.getUInt();2633    elements.push_back(idxValue < vec1Size ? vec1Elts[idxValue]2634                                           : vec2Elts[idxValue - vec1Size]);2635  }2636 2637  return cir::ConstVectorAttr::get(2638      getType(), mlir::ArrayAttr::get(getContext(), elements));2639}2640 2641LogicalResult cir::VecShuffleOp::verify() {2642  // The number of elements in the indices array must match the number of2643  // elements in the result type.2644  if (getIndices().size() != getResult().getType().getSize()) {2645    return emitOpError() << ": the number of elements in " << getIndices()2646                         << " and " << getResult().getType() << " don't match";2647  }2648 2649  // The element types of the two input vectors and of the result type must2650  // match.2651  if (getVec1().getType().getElementType() !=2652      getResult().getType().getElementType()) {2653    return emitOpError() << ": element types of " << getVec1().getType()2654                         << " and " << getResult().getType() << " don't match";2655  }2656 2657  const uint64_t maxValidIndex =2658      getVec1().getType().getSize() + getVec2().getType().getSize() - 1;2659  if (llvm::any_of(2660          getIndices().getAsRange<cir::IntAttr>(), [&](cir::IntAttr idxAttr) {2661            return idxAttr.getSInt() != -1 && idxAttr.getUInt() > maxValidIndex;2662          })) {2663    return emitOpError() << ": index for __builtin_shufflevector must be "2664                            "less than the total number of vector elements";2665  }2666  return success();2667}2668 2669//===----------------------------------------------------------------------===//2670// VecShuffleDynamicOp2671//===----------------------------------------------------------------------===//2672 2673OpFoldResult cir::VecShuffleDynamicOp::fold(FoldAdaptor adaptor) {2674  mlir::Attribute vec = adaptor.getVec();2675  mlir::Attribute indices = adaptor.getIndices();2676  if (mlir::isa_and_nonnull<cir::ConstVectorAttr>(vec) &&2677      mlir::isa_and_nonnull<cir::ConstVectorAttr>(indices)) {2678    auto vecAttr = mlir::cast<cir::ConstVectorAttr>(vec);2679    auto indicesAttr = mlir::cast<cir::ConstVectorAttr>(indices);2680 2681    mlir::ArrayAttr vecElts = vecAttr.getElts();2682    mlir::ArrayAttr indicesElts = indicesAttr.getElts();2683 2684    const uint64_t numElements = vecElts.size();2685 2686    SmallVector<mlir::Attribute, 16> elements;2687    elements.reserve(numElements);2688 2689    const uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1;2690    for (const auto &idxAttr : indicesElts.getAsRange<cir::IntAttr>()) {2691      uint64_t idxValue = idxAttr.getUInt();2692      uint64_t newIdx = idxValue & maskBits;2693      elements.push_back(vecElts[newIdx]);2694    }2695 2696    return cir::ConstVectorAttr::get(2697        getType(), mlir::ArrayAttr::get(getContext(), elements));2698  }2699 2700  return {};2701}2702 2703LogicalResult cir::VecShuffleDynamicOp::verify() {2704  // The number of elements in the two input vectors must match.2705  if (getVec().getType().getSize() !=2706      mlir::cast<cir::VectorType>(getIndices().getType()).getSize()) {2707    return emitOpError() << ": the number of elements in " << getVec().getType()2708                         << " and " << getIndices().getType() << " don't match";2709  }2710  return success();2711}2712 2713//===----------------------------------------------------------------------===//2714// VecTernaryOp2715//===----------------------------------------------------------------------===//2716 2717LogicalResult cir::VecTernaryOp::verify() {2718  // Verify that the condition operand has the same number of elements as the2719  // other operands.  (The automatic verification already checked that all2720  // operands are vector types and that the second and third operands are the2721  // same type.)2722  if (getCond().getType().getSize() != getLhs().getType().getSize()) {2723    return emitOpError() << ": the number of elements in "2724                         << getCond().getType() << " and " << getLhs().getType()2725                         << " don't match";2726  }2727  return success();2728}2729 2730OpFoldResult cir::VecTernaryOp::fold(FoldAdaptor adaptor) {2731  mlir::Attribute cond = adaptor.getCond();2732  mlir::Attribute lhs = adaptor.getLhs();2733  mlir::Attribute rhs = adaptor.getRhs();2734 2735  if (!mlir::isa_and_nonnull<cir::ConstVectorAttr>(cond) ||2736      !mlir::isa_and_nonnull<cir::ConstVectorAttr>(lhs) ||2737      !mlir::isa_and_nonnull<cir::ConstVectorAttr>(rhs))2738    return {};2739  auto condVec = mlir::cast<cir::ConstVectorAttr>(cond);2740  auto lhsVec = mlir::cast<cir::ConstVectorAttr>(lhs);2741  auto rhsVec = mlir::cast<cir::ConstVectorAttr>(rhs);2742 2743  mlir::ArrayAttr condElts = condVec.getElts();2744 2745  SmallVector<mlir::Attribute, 16> elements;2746  elements.reserve(condElts.size());2747 2748  for (const auto &[idx, condAttr] :2749       llvm::enumerate(condElts.getAsRange<cir::IntAttr>())) {2750    if (condAttr.getSInt()) {2751      elements.push_back(lhsVec.getElts()[idx]);2752    } else {2753      elements.push_back(rhsVec.getElts()[idx]);2754    }2755  }2756 2757  cir::VectorType vecTy = getLhs().getType();2758  return cir::ConstVectorAttr::get(2759      vecTy, mlir::ArrayAttr::get(getContext(), elements));2760}2761 2762//===----------------------------------------------------------------------===//2763// ComplexCreateOp2764//===----------------------------------------------------------------------===//2765 2766LogicalResult cir::ComplexCreateOp::verify() {2767  if (getType().getElementType() != getReal().getType()) {2768    emitOpError()2769        << "operand type of cir.complex.create does not match its result type";2770    return failure();2771  }2772 2773  return success();2774}2775 2776OpFoldResult cir::ComplexCreateOp::fold(FoldAdaptor adaptor) {2777  mlir::Attribute real = adaptor.getReal();2778  mlir::Attribute imag = adaptor.getImag();2779  if (!real || !imag)2780    return {};2781 2782  // When both of real and imag are constants, we can fold the operation into an2783  // `#cir.const_complex` operation.2784  auto realAttr = mlir::cast<mlir::TypedAttr>(real);2785  auto imagAttr = mlir::cast<mlir::TypedAttr>(imag);2786  return cir::ConstComplexAttr::get(realAttr, imagAttr);2787}2788 2789//===----------------------------------------------------------------------===//2790// ComplexRealOp2791//===----------------------------------------------------------------------===//2792 2793LogicalResult cir::ComplexRealOp::verify() {2794  mlir::Type operandTy = getOperand().getType();2795  if (auto complexOperandTy = mlir::dyn_cast<cir::ComplexType>(operandTy))2796    operandTy = complexOperandTy.getElementType();2797 2798  if (getType() != operandTy) {2799    emitOpError() << ": result type does not match operand type";2800    return failure();2801  }2802 2803  return success();2804}2805 2806OpFoldResult cir::ComplexRealOp::fold(FoldAdaptor adaptor) {2807  if (!mlir::isa<cir::ComplexType>(getOperand().getType()))2808    return nullptr;2809 2810  if (auto complexCreateOp = getOperand().getDefiningOp<cir::ComplexCreateOp>())2811    return complexCreateOp.getOperand(0);2812 2813  auto complex =2814      mlir::cast_if_present<cir::ConstComplexAttr>(adaptor.getOperand());2815  return complex ? complex.getReal() : nullptr;2816}2817 2818//===----------------------------------------------------------------------===//2819// ComplexImagOp2820//===----------------------------------------------------------------------===//2821 2822LogicalResult cir::ComplexImagOp::verify() {2823  mlir::Type operandTy = getOperand().getType();2824  if (auto complexOperandTy = mlir::dyn_cast<cir::ComplexType>(operandTy))2825    operandTy = complexOperandTy.getElementType();2826 2827  if (getType() != operandTy) {2828    emitOpError() << ": result type does not match operand type";2829    return failure();2830  }2831 2832  return success();2833}2834 2835OpFoldResult cir::ComplexImagOp::fold(FoldAdaptor adaptor) {2836  if (!mlir::isa<cir::ComplexType>(getOperand().getType()))2837    return nullptr;2838 2839  if (auto complexCreateOp = getOperand().getDefiningOp<cir::ComplexCreateOp>())2840    return complexCreateOp.getOperand(1);2841 2842  auto complex =2843      mlir::cast_if_present<cir::ConstComplexAttr>(adaptor.getOperand());2844  return complex ? complex.getImag() : nullptr;2845}2846 2847//===----------------------------------------------------------------------===//2848// ComplexRealPtrOp2849//===----------------------------------------------------------------------===//2850 2851LogicalResult cir::ComplexRealPtrOp::verify() {2852  mlir::Type resultPointeeTy = getType().getPointee();2853  cir::PointerType operandPtrTy = getOperand().getType();2854  auto operandPointeeTy =2855      mlir::cast<cir::ComplexType>(operandPtrTy.getPointee());2856 2857  if (resultPointeeTy != operandPointeeTy.getElementType()) {2858    return emitOpError() << ": result type does not match operand type";2859  }2860 2861  return success();2862}2863 2864//===----------------------------------------------------------------------===//2865// ComplexImagPtrOp2866//===----------------------------------------------------------------------===//2867 2868LogicalResult cir::ComplexImagPtrOp::verify() {2869  mlir::Type resultPointeeTy = getType().getPointee();2870  cir::PointerType operandPtrTy = getOperand().getType();2871  auto operandPointeeTy =2872      mlir::cast<cir::ComplexType>(operandPtrTy.getPointee());2873 2874  if (resultPointeeTy != operandPointeeTy.getElementType()) {2875    return emitOpError()2876           << "cir.complex.imag_ptr result type does not match operand type";2877  }2878  return success();2879}2880 2881//===----------------------------------------------------------------------===//2882// Bit manipulation operations2883//===----------------------------------------------------------------------===//2884 2885static OpFoldResult2886foldUnaryBitOp(mlir::Attribute inputAttr,2887               llvm::function_ref<llvm::APInt(const llvm::APInt &)> func,2888               bool poisonZero = false) {2889  if (mlir::isa_and_present<cir::PoisonAttr>(inputAttr)) {2890    // Propagate poison value2891    return inputAttr;2892  }2893 2894  auto input = mlir::dyn_cast_if_present<IntAttr>(inputAttr);2895  if (!input)2896    return nullptr;2897 2898  llvm::APInt inputValue = input.getValue();2899  if (poisonZero && inputValue.isZero())2900    return cir::PoisonAttr::get(input.getType());2901 2902  llvm::APInt resultValue = func(inputValue);2903  return IntAttr::get(input.getType(), resultValue);2904}2905 2906OpFoldResult BitClrsbOp::fold(FoldAdaptor adaptor) {2907  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2908    unsigned resultValue =2909        inputValue.getBitWidth() - inputValue.getSignificantBits();2910    return llvm::APInt(inputValue.getBitWidth(), resultValue);2911  });2912}2913 2914OpFoldResult BitClzOp::fold(FoldAdaptor adaptor) {2915  return foldUnaryBitOp(2916      adaptor.getInput(),2917      [](const llvm::APInt &inputValue) {2918        unsigned resultValue = inputValue.countLeadingZeros();2919        return llvm::APInt(inputValue.getBitWidth(), resultValue);2920      },2921      getPoisonZero());2922}2923 2924OpFoldResult BitCtzOp::fold(FoldAdaptor adaptor) {2925  return foldUnaryBitOp(2926      adaptor.getInput(),2927      [](const llvm::APInt &inputValue) {2928        return llvm::APInt(inputValue.getBitWidth(),2929                           inputValue.countTrailingZeros());2930      },2931      getPoisonZero());2932}2933 2934OpFoldResult BitFfsOp::fold(FoldAdaptor adaptor) {2935  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2936    unsigned trailingZeros = inputValue.countTrailingZeros();2937    unsigned result =2938        trailingZeros == inputValue.getBitWidth() ? 0 : trailingZeros + 1;2939    return llvm::APInt(inputValue.getBitWidth(), result);2940  });2941}2942 2943OpFoldResult BitParityOp::fold(FoldAdaptor adaptor) {2944  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2945    return llvm::APInt(inputValue.getBitWidth(), inputValue.popcount() % 2);2946  });2947}2948 2949OpFoldResult BitPopcountOp::fold(FoldAdaptor adaptor) {2950  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2951    return llvm::APInt(inputValue.getBitWidth(), inputValue.popcount());2952  });2953}2954 2955OpFoldResult BitReverseOp::fold(FoldAdaptor adaptor) {2956  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2957    return inputValue.reverseBits();2958  });2959}2960 2961OpFoldResult ByteSwapOp::fold(FoldAdaptor adaptor) {2962  return foldUnaryBitOp(adaptor.getInput(), [](const llvm::APInt &inputValue) {2963    return inputValue.byteSwap();2964  });2965}2966 2967OpFoldResult RotateOp::fold(FoldAdaptor adaptor) {2968  if (mlir::isa_and_present<cir::PoisonAttr>(adaptor.getInput()) ||2969      mlir::isa_and_present<cir::PoisonAttr>(adaptor.getAmount())) {2970    // Propagate poison values2971    return cir::PoisonAttr::get(getType());2972  }2973 2974  auto input = mlir::dyn_cast_if_present<IntAttr>(adaptor.getInput());2975  auto amount = mlir::dyn_cast_if_present<IntAttr>(adaptor.getAmount());2976  if (!input && !amount)2977    return nullptr;2978 2979  // We could fold cir.rotate even if one of its two operands is not a constant:2980  //   - `cir.rotate left/right %0, 0` could be folded into just %0 even if %02981  //     is not a constant.2982  //   - `cir.rotate left/right 0/0b111...111, %0` could be folded into 0 or2983  //     0b111...111 even if %0 is not a constant.2984 2985  llvm::APInt inputValue;2986  if (input) {2987    inputValue = input.getValue();2988    if (inputValue.isZero() || inputValue.isAllOnes()) {2989      // An input value of all 0s or all 1s will not change after rotation2990      return input;2991    }2992  }2993 2994  uint64_t amountValue;2995  if (amount) {2996    amountValue = amount.getValue().urem(getInput().getType().getWidth());2997    if (amountValue == 0) {2998      // A shift amount of 0 will not change the input value2999      return getInput();3000    }3001  }3002 3003  if (!input || !amount)3004    return nullptr;3005 3006  assert(inputValue.getBitWidth() == getInput().getType().getWidth() &&3007         "input value must have the same bit width as the input type");3008 3009  llvm::APInt resultValue;3010  if (isRotateLeft())3011    resultValue = inputValue.rotl(amountValue);3012  else3013    resultValue = inputValue.rotr(amountValue);3014 3015  return IntAttr::get(input.getContext(), input.getType(), resultValue);3016}3017 3018//===----------------------------------------------------------------------===//3019// InlineAsmOp3020//===----------------------------------------------------------------------===//3021 3022void cir::InlineAsmOp::print(OpAsmPrinter &p) {3023  p << '(' << getAsmFlavor() << ", ";3024  p.increaseIndent();3025  p.printNewline();3026 3027  llvm::SmallVector<std::string, 3> names{"out", "in", "in_out"};3028  auto *nameIt = names.begin();3029  auto *attrIt = getOperandAttrs().begin();3030 3031  for (mlir::OperandRange ops : getAsmOperands()) {3032    p << *nameIt << " = ";3033 3034    p << '[';3035    llvm::interleaveComma(llvm::make_range(ops.begin(), ops.end()), p,3036                          [&](Value value) {3037                            p.printOperand(value);3038                            p << " : " << value.getType();3039                            if (*attrIt)3040                              p << " (maybe_memory)";3041                            attrIt++;3042                          });3043    p << "],";3044    p.printNewline();3045    ++nameIt;3046  }3047 3048  p << "{";3049  p.printString(getAsmString());3050  p << " ";3051  p.printString(getConstraints());3052  p << "}";3053  p.decreaseIndent();3054  p << ')';3055  if (getSideEffects())3056    p << " side_effects";3057 3058  std::array elidedAttrs{3059      llvm::StringRef("asm_flavor"),        llvm::StringRef("asm_string"),3060      llvm::StringRef("constraints"),       llvm::StringRef("operand_attrs"),3061      llvm::StringRef("operands_segments"), llvm::StringRef("side_effects")};3062  p.printOptionalAttrDict(getOperation()->getAttrs(), elidedAttrs);3063 3064  if (auto v = getRes())3065    p << " -> " << v.getType();3066}3067 3068void cir::InlineAsmOp::build(OpBuilder &odsBuilder, OperationState &odsState,3069                             ArrayRef<ValueRange> asmOperands,3070                             StringRef asmString, StringRef constraints,3071                             bool sideEffects, cir::AsmFlavor asmFlavor,3072                             ArrayRef<Attribute> operandAttrs) {3073  // Set up the operands_segments for VariadicOfVariadic3074  SmallVector<int32_t> segments;3075  for (auto operandRange : asmOperands) {3076    segments.push_back(operandRange.size());3077    odsState.addOperands(operandRange);3078  }3079 3080  odsState.addAttribute(3081      "operands_segments",3082      DenseI32ArrayAttr::get(odsBuilder.getContext(), segments));3083  odsState.addAttribute("asm_string", odsBuilder.getStringAttr(asmString));3084  odsState.addAttribute("constraints", odsBuilder.getStringAttr(constraints));3085  odsState.addAttribute("asm_flavor",3086                        AsmFlavorAttr::get(odsBuilder.getContext(), asmFlavor));3087 3088  if (sideEffects)3089    odsState.addAttribute("side_effects", odsBuilder.getUnitAttr());3090 3091  odsState.addAttribute("operand_attrs", odsBuilder.getArrayAttr(operandAttrs));3092}3093 3094ParseResult cir::InlineAsmOp::parse(OpAsmParser &parser,3095                                    OperationState &result) {3096  llvm::SmallVector<mlir::Attribute> operandAttrs;3097  llvm::SmallVector<int32_t> operandsGroupSizes;3098  std::string asmString, constraints;3099  Type resType;3100  MLIRContext *ctxt = parser.getBuilder().getContext();3101 3102  auto error = [&](const Twine &msg) -> LogicalResult {3103    return parser.emitError(parser.getCurrentLocation(), msg);3104  };3105 3106  auto expected = [&](const std::string &c) {3107    return error("expected '" + c + "'");3108  };3109 3110  if (parser.parseLParen().failed())3111    return expected("(");3112 3113  auto flavor = FieldParser<AsmFlavor, AsmFlavor>::parse(parser);3114  if (failed(flavor))3115    return error("Unknown AsmFlavor");3116 3117  if (parser.parseComma().failed())3118    return expected(",");3119 3120  auto parseValue = [&](Value &v) {3121    OpAsmParser::UnresolvedOperand op;3122 3123    if (parser.parseOperand(op) || parser.parseColon())3124      return error("can't parse operand");3125 3126    Type typ;3127    if (parser.parseType(typ).failed())3128      return error("can't parse operand type");3129    llvm::SmallVector<mlir::Value> tmp;3130    if (parser.resolveOperand(op, typ, tmp))3131      return error("can't resolve operand");3132    v = tmp[0];3133    return mlir::success();3134  };3135 3136  auto parseOperands = [&](llvm::StringRef name) {3137    if (parser.parseKeyword(name).failed())3138      return error("expected " + name + " operands here");3139    if (parser.parseEqual().failed())3140      return expected("=");3141    if (parser.parseLSquare().failed())3142      return expected("[");3143 3144    int size = 0;3145    if (parser.parseOptionalRSquare().succeeded()) {3146      operandsGroupSizes.push_back(size);3147      if (parser.parseComma())3148        return expected(",");3149      return mlir::success();3150    }3151 3152    auto parseOperand = [&]() {3153      Value val;3154      if (parseValue(val).succeeded()) {3155        result.operands.push_back(val);3156        size++;3157 3158        if (parser.parseOptionalLParen().failed()) {3159          operandAttrs.push_back(mlir::Attribute());3160          return mlir::success();3161        }3162 3163        if (parser.parseKeyword("maybe_memory").succeeded()) {3164          operandAttrs.push_back(mlir::UnitAttr::get(ctxt));3165          if (parser.parseRParen())3166            return expected(")");3167          return mlir::success();3168        } else {3169          return expected("maybe_memory");3170        }3171      }3172      return mlir::failure();3173    };3174 3175    if (parser.parseCommaSeparatedList(parseOperand).failed())3176      return mlir::failure();3177 3178    if (parser.parseRSquare().failed() || parser.parseComma().failed())3179      return expected("]");3180    operandsGroupSizes.push_back(size);3181    return mlir::success();3182  };3183 3184  if (parseOperands("out").failed() || parseOperands("in").failed() ||3185      parseOperands("in_out").failed())3186    return error("failed to parse operands");3187 3188  if (parser.parseLBrace())3189    return expected("{");3190  if (parser.parseString(&asmString))3191    return error("asm string parsing failed");3192  if (parser.parseString(&constraints))3193    return error("constraints string parsing failed");3194  if (parser.parseRBrace())3195    return expected("}");3196  if (parser.parseRParen())3197    return expected(")");3198 3199  if (parser.parseOptionalKeyword("side_effects").succeeded())3200    result.attributes.set("side_effects", UnitAttr::get(ctxt));3201 3202  if (parser.parseOptionalArrow().succeeded() &&3203      parser.parseType(resType).failed())3204    return mlir::failure();3205 3206  if (parser.parseOptionalAttrDict(result.attributes).failed())3207    return mlir::failure();3208 3209  result.attributes.set("asm_flavor", AsmFlavorAttr::get(ctxt, *flavor));3210  result.attributes.set("asm_string", StringAttr::get(ctxt, asmString));3211  result.attributes.set("constraints", StringAttr::get(ctxt, constraints));3212  result.attributes.set("operand_attrs", ArrayAttr::get(ctxt, operandAttrs));3213  result.getOrAddProperties<InlineAsmOp::Properties>().operands_segments =3214      parser.getBuilder().getDenseI32ArrayAttr(operandsGroupSizes);3215  if (resType)3216    result.addTypes(TypeRange{resType});3217 3218  return mlir::success();3219}3220 3221//===----------------------------------------------------------------------===//3222// ThrowOp3223//===----------------------------------------------------------------------===//3224 3225mlir::LogicalResult cir::ThrowOp::verify() {3226  // For the no-rethrow version, it must have at least the exception pointer.3227  if (rethrows())3228    return success();3229 3230  if (getNumOperands() != 0) {3231    if (getTypeInfo())3232      return success();3233    return emitOpError() << "'type_info' symbol attribute missing";3234  }3235 3236  return failure();3237}3238 3239//===----------------------------------------------------------------------===//3240// AtomicFetchOp3241//===----------------------------------------------------------------------===//3242 3243LogicalResult cir::AtomicFetchOp::verify() {3244  if (getBinop() != cir::AtomicFetchKind::Add &&3245      getBinop() != cir::AtomicFetchKind::Sub &&3246      getBinop() != cir::AtomicFetchKind::Max &&3247      getBinop() != cir::AtomicFetchKind::Min &&3248      !mlir::isa<cir::IntType>(getVal().getType()))3249    return emitError("only atomic add, sub, max, and min operation could "3250                     "operate on floating-point values");3251  return success();3252}3253 3254//===----------------------------------------------------------------------===//3255// TypeInfoAttr3256//===----------------------------------------------------------------------===//3257 3258LogicalResult cir::TypeInfoAttr::verify(3259    ::llvm::function_ref<::mlir::InFlightDiagnostic()> emitError,3260    ::mlir::Type type, ::mlir::ArrayAttr typeInfoData) {3261 3262  if (cir::ConstRecordAttr::verify(emitError, type, typeInfoData).failed())3263    return failure();3264 3265  return success();3266}3267 3268//===----------------------------------------------------------------------===//3269// TryOp3270//===----------------------------------------------------------------------===//3271 3272void cir::TryOp::getSuccessorRegions(3273    mlir::RegionBranchPoint point,3274    llvm::SmallVectorImpl<mlir::RegionSuccessor> &regions) {3275  // The `try` and the `catchers` region branch back to the parent operation.3276  if (!point.isParent()) {3277    regions.push_back(3278        RegionSuccessor(getOperation(), getOperation()->getResults()));3279    return;3280  }3281 3282  regions.push_back(mlir::RegionSuccessor(&getTryRegion()));3283 3284  // TODO(CIR): If we know a target function never throws a specific type, we3285  // can remove the catch handler.3286  for (mlir::Region &handlerRegion : this->getHandlerRegions())3287    regions.push_back(mlir::RegionSuccessor(&handlerRegion));3288}3289 3290static void3291printTryHandlerRegions(mlir::OpAsmPrinter &printer, cir::TryOp op,3292                       mlir::MutableArrayRef<mlir::Region> handlerRegions,3293                       mlir::ArrayAttr handlerTypes) {3294  if (!handlerTypes)3295    return;3296 3297  for (const auto [typeIdx, typeAttr] : llvm::enumerate(handlerTypes)) {3298    if (typeIdx)3299      printer << " ";3300 3301    if (mlir::isa<cir::CatchAllAttr>(typeAttr)) {3302      printer << "catch all ";3303    } else if (mlir::isa<cir::UnwindAttr>(typeAttr)) {3304      printer << "unwind ";3305    } else {3306      printer << "catch [type ";3307      printer.printAttribute(typeAttr);3308      printer << "] ";3309    }3310 3311    printer.printRegion(handlerRegions[typeIdx],3312                        /*printEntryBLockArgs=*/false,3313                        /*printBlockTerminators=*/true);3314  }3315}3316 3317static mlir::ParseResult parseTryHandlerRegions(3318    mlir::OpAsmParser &parser,3319    llvm::SmallVectorImpl<std::unique_ptr<mlir::Region>> &handlerRegions,3320    mlir::ArrayAttr &handlerTypes) {3321 3322  auto parseCheckedCatcherRegion = [&]() -> mlir::ParseResult {3323    handlerRegions.emplace_back(new mlir::Region);3324 3325    mlir::Region &currRegion = *handlerRegions.back();3326    mlir::SMLoc regionLoc = parser.getCurrentLocation();3327    if (parser.parseRegion(currRegion)) {3328      handlerRegions.clear();3329      return failure();3330    }3331 3332    if (currRegion.empty())3333      return parser.emitError(regionLoc, "handler region shall not be empty");3334 3335    if (!(currRegion.back().mightHaveTerminator() &&3336          currRegion.back().getTerminator()))3337      return parser.emitError(3338          regionLoc, "blocks are expected to be explicitly terminated");3339 3340    return success();3341  };3342 3343  bool hasCatchAll = false;3344  llvm::SmallVector<mlir::Attribute, 4> catcherAttrs;3345  while (parser.parseOptionalKeyword("catch").succeeded()) {3346    bool hasLSquare = parser.parseOptionalLSquare().succeeded();3347 3348    llvm::StringRef attrStr;3349    if (parser.parseOptionalKeyword(&attrStr, {"all", "type"}).failed())3350      return parser.emitError(parser.getCurrentLocation(),3351                              "expected 'all' or 'type' keyword");3352 3353    bool isCatchAll = attrStr == "all";3354    if (isCatchAll) {3355      if (hasCatchAll)3356        return parser.emitError(parser.getCurrentLocation(),3357                                "can't have more than one catch all");3358      hasCatchAll = true;3359    }3360 3361    mlir::Attribute exceptionRTTIAttr;3362    if (!isCatchAll && parser.parseAttribute(exceptionRTTIAttr).failed())3363      return parser.emitError(parser.getCurrentLocation(),3364                              "expected valid RTTI info attribute");3365 3366    catcherAttrs.push_back(isCatchAll3367                               ? cir::CatchAllAttr::get(parser.getContext())3368                               : exceptionRTTIAttr);3369 3370    if (hasLSquare && isCatchAll)3371      return parser.emitError(parser.getCurrentLocation(),3372                              "catch all dosen't need RTTI info attribute");3373 3374    if (hasLSquare && parser.parseRSquare().failed())3375      return parser.emitError(parser.getCurrentLocation(),3376                              "expected `]` after RTTI info attribute");3377 3378    if (parseCheckedCatcherRegion().failed())3379      return mlir::failure();3380  }3381 3382  if (parser.parseOptionalKeyword("unwind").succeeded()) {3383    if (hasCatchAll)3384      return parser.emitError(parser.getCurrentLocation(),3385                              "unwind can't be used with catch all");3386 3387    catcherAttrs.push_back(cir::UnwindAttr::get(parser.getContext()));3388    if (parseCheckedCatcherRegion().failed())3389      return mlir::failure();3390  }3391 3392  handlerTypes = parser.getBuilder().getArrayAttr(catcherAttrs);3393  return mlir::success();3394}3395 3396//===----------------------------------------------------------------------===//3397// TableGen'd op method definitions3398//===----------------------------------------------------------------------===//3399 3400#define GET_OP_CLASSES3401#include "clang/CIR/Dialect/IR/CIROps.cpp.inc"3402