brintos

brintos / llvm-project-archived public Read only

0
0
Text · 165.6 KiB · 0c34d87 Raw
4129 lines · cpp
1//====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===//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 lowering of CIR operations to LLVMIR.10//11//===----------------------------------------------------------------------===//12 13#include "LowerToLLVM.h"14 15#include <deque>16#include <optional>17 18#include "mlir/Conversion/LLVMCommon/TypeConverter.h"19#include "mlir/Dialect/DLTI/DLTI.h"20#include "mlir/Dialect/Func/IR/FuncOps.h"21#include "mlir/Dialect/LLVMIR/LLVMDialect.h"22#include "mlir/Dialect/LLVMIR/LLVMTypes.h"23#include "mlir/IR/BuiltinAttributes.h"24#include "mlir/IR/BuiltinDialect.h"25#include "mlir/IR/BuiltinOps.h"26#include "mlir/IR/Types.h"27#include "mlir/Pass/Pass.h"28#include "mlir/Pass/PassManager.h"29#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"30#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"31#include "mlir/Target/LLVMIR/Export.h"32#include "mlir/Transforms/DialectConversion.h"33#include "clang/CIR/Dialect/IR/CIRAttrs.h"34#include "clang/CIR/Dialect/IR/CIRDialect.h"35#include "clang/CIR/Dialect/IR/CIRTypes.h"36#include "clang/CIR/Dialect/Passes.h"37#include "clang/CIR/LoweringHelpers.h"38#include "clang/CIR/MissingFeatures.h"39#include "clang/CIR/Passes.h"40#include "llvm/ADT/TypeSwitch.h"41#include "llvm/IR/Module.h"42#include "llvm/Support/ErrorHandling.h"43#include "llvm/Support/TimeProfiler.h"44 45using namespace cir;46using namespace llvm;47 48namespace cir {49namespace direct {50 51//===----------------------------------------------------------------------===//52// Helper Methods53//===----------------------------------------------------------------------===//54 55namespace {56/// If the given type is a vector type, return the vector's element type.57/// Otherwise return the given type unchanged.58mlir::Type elementTypeIfVector(mlir::Type type) {59  return llvm::TypeSwitch<mlir::Type, mlir::Type>(type)60      .Case<cir::VectorType, mlir::VectorType>(61          [](auto p) { return p.getElementType(); })62      .Default([](mlir::Type p) { return p; });63}64} // namespace65 66/// Given a type convertor and a data layout, convert the given type to a type67/// that is suitable for memory operations. For example, this can be used to68/// lower cir.bool accesses to i8.69static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,70                                       mlir::DataLayout const &dataLayout,71                                       mlir::Type type) {72  // TODO(cir): Handle other types similarly to clang's codegen73  // convertTypeForMemory74  if (isa<cir::BoolType>(type)) {75    return mlir::IntegerType::get(type.getContext(),76                                  dataLayout.getTypeSizeInBits(type));77  }78 79  return converter.convertType(type);80}81 82static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,83                                 mlir::IntegerType dstTy,84                                 bool isSigned = false) {85  mlir::Type srcTy = src.getType();86  assert(mlir::isa<mlir::IntegerType>(srcTy));87 88  unsigned srcWidth = mlir::cast<mlir::IntegerType>(srcTy).getWidth();89  unsigned dstWidth = mlir::cast<mlir::IntegerType>(dstTy).getWidth();90  mlir::Location loc = src.getLoc();91 92  if (dstWidth > srcWidth && isSigned)93    return mlir::LLVM::SExtOp::create(bld, loc, dstTy, src);94  if (dstWidth > srcWidth)95    return mlir::LLVM::ZExtOp::create(bld, loc, dstTy, src);96  if (dstWidth < srcWidth)97    return mlir::LLVM::TruncOp::create(bld, loc, dstTy, src);98  return mlir::LLVM::BitcastOp::create(bld, loc, dstTy, src);99}100 101static mlir::LLVM::Visibility102lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) {103  switch (visibilityKind) {104  case cir::VisibilityKind::Default:105    return ::mlir::LLVM::Visibility::Default;106  case cir::VisibilityKind::Hidden:107    return ::mlir::LLVM::Visibility::Hidden;108  case cir::VisibilityKind::Protected:109    return ::mlir::LLVM::Visibility::Protected;110  }111}112 113/// Emits the value from memory as expected by its users. Should be called when114/// the memory represetnation of a CIR type is not equal to its scalar115/// representation.116static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,117                                  mlir::DataLayout const &dataLayout,118                                  cir::LoadOp op, mlir::Value value) {119 120  // TODO(cir): Handle other types similarly to clang's codegen EmitFromMemory121  if (auto boolTy = mlir::dyn_cast<cir::BoolType>(op.getType())) {122    // Create a cast value from specified size in datalayout to i1123    assert(value.getType().isInteger(dataLayout.getTypeSizeInBits(boolTy)));124    return createIntCast(rewriter, value, rewriter.getI1Type());125  }126 127  return value;128}129 130/// Emits a value to memory with the expected scalar type. Should be called when131/// the memory represetnation of a CIR type is not equal to its scalar132/// representation.133static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,134                                mlir::DataLayout const &dataLayout,135                                mlir::Type origType, mlir::Value value) {136 137  // TODO(cir): Handle other types similarly to clang's codegen EmitToMemory138  if (auto boolTy = mlir::dyn_cast<cir::BoolType>(origType)) {139    // Create zext of value from i1 to i8140    mlir::IntegerType memType =141        rewriter.getIntegerType(dataLayout.getTypeSizeInBits(boolTy));142    return createIntCast(rewriter, value, memType);143  }144 145  return value;146}147 148mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {149  using CIR = cir::GlobalLinkageKind;150  using LLVM = mlir::LLVM::Linkage;151 152  switch (linkage) {153  case CIR::AvailableExternallyLinkage:154    return LLVM::AvailableExternally;155  case CIR::CommonLinkage:156    return LLVM::Common;157  case CIR::ExternalLinkage:158    return LLVM::External;159  case CIR::ExternalWeakLinkage:160    return LLVM::ExternWeak;161  case CIR::InternalLinkage:162    return LLVM::Internal;163  case CIR::LinkOnceAnyLinkage:164    return LLVM::Linkonce;165  case CIR::LinkOnceODRLinkage:166    return LLVM::LinkonceODR;167  case CIR::PrivateLinkage:168    return LLVM::Private;169  case CIR::WeakAnyLinkage:170    return LLVM::Weak;171  case CIR::WeakODRLinkage:172    return LLVM::WeakODR;173  };174  llvm_unreachable("Unknown CIR linkage type");175}176 177mlir::LogicalResult CIRToLLVMCopyOpLowering::matchAndRewrite(178    cir::CopyOp op, OpAdaptor adaptor,179    mlir::ConversionPatternRewriter &rewriter) const {180  mlir::DataLayout layout(op->getParentOfType<mlir::ModuleOp>());181  const mlir::Value length = mlir::LLVM::ConstantOp::create(182      rewriter, op.getLoc(), rewriter.getI32Type(), op.getLength(layout));183  assert(!cir::MissingFeatures::aggValueSlotVolatile());184  rewriter.replaceOpWithNewOp<mlir::LLVM::MemcpyOp>(185      op, adaptor.getDst(), adaptor.getSrc(), length, op.getIsVolatile());186  return mlir::success();187}188 189mlir::LogicalResult CIRToLLVMCosOpLowering::matchAndRewrite(190    cir::CosOp op, OpAdaptor adaptor,191    mlir::ConversionPatternRewriter &rewriter) const {192  mlir::Type resTy = typeConverter->convertType(op.getType());193  rewriter.replaceOpWithNewOp<mlir::LLVM::CosOp>(op, resTy, adaptor.getSrc());194  return mlir::success();195}196 197mlir::LogicalResult CIRToLLVMExpOpLowering::matchAndRewrite(198    cir::ExpOp op, OpAdaptor adaptor,199    mlir::ConversionPatternRewriter &rewriter) const {200  mlir::Type resTy = typeConverter->convertType(op.getType());201  rewriter.replaceOpWithNewOp<mlir::LLVM::ExpOp>(op, resTy, adaptor.getSrc());202  return mlir::success();203}204 205mlir::LogicalResult CIRToLLVMExp2OpLowering::matchAndRewrite(206    cir::Exp2Op op, OpAdaptor adaptor,207    mlir::ConversionPatternRewriter &rewriter) const {208  mlir::Type resTy = typeConverter->convertType(op.getType());209  rewriter.replaceOpWithNewOp<mlir::LLVM::Exp2Op>(op, resTy, adaptor.getSrc());210  return mlir::success();211}212 213static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,214                                  mlir::Value llvmSrc, mlir::Type llvmDstIntTy,215                                  bool isUnsigned, uint64_t cirSrcWidth,216                                  uint64_t cirDstIntWidth) {217  if (cirSrcWidth == cirDstIntWidth)218    return llvmSrc;219 220  auto loc = llvmSrc.getLoc();221  if (cirSrcWidth < cirDstIntWidth) {222    if (isUnsigned)223      return mlir::LLVM::ZExtOp::create(rewriter, loc, llvmDstIntTy, llvmSrc);224    return mlir::LLVM::SExtOp::create(rewriter, loc, llvmDstIntTy, llvmSrc);225  }226 227  // Otherwise truncate228  return mlir::LLVM::TruncOp::create(rewriter, loc, llvmDstIntTy, llvmSrc);229}230 231class CIRAttrToValue {232public:233  CIRAttrToValue(mlir::Operation *parentOp,234                 mlir::ConversionPatternRewriter &rewriter,235                 const mlir::TypeConverter *converter)236      : parentOp(parentOp), rewriter(rewriter), converter(converter) {}237 238  mlir::Value visit(mlir::Attribute attr) {239    return llvm::TypeSwitch<mlir::Attribute, mlir::Value>(attr)240        .Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr,241              cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,242              cir::ConstPtrAttr, cir::GlobalViewAttr, cir::TypeInfoAttr,243              cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(244            [&](auto attrT) { return visitCirAttr(attrT); })245        .Default([&](auto attrT) { return mlir::Value(); });246  }247 248  mlir::Value visitCirAttr(cir::IntAttr intAttr);249  mlir::Value visitCirAttr(cir::FPAttr fltAttr);250  mlir::Value visitCirAttr(cir::ConstComplexAttr complexAttr);251  mlir::Value visitCirAttr(cir::ConstPtrAttr ptrAttr);252  mlir::Value visitCirAttr(cir::ConstArrayAttr attr);253  mlir::Value visitCirAttr(cir::ConstRecordAttr attr);254  mlir::Value visitCirAttr(cir::ConstVectorAttr attr);255  mlir::Value visitCirAttr(cir::GlobalViewAttr attr);256  mlir::Value visitCirAttr(cir::TypeInfoAttr attr);257  mlir::Value visitCirAttr(cir::UndefAttr attr);258  mlir::Value visitCirAttr(cir::VTableAttr attr);259  mlir::Value visitCirAttr(cir::ZeroAttr attr);260 261private:262  mlir::Operation *parentOp;263  mlir::ConversionPatternRewriter &rewriter;264  const mlir::TypeConverter *converter;265};266 267/// Switches on the type of attribute and calls the appropriate conversion.268mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,269                                const mlir::Attribute attr,270                                mlir::ConversionPatternRewriter &rewriter,271                                const mlir::TypeConverter *converter) {272  CIRAttrToValue valueConverter(parentOp, rewriter, converter);273  mlir::Value value = valueConverter.visit(attr);274  if (!value)275    llvm_unreachable("unhandled attribute type");276  return value;277}278 279void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,280                              cir::SideEffect sideEffect,281                              mlir::LLVM::MemoryEffectsAttr &memoryEffect,282                              bool &noUnwind, bool &willReturn) {283  using mlir::LLVM::ModRefInfo;284 285  switch (sideEffect) {286  case cir::SideEffect::All:287    memoryEffect = {};288    noUnwind = isNothrow;289    willReturn = false;290    break;291 292  case cir::SideEffect::Pure:293    memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(294        callOp->getContext(), /*other=*/ModRefInfo::Ref,295        /*argMem=*/ModRefInfo::Ref,296        /*inaccessibleMem=*/ModRefInfo::Ref,297        /*errnoMem=*/ModRefInfo::Ref,298        /*targetMem0=*/ModRefInfo::Ref,299        /*targetMem1=*/ModRefInfo::Ref);300    noUnwind = true;301    willReturn = true;302    break;303 304  case cir::SideEffect::Const:305    memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(306        callOp->getContext(), /*other=*/ModRefInfo::NoModRef,307        /*argMem=*/ModRefInfo::NoModRef,308        /*inaccessibleMem=*/ModRefInfo::NoModRef,309        /*errnoMem=*/ModRefInfo::NoModRef,310        /*targetMem0=*/ModRefInfo::NoModRef,311        /*targetMem1=*/ModRefInfo::NoModRef);312    noUnwind = true;313    willReturn = true;314    break;315  }316}317 318static mlir::LLVM::CallIntrinsicOp319createCallLLVMIntrinsicOp(mlir::ConversionPatternRewriter &rewriter,320                          mlir::Location loc, const llvm::Twine &intrinsicName,321                          mlir::Type resultTy, mlir::ValueRange operands) {322  auto intrinsicNameAttr =323      mlir::StringAttr::get(rewriter.getContext(), intrinsicName);324  return mlir::LLVM::CallIntrinsicOp::create(rewriter, loc, resultTy,325                                             intrinsicNameAttr, operands);326}327 328static mlir::LLVM::CallIntrinsicOp replaceOpWithCallLLVMIntrinsicOp(329    mlir::ConversionPatternRewriter &rewriter, mlir::Operation *op,330    const llvm::Twine &intrinsicName, mlir::Type resultTy,331    mlir::ValueRange operands) {332  mlir::LLVM::CallIntrinsicOp callIntrinOp = createCallLLVMIntrinsicOp(333      rewriter, op->getLoc(), intrinsicName, resultTy, operands);334  rewriter.replaceOp(op, callIntrinOp.getOperation());335  return callIntrinOp;336}337 338mlir::LogicalResult CIRToLLVMLLVMIntrinsicCallOpLowering::matchAndRewrite(339    cir::LLVMIntrinsicCallOp op, OpAdaptor adaptor,340    mlir::ConversionPatternRewriter &rewriter) const {341  mlir::Type llvmResTy =342      getTypeConverter()->convertType(op->getResultTypes()[0]);343  if (!llvmResTy)344    return op.emitError("expected LLVM result type");345  StringRef name = op.getIntrinsicName();346 347  // Some LLVM intrinsics require ElementType attribute to be attached to348  // the argument of pointer type. That prevents us from generating LLVM IR349  // because from LLVM dialect, we have LLVM IR like the below which fails350  // LLVM IR verification.351  // %3 = call i64 @llvm.aarch64.ldxr.p0(ptr %2)352  // The expected LLVM IR should be like353  // %3 = call i64 @llvm.aarch64.ldxr.p0(ptr elementtype(i32) %2)354  // TODO(cir): MLIR LLVM dialect should handle this part as CIR has no way355  // to set LLVM IR attribute.356  assert(!cir::MissingFeatures::intrinsicElementTypeSupport());357  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm." + name, llvmResTy,358                                   adaptor.getOperands());359  return mlir::success();360}361 362/// IntAttr visitor.363mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {364  mlir::Location loc = parentOp->getLoc();365  return mlir::LLVM::ConstantOp::create(366      rewriter, loc, converter->convertType(intAttr.getType()),367      intAttr.getValue());368}369 370/// FPAttr visitor.371mlir::Value CIRAttrToValue::visitCirAttr(cir::FPAttr fltAttr) {372  mlir::Location loc = parentOp->getLoc();373  return mlir::LLVM::ConstantOp::create(374      rewriter, loc, converter->convertType(fltAttr.getType()),375      fltAttr.getValue());376}377 378/// ConstComplexAttr visitor.379mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstComplexAttr complexAttr) {380  auto complexType = mlir::cast<cir::ComplexType>(complexAttr.getType());381  mlir::Type complexElemTy = complexType.getElementType();382  mlir::Type complexElemLLVMTy = converter->convertType(complexElemTy);383 384  mlir::Attribute components[2];385  if (const auto intType = mlir::dyn_cast<cir::IntType>(complexElemTy)) {386    components[0] = rewriter.getIntegerAttr(387        complexElemLLVMTy,388        mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());389    components[1] = rewriter.getIntegerAttr(390        complexElemLLVMTy,391        mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());392  } else {393    components[0] = rewriter.getFloatAttr(394        complexElemLLVMTy,395        mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());396    components[1] = rewriter.getFloatAttr(397        complexElemLLVMTy,398        mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());399  }400 401  mlir::Location loc = parentOp->getLoc();402  return mlir::LLVM::ConstantOp::create(403      rewriter, loc, converter->convertType(complexAttr.getType()),404      rewriter.getArrayAttr(components));405}406 407/// ConstPtrAttr visitor.408mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstPtrAttr ptrAttr) {409  mlir::Location loc = parentOp->getLoc();410  if (ptrAttr.isNullValue()) {411    return mlir::LLVM::ZeroOp::create(412        rewriter, loc, converter->convertType(ptrAttr.getType()));413  }414  mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());415  mlir::Value ptrVal = mlir::LLVM::ConstantOp::create(416      rewriter, loc,417      rewriter.getIntegerType(layout.getTypeSizeInBits(ptrAttr.getType())),418      ptrAttr.getValue().getInt());419  return mlir::LLVM::IntToPtrOp::create(420      rewriter, loc, converter->convertType(ptrAttr.getType()), ptrVal);421}422 423// ConstArrayAttr visitor424mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {425  mlir::Type llvmTy = converter->convertType(attr.getType());426  mlir::Location loc = parentOp->getLoc();427  mlir::Value result;428 429  if (attr.hasTrailingZeros()) {430    mlir::Type arrayTy = attr.getType();431    result = mlir::LLVM::ZeroOp::create(rewriter, loc,432                                        converter->convertType(arrayTy));433  } else {434    result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);435  }436 437  // Iteratively lower each constant element of the array.438  if (auto arrayAttr = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts())) {439    for (auto [idx, elt] : llvm::enumerate(arrayAttr)) {440      mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());441      mlir::Value init = visit(elt);442      result =443          mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);444    }445  } else if (auto strAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) {446    // TODO(cir): this diverges from traditional lowering. Normally the string447    // would be a global constant that is memcopied.448    auto arrayTy = mlir::dyn_cast<cir::ArrayType>(strAttr.getType());449    assert(arrayTy && "String attribute must have an array type");450    mlir::Type eltTy = arrayTy.getElementType();451    for (auto [idx, elt] : llvm::enumerate(strAttr)) {452      auto init = mlir::LLVM::ConstantOp::create(453          rewriter, loc, converter->convertType(eltTy), elt);454      result =455          mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);456    }457  } else {458    llvm_unreachable("unexpected ConstArrayAttr elements");459  }460 461  return result;462}463 464/// ConstRecord visitor.465mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstRecordAttr constRecord) {466  const mlir::Type llvmTy = converter->convertType(constRecord.getType());467  const mlir::Location loc = parentOp->getLoc();468  mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);469 470  // Iteratively lower each constant element of the record.471  for (auto [idx, elt] : llvm::enumerate(constRecord.getMembers())) {472    mlir::Value init = visit(elt);473    result =474        mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);475  }476 477  return result;478}479 480/// ConstVectorAttr visitor.481mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstVectorAttr attr) {482  const mlir::Type llvmTy = converter->convertType(attr.getType());483  const mlir::Location loc = parentOp->getLoc();484 485  SmallVector<mlir::Attribute> mlirValues;486  for (const mlir::Attribute elementAttr : attr.getElts()) {487    mlir::Attribute mlirAttr;488    if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(elementAttr)) {489      mlirAttr = rewriter.getIntegerAttr(490          converter->convertType(intAttr.getType()), intAttr.getValue());491    } else if (auto floatAttr = mlir::dyn_cast<cir::FPAttr>(elementAttr)) {492      mlirAttr = rewriter.getFloatAttr(493          converter->convertType(floatAttr.getType()), floatAttr.getValue());494    } else {495      llvm_unreachable(496          "vector constant with an element that is neither an int nor a float");497    }498    mlirValues.push_back(mlirAttr);499  }500 501  return mlir::LLVM::ConstantOp::create(502      rewriter, loc, llvmTy,503      mlir::DenseElementsAttr::get(mlir::cast<mlir::ShapedType>(llvmTy),504                                   mlirValues));505}506 507// GlobalViewAttr visitor.508mlir::Value CIRAttrToValue::visitCirAttr(cir::GlobalViewAttr globalAttr) {509  auto moduleOp = parentOp->getParentOfType<mlir::ModuleOp>();510  mlir::DataLayout dataLayout(moduleOp);511  mlir::Type sourceType;512  assert(!cir::MissingFeatures::addressSpace());513  llvm::StringRef symName;514  mlir::Operation *sourceSymbol =515      mlir::SymbolTable::lookupSymbolIn(moduleOp, globalAttr.getSymbol());516  if (auto llvmSymbol = dyn_cast<mlir::LLVM::GlobalOp>(sourceSymbol)) {517    sourceType = llvmSymbol.getType();518    symName = llvmSymbol.getSymName();519  } else if (auto cirSymbol = dyn_cast<cir::GlobalOp>(sourceSymbol)) {520    sourceType =521        convertTypeForMemory(*converter, dataLayout, cirSymbol.getSymType());522    symName = cirSymbol.getSymName();523  } else if (auto llvmFun = dyn_cast<mlir::LLVM::LLVMFuncOp>(sourceSymbol)) {524    sourceType = llvmFun.getFunctionType();525    symName = llvmFun.getSymName();526  } else if (auto fun = dyn_cast<cir::FuncOp>(sourceSymbol)) {527    sourceType = converter->convertType(fun.getFunctionType());528    symName = fun.getSymName();529  } else if (auto alias = dyn_cast<mlir::LLVM::AliasOp>(sourceSymbol)) {530    sourceType = alias.getType();531    symName = alias.getSymName();532  } else {533    llvm_unreachable("Unexpected GlobalOp type");534  }535 536  mlir::Location loc = parentOp->getLoc();537  mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(538      rewriter, loc, mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),539      symName);540 541  if (globalAttr.getIndices()) {542    llvm::SmallVector<mlir::LLVM::GEPArg> indices;543 544    if (mlir::isa<mlir::LLVM::LLVMArrayType, mlir::LLVM::LLVMStructType>(545            sourceType))546      indices.push_back(0);547 548    for (mlir::Attribute idx : globalAttr.getIndices()) {549      auto intAttr = mlir::cast<mlir::IntegerAttr>(idx);550      indices.push_back(intAttr.getValue().getSExtValue());551    }552    mlir::Type resTy = addrOp.getType();553    mlir::Type eltTy = converter->convertType(sourceType);554    addrOp =555        mlir::LLVM::GEPOp::create(rewriter, loc, resTy, eltTy, addrOp, indices,556                                  mlir::LLVM::GEPNoWrapFlags::none);557  }558 559  // The incubator has handling here for the attribute having integer type, but560  // the only test case I could find that reaches it is a direct CIR-to-LLVM IR561  // lowering with no clear indication of how the CIR might have been generated.562  // We'll hit the unreachable below if this happens.563  assert(!cir::MissingFeatures::globalViewIntLowering());564 565  if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(globalAttr.getType())) {566    mlir::Type llvmEltTy =567        convertTypeForMemory(*converter, dataLayout, ptrTy.getPointee());568 569    if (llvmEltTy == sourceType)570      return addrOp;571 572    mlir::Type llvmDstTy = converter->convertType(globalAttr.getType());573    return mlir::LLVM::BitcastOp::create(rewriter, parentOp->getLoc(),574                                         llvmDstTy, addrOp);575  }576 577  llvm_unreachable("Expecting pointer or integer type for GlobalViewAttr");578}579 580// TypeInfoAttr visitor.581mlir::Value CIRAttrToValue::visitCirAttr(cir::TypeInfoAttr typeInfoAttr) {582  mlir::Type llvmTy = converter->convertType(typeInfoAttr.getType());583  mlir::Location loc = parentOp->getLoc();584  mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);585 586  for (auto [idx, elt] : llvm::enumerate(typeInfoAttr.getData())) {587    mlir::Value init = visit(elt);588    result =589        mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);590  }591 592  return result;593}594 595/// UndefAttr visitor.596mlir::Value CIRAttrToValue::visitCirAttr(cir::UndefAttr undefAttr) {597  mlir::Location loc = parentOp->getLoc();598  return mlir::LLVM::UndefOp::create(599      rewriter, loc, converter->convertType(undefAttr.getType()));600}601 602// VTableAttr visitor.603mlir::Value CIRAttrToValue::visitCirAttr(cir::VTableAttr vtableArr) {604  mlir::Type llvmTy = converter->convertType(vtableArr.getType());605  mlir::Location loc = parentOp->getLoc();606  mlir::Value result = mlir::LLVM::UndefOp::create(rewriter, loc, llvmTy);607 608  for (auto [idx, elt] : llvm::enumerate(vtableArr.getData())) {609    mlir::Value init = visit(elt);610    result =611        mlir::LLVM::InsertValueOp::create(rewriter, loc, result, init, idx);612  }613 614  return result;615}616 617/// ZeroAttr visitor.618mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr attr) {619  mlir::Location loc = parentOp->getLoc();620  return mlir::LLVM::ZeroOp::create(rewriter, loc,621                                    converter->convertType(attr.getType()));622}623 624// This class handles rewriting initializer attributes for types that do not625// require region initialization.626class GlobalInitAttrRewriter {627public:628  GlobalInitAttrRewriter(mlir::Type type,629                         mlir::ConversionPatternRewriter &rewriter)630      : llvmType(type), rewriter(rewriter) {}631 632  mlir::Attribute visit(mlir::Attribute attr) {633    return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)634        .Case<cir::IntAttr, cir::FPAttr, cir::BoolAttr>(635            [&](auto attrT) { return visitCirAttr(attrT); })636        .Default([&](auto attrT) { return mlir::Attribute(); });637  }638 639  mlir::Attribute visitCirAttr(cir::IntAttr attr) {640    return rewriter.getIntegerAttr(llvmType, attr.getValue());641  }642 643  mlir::Attribute visitCirAttr(cir::FPAttr attr) {644    return rewriter.getFloatAttr(llvmType, attr.getValue());645  }646 647  mlir::Attribute visitCirAttr(cir::BoolAttr attr) {648    return rewriter.getBoolAttr(attr.getValue());649  }650 651private:652  mlir::Type llvmType;653  mlir::ConversionPatternRewriter &rewriter;654};655 656// This pass requires the CIR to be in a "flat" state. All blocks in each657// function must belong to the parent region. Once scopes and control flow658// are implemented in CIR, a pass will be run before this one to flatten659// the CIR and get it into the state that this pass requires.660struct ConvertCIRToLLVMPass661    : public mlir::PassWrapper<ConvertCIRToLLVMPass,662                               mlir::OperationPass<mlir::ModuleOp>> {663  void getDependentDialects(mlir::DialectRegistry &registry) const override {664    registry.insert<mlir::BuiltinDialect, mlir::DLTIDialect,665                    mlir::LLVM::LLVMDialect, mlir::func::FuncDialect>();666  }667  void runOnOperation() final;668 669  void processCIRAttrs(mlir::ModuleOp module);670 671  StringRef getDescription() const override {672    return "Convert the prepared CIR dialect module to LLVM dialect";673  }674 675  StringRef getArgument() const override { return "cir-flat-to-llvm"; }676};677 678mlir::LogicalResult CIRToLLVMACosOpLowering::matchAndRewrite(679    cir::ACosOp op, OpAdaptor adaptor,680    mlir::ConversionPatternRewriter &rewriter) const {681  mlir::Type resTy = typeConverter->convertType(op.getType());682  rewriter.replaceOpWithNewOp<mlir::LLVM::ACosOp>(op, resTy,683                                                  adaptor.getOperands()[0]);684  return mlir::success();685}686 687mlir::LogicalResult CIRToLLVMASinOpLowering::matchAndRewrite(688    cir::ASinOp op, OpAdaptor adaptor,689    mlir::ConversionPatternRewriter &rewriter) const {690  mlir::Type resTy = typeConverter->convertType(op.getType());691  rewriter.replaceOpWithNewOp<mlir::LLVM::ASinOp>(op, resTy, adaptor.getSrc());692  return mlir::success();693}694 695mlir::LogicalResult CIRToLLVMIsFPClassOpLowering::matchAndRewrite(696    cir::IsFPClassOp op, OpAdaptor adaptor,697    mlir::ConversionPatternRewriter &rewriter) const {698  mlir::Value src = adaptor.getSrc();699  cir::FPClassTest flags = adaptor.getFlags();700  mlir::IntegerType retTy = rewriter.getI1Type();701 702  rewriter.replaceOpWithNewOp<mlir::LLVM::IsFPClass>(703      op, retTy, src, static_cast<uint32_t>(flags));704  return mlir::success();705}706 707mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(708    cir::AssumeOp op, OpAdaptor adaptor,709    mlir::ConversionPatternRewriter &rewriter) const {710  auto cond = adaptor.getPredicate();711  rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(op, cond);712  return mlir::success();713}714 715mlir::LogicalResult CIRToLLVMAssumeAlignedOpLowering::matchAndRewrite(716    cir::AssumeAlignedOp op, OpAdaptor adaptor,717    mlir::ConversionPatternRewriter &rewriter) const {718  SmallVector<mlir::Value, 3> opBundleArgs{adaptor.getPointer()};719 720  auto alignment = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),721                                                  adaptor.getAlignmentAttr());722  opBundleArgs.push_back(alignment);723 724  if (mlir::Value offset = adaptor.getOffset())725    opBundleArgs.push_back(offset);726 727  auto cond = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),728                                             rewriter.getI1Type(), 1);729  mlir::LLVM::AssumeOp::create(rewriter, op.getLoc(), cond, "align",730                               opBundleArgs);731 732  // The llvm.assume operation does not have a result, so we need to replace733  // all uses of this cir.assume_aligned operation with the input ptr itself.734  rewriter.replaceOp(op, adaptor.getPointer());735  return mlir::success();736}737 738mlir::LogicalResult CIRToLLVMAssumeSepStorageOpLowering::matchAndRewrite(739    cir::AssumeSepStorageOp op, OpAdaptor adaptor,740    mlir::ConversionPatternRewriter &rewriter) const {741  auto cond = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),742                                             rewriter.getI1Type(), 1);743  rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(744      op, cond, mlir::LLVM::AssumeSeparateStorageTag{}, adaptor.getPtr1(),745      adaptor.getPtr2());746  return mlir::success();747}748 749static mlir::LLVM::AtomicOrdering750getLLVMMemOrder(std::optional<cir::MemOrder> memorder) {751  if (!memorder)752    return mlir::LLVM::AtomicOrdering::not_atomic;753  switch (*memorder) {754  case cir::MemOrder::Relaxed:755    return mlir::LLVM::AtomicOrdering::monotonic;756  case cir::MemOrder::Consume:757  case cir::MemOrder::Acquire:758    return mlir::LLVM::AtomicOrdering::acquire;759  case cir::MemOrder::Release:760    return mlir::LLVM::AtomicOrdering::release;761  case cir::MemOrder::AcquireRelease:762    return mlir::LLVM::AtomicOrdering::acq_rel;763  case cir::MemOrder::SequentiallyConsistent:764    return mlir::LLVM::AtomicOrdering::seq_cst;765  }766  llvm_unreachable("unknown memory order");767}768 769mlir::LogicalResult CIRToLLVMAtomicCmpXchgOpLowering::matchAndRewrite(770    cir::AtomicCmpXchgOp op, OpAdaptor adaptor,771    mlir::ConversionPatternRewriter &rewriter) const {772  mlir::Value expected = adaptor.getExpected();773  mlir::Value desired = adaptor.getDesired();774 775  auto cmpxchg = mlir::LLVM::AtomicCmpXchgOp::create(776      rewriter, op.getLoc(), adaptor.getPtr(), expected, desired,777      getLLVMMemOrder(adaptor.getSuccOrder()),778      getLLVMMemOrder(adaptor.getFailOrder()));779  assert(!cir::MissingFeatures::atomicScope());780  cmpxchg.setAlignment(adaptor.getAlignment());781  cmpxchg.setWeak(adaptor.getWeak());782  cmpxchg.setVolatile_(adaptor.getIsVolatile());783 784  // Check result and apply stores accordingly.785  auto old = mlir::LLVM::ExtractValueOp::create(rewriter, op.getLoc(),786                                                cmpxchg.getResult(), 0);787  auto cmp = mlir::LLVM::ExtractValueOp::create(rewriter, op.getLoc(),788                                                cmpxchg.getResult(), 1);789 790  rewriter.replaceOp(op, {old, cmp});791  return mlir::success();792}793 794mlir::LogicalResult CIRToLLVMAtomicXchgOpLowering::matchAndRewrite(795    cir::AtomicXchgOp op, OpAdaptor adaptor,796    mlir::ConversionPatternRewriter &rewriter) const {797  assert(!cir::MissingFeatures::atomicSyncScopeID());798  mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(adaptor.getMemOrder());799  rewriter.replaceOpWithNewOp<mlir::LLVM::AtomicRMWOp>(800      op, mlir::LLVM::AtomicBinOp::xchg, adaptor.getPtr(), adaptor.getVal(),801      llvmOrder);802  return mlir::success();803}804 805mlir::LogicalResult CIRToLLVMAtomicTestAndSetOpLowering::matchAndRewrite(806    cir::AtomicTestAndSetOp op, OpAdaptor adaptor,807    mlir::ConversionPatternRewriter &rewriter) const {808  assert(!cir::MissingFeatures::atomicSyncScopeID());809 810  mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder());811 812  auto one = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),813                                            rewriter.getI8Type(), 1);814  auto rmw = mlir::LLVM::AtomicRMWOp::create(815      rewriter, op.getLoc(), mlir::LLVM::AtomicBinOp::xchg, adaptor.getPtr(),816      one, llvmOrder, /*syncscope=*/llvm::StringRef(),817      adaptor.getAlignment().value_or(0), op.getIsVolatile());818 819  auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),820                                             rewriter.getI8Type(), 0);821  auto cmp = mlir::LLVM::ICmpOp::create(822      rewriter, op.getLoc(), mlir::LLVM::ICmpPredicate::ne, rmw, zero);823 824  rewriter.replaceOp(op, cmp);825  return mlir::success();826}827 828mlir::LogicalResult CIRToLLVMAtomicClearOpLowering::matchAndRewrite(829    cir::AtomicClearOp op, OpAdaptor adaptor,830    mlir::ConversionPatternRewriter &rewriter) const {831  assert(!cir::MissingFeatures::atomicSyncScopeID());832 833  mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder());834  auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),835                                             rewriter.getI8Type(), 0);836  auto store = mlir::LLVM::StoreOp::create(837      rewriter, op.getLoc(), zero, adaptor.getPtr(),838      adaptor.getAlignment().value_or(0), op.getIsVolatile(),839      /*isNonTemporal=*/false, /*isInvariantGroup=*/false, llvmOrder);840 841  rewriter.replaceOp(op, store);842  return mlir::success();843}844 845static mlir::LLVM::AtomicBinOp846getLLVMAtomicBinOp(cir::AtomicFetchKind k, bool isInt, bool isSignedInt) {847  switch (k) {848  case cir::AtomicFetchKind::Add:849    return isInt ? mlir::LLVM::AtomicBinOp::add : mlir::LLVM::AtomicBinOp::fadd;850  case cir::AtomicFetchKind::Sub:851    return isInt ? mlir::LLVM::AtomicBinOp::sub : mlir::LLVM::AtomicBinOp::fsub;852  case cir::AtomicFetchKind::And:853    return mlir::LLVM::AtomicBinOp::_and;854  case cir::AtomicFetchKind::Xor:855    return mlir::LLVM::AtomicBinOp::_xor;856  case cir::AtomicFetchKind::Or:857    return mlir::LLVM::AtomicBinOp::_or;858  case cir::AtomicFetchKind::Nand:859    return mlir::LLVM::AtomicBinOp::nand;860  case cir::AtomicFetchKind::Max: {861    if (!isInt)862      return mlir::LLVM::AtomicBinOp::fmax;863    return isSignedInt ? mlir::LLVM::AtomicBinOp::max864                       : mlir::LLVM::AtomicBinOp::umax;865  }866  case cir::AtomicFetchKind::Min: {867    if (!isInt)868      return mlir::LLVM::AtomicBinOp::fmin;869    return isSignedInt ? mlir::LLVM::AtomicBinOp::min870                       : mlir::LLVM::AtomicBinOp::umin;871  }872  }873  llvm_unreachable("Unknown atomic fetch opcode");874}875 876static llvm::StringLiteral getLLVMBinop(cir::AtomicFetchKind k, bool isInt) {877  switch (k) {878  case cir::AtomicFetchKind::Add:879    return isInt ? mlir::LLVM::AddOp::getOperationName()880                 : mlir::LLVM::FAddOp::getOperationName();881  case cir::AtomicFetchKind::Sub:882    return isInt ? mlir::LLVM::SubOp::getOperationName()883                 : mlir::LLVM::FSubOp::getOperationName();884  case cir::AtomicFetchKind::And:885    return mlir::LLVM::AndOp::getOperationName();886  case cir::AtomicFetchKind::Xor:887    return mlir::LLVM::XOrOp::getOperationName();888  case cir::AtomicFetchKind::Or:889    return mlir::LLVM::OrOp::getOperationName();890  case cir::AtomicFetchKind::Nand:891    // There's no nand binop in LLVM, this is later fixed with a not.892    return mlir::LLVM::AndOp::getOperationName();893  case cir::AtomicFetchKind::Max:894  case cir::AtomicFetchKind::Min:895    llvm_unreachable("handled in buildMinMaxPostOp");896  }897  llvm_unreachable("Unknown atomic fetch opcode");898}899 900mlir::Value CIRToLLVMAtomicFetchOpLowering::buildPostOp(901    cir::AtomicFetchOp op, OpAdaptor adaptor,902    mlir::ConversionPatternRewriter &rewriter, mlir::Value rmwVal,903    bool isInt) const {904  SmallVector<mlir::Value> atomicOperands = {rmwVal, adaptor.getVal()};905  SmallVector<mlir::Type> atomicResTys = {rmwVal.getType()};906  return rewriter907      .create(op.getLoc(),908              rewriter.getStringAttr(getLLVMBinop(op.getBinop(), isInt)),909              atomicOperands, atomicResTys, {})910      ->getResult(0);911}912 913mlir::Value CIRToLLVMAtomicFetchOpLowering::buildMinMaxPostOp(914    cir::AtomicFetchOp op, OpAdaptor adaptor,915    mlir::ConversionPatternRewriter &rewriter, mlir::Value rmwVal, bool isInt,916    bool isSigned) const {917  mlir::Location loc = op.getLoc();918 919  if (!isInt) {920    if (op.getBinop() == cir::AtomicFetchKind::Max)921      return mlir::LLVM::MaxNumOp::create(rewriter, loc, rmwVal,922                                          adaptor.getVal());923    return mlir::LLVM::MinNumOp::create(rewriter, loc, rmwVal,924                                        adaptor.getVal());925  }926 927  mlir::LLVM::ICmpPredicate pred;928  if (op.getBinop() == cir::AtomicFetchKind::Max) {929    pred = isSigned ? mlir::LLVM::ICmpPredicate::sgt930                    : mlir::LLVM::ICmpPredicate::ugt;931  } else { // Min932    pred = isSigned ? mlir::LLVM::ICmpPredicate::slt933                    : mlir::LLVM::ICmpPredicate::ult;934  }935  mlir::Value cmp = mlir::LLVM::ICmpOp::create(936      rewriter, loc,937      mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(), pred), rmwVal,938      adaptor.getVal());939  return mlir::LLVM::SelectOp::create(rewriter, loc, cmp, rmwVal,940                                      adaptor.getVal());941}942 943mlir::LogicalResult CIRToLLVMAtomicFetchOpLowering::matchAndRewrite(944    cir::AtomicFetchOp op, OpAdaptor adaptor,945    mlir::ConversionPatternRewriter &rewriter) const {946  bool isInt = false;947  bool isSignedInt = false;948  if (auto intTy = mlir::dyn_cast<cir::IntType>(op.getVal().getType())) {949    isInt = true;950    isSignedInt = intTy.isSigned();951  } else if (mlir::isa<cir::SingleType, cir::DoubleType>(952                 op.getVal().getType())) {953    isInt = false;954  } else {955    return op.emitError() << "Unsupported type: " << op.getVal().getType();956  }957 958  mlir::LLVM::AtomicOrdering llvmOrder = getLLVMMemOrder(op.getMemOrder());959  mlir::LLVM::AtomicBinOp llvmBinOp =960      getLLVMAtomicBinOp(op.getBinop(), isInt, isSignedInt);961  auto rmwVal = mlir::LLVM::AtomicRMWOp::create(rewriter, op.getLoc(),962                                                llvmBinOp, adaptor.getPtr(),963                                                adaptor.getVal(), llvmOrder);964 965  mlir::Value result = rmwVal.getResult();966  if (!op.getFetchFirst()) {967    if (op.getBinop() == cir::AtomicFetchKind::Max ||968        op.getBinop() == cir::AtomicFetchKind::Min)969      result = buildMinMaxPostOp(op, adaptor, rewriter, rmwVal.getRes(), isInt,970                                 isSignedInt);971    else972      result = buildPostOp(op, adaptor, rewriter, rmwVal.getRes(), isInt);973 974    // Compensate lack of nand binop in LLVM IR.975    if (op.getBinop() == cir::AtomicFetchKind::Nand) {976      auto negOne = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),977                                                   result.getType(), -1);978      result = mlir::LLVM::XOrOp::create(rewriter, op.getLoc(), result, negOne);979    }980  }981 982  rewriter.replaceOp(op, result);983  return mlir::success();984}985 986mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite(987    cir::BitClrsbOp op, OpAdaptor adaptor,988    mlir::ConversionPatternRewriter &rewriter) const {989  auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),990                                             adaptor.getInput().getType(), 0);991  auto isNeg = mlir::LLVM::ICmpOp::create(992      rewriter, op.getLoc(),993      mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(),994                                         mlir::LLVM::ICmpPredicate::slt),995      adaptor.getInput(), zero);996 997  auto negOne = mlir::LLVM::ConstantOp::create(998      rewriter, op.getLoc(), adaptor.getInput().getType(), -1);999  auto flipped = mlir::LLVM::XOrOp::create(rewriter, op.getLoc(),1000                                           adaptor.getInput(), negOne);1001 1002  auto select = mlir::LLVM::SelectOp::create(rewriter, op.getLoc(), isNeg,1003                                             flipped, adaptor.getInput());1004 1005  auto resTy = getTypeConverter()->convertType(op.getType());1006  auto clz = mlir::LLVM::CountLeadingZerosOp::create(1007      rewriter, op.getLoc(), resTy, select, /*is_zero_poison=*/false);1008 1009  auto one = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), resTy, 1);1010  auto res = mlir::LLVM::SubOp::create(rewriter, op.getLoc(), clz, one);1011  rewriter.replaceOp(op, res);1012 1013  return mlir::LogicalResult::success();1014}1015 1016mlir::LogicalResult CIRToLLVMBitClzOpLowering::matchAndRewrite(1017    cir::BitClzOp op, OpAdaptor adaptor,1018    mlir::ConversionPatternRewriter &rewriter) const {1019  auto resTy = getTypeConverter()->convertType(op.getType());1020  auto llvmOp = mlir::LLVM::CountLeadingZerosOp::create(1021      rewriter, op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());1022  rewriter.replaceOp(op, llvmOp);1023  return mlir::LogicalResult::success();1024}1025 1026mlir::LogicalResult CIRToLLVMBitCtzOpLowering::matchAndRewrite(1027    cir::BitCtzOp op, OpAdaptor adaptor,1028    mlir::ConversionPatternRewriter &rewriter) const {1029  auto resTy = getTypeConverter()->convertType(op.getType());1030  auto llvmOp = mlir::LLVM::CountTrailingZerosOp::create(1031      rewriter, op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());1032  rewriter.replaceOp(op, llvmOp);1033  return mlir::LogicalResult::success();1034}1035 1036mlir::LogicalResult CIRToLLVMBitFfsOpLowering::matchAndRewrite(1037    cir::BitFfsOp op, OpAdaptor adaptor,1038    mlir::ConversionPatternRewriter &rewriter) const {1039  auto resTy = getTypeConverter()->convertType(op.getType());1040  auto ctz = mlir::LLVM::CountTrailingZerosOp::create(rewriter, op.getLoc(),1041                                                      resTy, adaptor.getInput(),1042                                                      /*is_zero_poison=*/true);1043 1044  auto one = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), resTy, 1);1045  auto ctzAddOne = mlir::LLVM::AddOp::create(rewriter, op.getLoc(), ctz, one);1046 1047  auto zeroInputTy = mlir::LLVM::ConstantOp::create(1048      rewriter, op.getLoc(), adaptor.getInput().getType(), 0);1049  auto isZero = mlir::LLVM::ICmpOp::create(1050      rewriter, op.getLoc(),1051      mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(),1052                                         mlir::LLVM::ICmpPredicate::eq),1053      adaptor.getInput(), zeroInputTy);1054 1055  auto zero = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), resTy, 0);1056  auto res = mlir::LLVM::SelectOp::create(rewriter, op.getLoc(), isZero, zero,1057                                          ctzAddOne);1058  rewriter.replaceOp(op, res);1059 1060  return mlir::LogicalResult::success();1061}1062 1063mlir::LogicalResult CIRToLLVMBitParityOpLowering::matchAndRewrite(1064    cir::BitParityOp op, OpAdaptor adaptor,1065    mlir::ConversionPatternRewriter &rewriter) const {1066  auto resTy = getTypeConverter()->convertType(op.getType());1067  auto popcnt = mlir::LLVM::CtPopOp::create(rewriter, op.getLoc(), resTy,1068                                            adaptor.getInput());1069 1070  auto one = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(), resTy, 1);1071  auto popcntMod2 =1072      mlir::LLVM::AndOp::create(rewriter, op.getLoc(), popcnt, one);1073  rewriter.replaceOp(op, popcntMod2);1074 1075  return mlir::LogicalResult::success();1076}1077 1078mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(1079    cir::BitPopcountOp op, OpAdaptor adaptor,1080    mlir::ConversionPatternRewriter &rewriter) const {1081  auto resTy = getTypeConverter()->convertType(op.getType());1082  auto llvmOp = mlir::LLVM::CtPopOp::create(rewriter, op.getLoc(), resTy,1083                                            adaptor.getInput());1084  rewriter.replaceOp(op, llvmOp);1085  return mlir::LogicalResult::success();1086}1087 1088mlir::LogicalResult CIRToLLVMBitReverseOpLowering::matchAndRewrite(1089    cir::BitReverseOp op, OpAdaptor adaptor,1090    mlir::ConversionPatternRewriter &rewriter) const {1091  rewriter.replaceOpWithNewOp<mlir::LLVM::BitReverseOp>(op, adaptor.getInput());1092  return mlir::success();1093}1094 1095mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(1096    cir::BrCondOp brOp, OpAdaptor adaptor,1097    mlir::ConversionPatternRewriter &rewriter) const {1098  // When ZExtOp is implemented, we'll need to check if the condition is a1099  // ZExtOp and if so, delete it if it has a single use.1100  assert(!cir::MissingFeatures::zextOp());1101 1102  mlir::Value i1Condition = adaptor.getCond();1103 1104  rewriter.replaceOpWithNewOp<mlir::LLVM::CondBrOp>(1105      brOp, i1Condition, brOp.getDestTrue(), adaptor.getDestOperandsTrue(),1106      brOp.getDestFalse(), adaptor.getDestOperandsFalse());1107 1108  return mlir::success();1109}1110 1111mlir::LogicalResult CIRToLLVMByteSwapOpLowering::matchAndRewrite(1112    cir::ByteSwapOp op, OpAdaptor adaptor,1113    mlir::ConversionPatternRewriter &rewriter) const {1114  rewriter.replaceOpWithNewOp<mlir::LLVM::ByteSwapOp>(op, adaptor.getInput());1115  return mlir::LogicalResult::success();1116}1117 1118mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {1119  return getTypeConverter()->convertType(ty);1120}1121 1122mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(1123    cir::CastOp castOp, OpAdaptor adaptor,1124    mlir::ConversionPatternRewriter &rewriter) const {1125  // For arithmetic conversions, LLVM IR uses the same instruction to convert1126  // both individual scalars and entire vectors. This lowering pass handles1127  // both situations.1128 1129  switch (castOp.getKind()) {1130  case cir::CastKind::array_to_ptrdecay: {1131    const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType());1132    mlir::Value sourceValue = adaptor.getSrc();1133    mlir::Type targetType = convertTy(ptrTy);1134    mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,1135                                                ptrTy.getPointee());1136    llvm::SmallVector<mlir::LLVM::GEPArg> offset{0};1137    rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(1138        castOp, targetType, elementTy, sourceValue, offset);1139    break;1140  }1141  case cir::CastKind::int_to_bool: {1142    mlir::Value llvmSrcVal = adaptor.getSrc();1143    mlir::Value zeroInt = mlir::LLVM::ConstantOp::create(1144        rewriter, castOp.getLoc(), llvmSrcVal.getType(), 0);1145    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(1146        castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroInt);1147    break;1148  }1149  case cir::CastKind::integral: {1150    mlir::Type srcType = castOp.getSrc().getType();1151    mlir::Type dstType = castOp.getType();1152    mlir::Value llvmSrcVal = adaptor.getSrc();1153    mlir::Type llvmDstType = getTypeConverter()->convertType(dstType);1154    cir::IntType srcIntType =1155        mlir::cast<cir::IntType>(elementTypeIfVector(srcType));1156    cir::IntType dstIntType =1157        mlir::cast<cir::IntType>(elementTypeIfVector(dstType));1158    rewriter.replaceOp(castOp, getLLVMIntCast(rewriter, llvmSrcVal, llvmDstType,1159                                              srcIntType.isUnsigned(),1160                                              srcIntType.getWidth(),1161                                              dstIntType.getWidth()));1162    break;1163  }1164  case cir::CastKind::floating: {1165    mlir::Value llvmSrcVal = adaptor.getSrc();1166    mlir::Type llvmDstTy = getTypeConverter()->convertType(castOp.getType());1167 1168    mlir::Type srcTy = elementTypeIfVector(castOp.getSrc().getType());1169    mlir::Type dstTy = elementTypeIfVector(castOp.getType());1170 1171    if (!mlir::isa<cir::FPTypeInterface>(dstTy) ||1172        !mlir::isa<cir::FPTypeInterface>(srcTy))1173      return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy;1174 1175    auto getFloatWidth = [](mlir::Type ty) -> unsigned {1176      return mlir::cast<cir::FPTypeInterface>(ty).getWidth();1177    };1178 1179    if (getFloatWidth(srcTy) > getFloatWidth(dstTy))1180      rewriter.replaceOpWithNewOp<mlir::LLVM::FPTruncOp>(castOp, llvmDstTy,1181                                                         llvmSrcVal);1182    else1183      rewriter.replaceOpWithNewOp<mlir::LLVM::FPExtOp>(castOp, llvmDstTy,1184                                                       llvmSrcVal);1185    return mlir::success();1186  }1187  case cir::CastKind::int_to_ptr: {1188    auto dstTy = mlir::cast<cir::PointerType>(castOp.getType());1189    mlir::Value llvmSrcVal = adaptor.getSrc();1190    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1191    rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(castOp, llvmDstTy,1192                                                        llvmSrcVal);1193    return mlir::success();1194  }1195  case cir::CastKind::ptr_to_int: {1196    auto dstTy = mlir::cast<cir::IntType>(castOp.getType());1197    mlir::Value llvmSrcVal = adaptor.getSrc();1198    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1199    rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(castOp, llvmDstTy,1200                                                        llvmSrcVal);1201    return mlir::success();1202  }1203  case cir::CastKind::float_to_bool: {1204    mlir::Value llvmSrcVal = adaptor.getSrc();1205    auto kind = mlir::LLVM::FCmpPredicate::une;1206 1207    // Check if float is not equal to zero.1208    auto zeroFloat = mlir::LLVM::ConstantOp::create(1209        rewriter, castOp.getLoc(), llvmSrcVal.getType(),1210        mlir::FloatAttr::get(llvmSrcVal.getType(), 0.0));1211 1212    // Extend comparison result to either bool (C++) or int (C).1213    rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(castOp, kind, llvmSrcVal,1214                                                    zeroFloat);1215 1216    return mlir::success();1217  }1218  case cir::CastKind::bool_to_int: {1219    auto dstTy = mlir::cast<cir::IntType>(castOp.getType());1220    mlir::Value llvmSrcVal = adaptor.getSrc();1221    auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType());1222    auto llvmDstTy =1223        mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy));1224    if (llvmSrcTy.getWidth() == llvmDstTy.getWidth())1225      rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,1226                                                         llvmSrcVal);1227    else1228      rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(castOp, llvmDstTy,1229                                                      llvmSrcVal);1230    return mlir::success();1231  }1232  case cir::CastKind::bool_to_float: {1233    mlir::Type dstTy = castOp.getType();1234    mlir::Value llvmSrcVal = adaptor.getSrc();1235    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1236    rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,1237                                                      llvmSrcVal);1238    return mlir::success();1239  }1240  case cir::CastKind::int_to_float: {1241    mlir::Type dstTy = castOp.getType();1242    mlir::Value llvmSrcVal = adaptor.getSrc();1243    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1244    if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getSrc().getType()))1245            .isSigned())1246      rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(castOp, llvmDstTy,1247                                                        llvmSrcVal);1248    else1249      rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,1250                                                        llvmSrcVal);1251    return mlir::success();1252  }1253  case cir::CastKind::float_to_int: {1254    mlir::Type dstTy = castOp.getType();1255    mlir::Value llvmSrcVal = adaptor.getSrc();1256    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1257    if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getType()))1258            .isSigned())1259      rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(castOp, llvmDstTy,1260                                                        llvmSrcVal);1261    else1262      rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(castOp, llvmDstTy,1263                                                        llvmSrcVal);1264    return mlir::success();1265  }1266  case cir::CastKind::bitcast: {1267    mlir::Type dstTy = castOp.getType();1268    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1269 1270    assert(!MissingFeatures::cxxABI());1271    assert(!MissingFeatures::dataMemberType());1272 1273    mlir::Value llvmSrcVal = adaptor.getSrc();1274    rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,1275                                                       llvmSrcVal);1276    return mlir::success();1277  }1278  case cir::CastKind::ptr_to_bool: {1279    mlir::Value llvmSrcVal = adaptor.getSrc();1280    mlir::Value zeroPtr = mlir::LLVM::ZeroOp::create(rewriter, castOp.getLoc(),1281                                                     llvmSrcVal.getType());1282    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(1283        castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroPtr);1284    break;1285  }1286  case cir::CastKind::address_space: {1287    mlir::Type dstTy = castOp.getType();1288    mlir::Value llvmSrcVal = adaptor.getSrc();1289    mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1290    rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(castOp, llvmDstTy,1291                                                             llvmSrcVal);1292    break;1293  }1294  case cir::CastKind::member_ptr_to_bool:1295    assert(!MissingFeatures::cxxABI());1296    assert(!MissingFeatures::methodType());1297    break;1298  default: {1299    return castOp.emitError("Unhandled cast kind: ")1300           << castOp.getKindAttrName();1301  }1302  }1303 1304  return mlir::success();1305}1306 1307mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(1308    cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,1309    mlir::ConversionPatternRewriter &rewriter) const {1310 1311  const mlir::TypeConverter *tc = getTypeConverter();1312  const mlir::Type resultTy = tc->convertType(ptrStrideOp.getType());1313 1314  mlir::Type elementTy =1315      convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementType());1316  mlir::MLIRContext *ctx = elementTy.getContext();1317 1318  // void and function types doesn't really have a layout to use in GEPs,1319  // make it i8 instead.1320  if (mlir::isa<mlir::LLVM::LLVMVoidType>(elementTy) ||1321      mlir::isa<mlir::LLVM::LLVMFunctionType>(elementTy))1322    elementTy = mlir::IntegerType::get(elementTy.getContext(), 8,1323                                       mlir::IntegerType::Signless);1324  // Zero-extend, sign-extend or trunc the pointer value.1325  mlir::Value index = adaptor.getStride();1326  const unsigned width =1327      mlir::cast<mlir::IntegerType>(index.getType()).getWidth();1328  const std::optional<std::uint64_t> layoutWidth =1329      dataLayout.getTypeIndexBitwidth(adaptor.getBase().getType());1330 1331  mlir::Operation *indexOp = index.getDefiningOp();1332  if (indexOp && layoutWidth && width != *layoutWidth) {1333    // If the index comes from a subtraction, make sure the extension happens1334    // before it. To achieve that, look at unary minus, which already got1335    // lowered to "sub 0, x".1336    const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp);1337    auto unary = ptrStrideOp.getStride().getDefiningOp<cir::UnaryOp>();1338    bool rewriteSub =1339        unary && unary.getKind() == cir::UnaryOpKind::Minus && sub;1340    if (rewriteSub)1341      index = indexOp->getOperand(1);1342 1343    // Handle the cast1344    const auto llvmDstType = mlir::IntegerType::get(ctx, *layoutWidth);1345    index = getLLVMIntCast(rewriter, index, llvmDstType,1346                           ptrStrideOp.getStride().getType().isUnsigned(),1347                           width, *layoutWidth);1348 1349    // Rewrite the sub in front of extensions/trunc1350    if (rewriteSub) {1351      index = mlir::LLVM::SubOp::create(1352          rewriter, index.getLoc(), index.getType(),1353          mlir::LLVM::ConstantOp::create(rewriter, index.getLoc(),1354                                         index.getType(), 0),1355          index);1356      rewriter.eraseOp(sub);1357    }1358  }1359 1360  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(1361      ptrStrideOp, resultTy, elementTy, adaptor.getBase(), index);1362  return mlir::success();1363}1364 1365mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(1366    cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,1367    mlir::ConversionPatternRewriter &rewriter) const {1368  const mlir::Type resultType =1369      getTypeConverter()->convertType(baseClassOp.getType());1370  mlir::Value derivedAddr = adaptor.getDerivedAddr();1371  llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {1372      adaptor.getOffset().getZExtValue()};1373  mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8,1374                                               mlir::IntegerType::Signless);1375  if (adaptor.getOffset().getZExtValue() == 0) {1376    rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(1377        baseClassOp, resultType, adaptor.getDerivedAddr());1378    return mlir::success();1379  }1380 1381  if (baseClassOp.getAssumeNotNull()) {1382    rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(1383        baseClassOp, resultType, byteType, derivedAddr, offset);1384  } else {1385    auto loc = baseClassOp.getLoc();1386    mlir::Value isNull = mlir::LLVM::ICmpOp::create(1387        rewriter, loc, mlir::LLVM::ICmpPredicate::eq, derivedAddr,1388        mlir::LLVM::ZeroOp::create(rewriter, loc, derivedAddr.getType()));1389    mlir::Value adjusted = mlir::LLVM::GEPOp::create(1390        rewriter, loc, resultType, byteType, derivedAddr, offset);1391    rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(baseClassOp, isNull,1392                                                      derivedAddr, adjusted);1393  }1394  return mlir::success();1395}1396 1397mlir::LogicalResult CIRToLLVMDerivedClassAddrOpLowering::matchAndRewrite(1398    cir::DerivedClassAddrOp derivedClassOp, OpAdaptor adaptor,1399    mlir::ConversionPatternRewriter &rewriter) const {1400  const mlir::Type resultType =1401      getTypeConverter()->convertType(derivedClassOp.getType());1402  mlir::Value baseAddr = adaptor.getBaseAddr();1403  // The offset is set in the operation as an unsigned value, but it must be1404  // applied as a negative offset.1405  int64_t offsetVal = -(adaptor.getOffset().getZExtValue());1406  if (offsetVal == 0) {1407    // If the offset is zero, we can just return the base address,1408    rewriter.replaceOp(derivedClassOp, baseAddr);1409    return mlir::success();1410  }1411  llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {offsetVal};1412  mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8,1413                                               mlir::IntegerType::Signless);1414  if (derivedClassOp.getAssumeNotNull()) {1415    rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(1416        derivedClassOp, resultType, byteType, baseAddr, offset,1417        mlir::LLVM::GEPNoWrapFlags::inbounds);1418  } else {1419    mlir::Location loc = derivedClassOp.getLoc();1420    mlir::Value isNull = mlir::LLVM::ICmpOp::create(1421        rewriter, loc, mlir::LLVM::ICmpPredicate::eq, baseAddr,1422        mlir::LLVM::ZeroOp::create(rewriter, loc, baseAddr.getType()));1423    mlir::Value adjusted =1424        mlir::LLVM::GEPOp::create(rewriter, loc, resultType, byteType, baseAddr,1425                                  offset, mlir::LLVM::GEPNoWrapFlags::inbounds);1426    rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(derivedClassOp, isNull,1427                                                      baseAddr, adjusted);1428  }1429  return mlir::success();1430}1431 1432mlir::LogicalResult CIRToLLVMATanOpLowering::matchAndRewrite(1433    cir::ATanOp op, OpAdaptor adaptor,1434    mlir::ConversionPatternRewriter &rewriter) const {1435  mlir::Type resTy = typeConverter->convertType(op.getType());1436  rewriter.replaceOpWithNewOp<mlir::LLVM::ATanOp>(op, resTy, adaptor.getSrc());1437  return mlir::success();1438}1439 1440mlir::LogicalResult CIRToLLVMCeilOpLowering::matchAndRewrite(1441    cir::CeilOp op, OpAdaptor adaptor,1442    mlir::ConversionPatternRewriter &rewriter) const {1443  mlir::Type resTy = typeConverter->convertType(op.getType());1444  rewriter.replaceOpWithNewOp<mlir::LLVM::FCeilOp>(op, resTy, adaptor.getSrc());1445  return mlir::success();1446}1447 1448mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(1449    cir::AllocaOp op, OpAdaptor adaptor,1450    mlir::ConversionPatternRewriter &rewriter) const {1451  mlir::Value size =1452      op.isDynamic()1453          ? adaptor.getDynAllocSize()1454          : mlir::LLVM::ConstantOp::create(1455                rewriter, op.getLoc(),1456                typeConverter->convertType(rewriter.getIndexType()), 1);1457  mlir::Type elementTy =1458      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType());1459  mlir::Type resultTy =1460      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());1461 1462  assert(!cir::MissingFeatures::addressSpace());1463  assert(!cir::MissingFeatures::opAllocaAnnotations());1464 1465  rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(1466      op, resultTy, elementTy, size, op.getAlignmentAttr().getInt());1467 1468  return mlir::success();1469}1470 1471mlir::LogicalResult CIRToLLVMReturnOpLowering::matchAndRewrite(1472    cir::ReturnOp op, OpAdaptor adaptor,1473    mlir::ConversionPatternRewriter &rewriter) const {1474  rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op, adaptor.getOperands());1475  return mlir::LogicalResult::success();1476}1477 1478mlir::LogicalResult CIRToLLVMRotateOpLowering::matchAndRewrite(1479    cir::RotateOp op, OpAdaptor adaptor,1480    mlir::ConversionPatternRewriter &rewriter) const {1481  // Note that LLVM intrinsic calls to @llvm.fsh{r,l}.i* have the same type as1482  // the operand.1483  mlir::Value input = adaptor.getInput();1484  if (op.isRotateLeft())1485    rewriter.replaceOpWithNewOp<mlir::LLVM::FshlOp>(op, input, input,1486                                                    adaptor.getAmount());1487  else1488    rewriter.replaceOpWithNewOp<mlir::LLVM::FshrOp>(op, input, input,1489                                                    adaptor.getAmount());1490  return mlir::LogicalResult::success();1491}1492 1493static mlir::LogicalResult1494rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,1495                    mlir::ConversionPatternRewriter &rewriter,1496                    const mlir::TypeConverter *converter,1497                    mlir::FlatSymbolRefAttr calleeAttr) {1498  llvm::SmallVector<mlir::Type, 8> llvmResults;1499  mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes();1500  auto call = cast<cir::CIRCallOpInterface>(op);1501 1502  if (converter->convertTypes(cirResults, llvmResults).failed())1503    return mlir::failure();1504 1505  assert(!cir::MissingFeatures::opCallCallConv());1506 1507  mlir::LLVM::MemoryEffectsAttr memoryEffects;1508  bool noUnwind = false;1509  bool willReturn = false;1510  convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),1511                           memoryEffects, noUnwind, willReturn);1512 1513  mlir::LLVM::LLVMFunctionType llvmFnTy;1514 1515  // Temporary to handle the case where we need to prepend an operand if the1516  // callee is an alias.1517  SmallVector<mlir::Value> adjustedCallOperands;1518 1519  if (calleeAttr) { // direct call1520    mlir::Operation *callee =1521        mlir::SymbolTable::lookupNearestSymbolFrom(op, calleeAttr);1522    if (auto fn = mlir::dyn_cast<mlir::FunctionOpInterface>(callee)) {1523      llvmFnTy = converter->convertType<mlir::LLVM::LLVMFunctionType>(1524          fn.getFunctionType());1525      assert(llvmFnTy && "Failed to convert function type");1526    } else if (auto alias = mlir::cast<mlir::LLVM::AliasOp>(callee)) {1527      // If the callee was an alias. In that case,1528      // we need to prepend the address of the alias to the operands. The1529      // way aliases work in the LLVM dialect is a little counter-intuitive.1530      // The AliasOp itself is a pseudo-function that returns the address of1531      // the global value being aliased, but when we generate the call we1532      // need to insert an operation that gets the address of the AliasOp.1533      // This all gets sorted out when the LLVM dialect is lowered to LLVM IR.1534      auto symAttr = mlir::cast<mlir::FlatSymbolRefAttr>(calleeAttr);1535      auto addrOfAlias =1536          mlir::LLVM::AddressOfOp::create(1537              rewriter, op->getLoc(),1538              mlir::LLVM::LLVMPointerType::get(rewriter.getContext()), symAttr)1539              .getResult();1540      adjustedCallOperands.push_back(addrOfAlias);1541 1542      // Now add the regular operands and assign this to the range value.1543      llvm::append_range(adjustedCallOperands, callOperands);1544      callOperands = adjustedCallOperands;1545 1546      // Clear the callee attribute because we're calling an alias.1547      calleeAttr = {};1548      llvmFnTy = mlir::cast<mlir::LLVM::LLVMFunctionType>(alias.getType());1549    } else {1550      // Was this an ifunc?1551      return op->emitError("Unexpected callee type!");1552    }1553  } else { // indirect call1554    assert(!op->getOperands().empty() &&1555           "operands list must no be empty for the indirect call");1556    auto calleeTy = op->getOperands().front().getType();1557    auto calleePtrTy = cast<cir::PointerType>(calleeTy);1558    auto calleeFuncTy = cast<cir::FuncType>(calleePtrTy.getPointee());1559    llvm::append_range(adjustedCallOperands, callOperands);1560    llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(1561        converter->convertType(calleeFuncTy));1562  }1563 1564  assert(!cir::MissingFeatures::opCallLandingPad());1565  assert(!cir::MissingFeatures::opCallContinueBlock());1566  assert(!cir::MissingFeatures::opCallCallConv());1567 1568  auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(1569      op, llvmFnTy, calleeAttr, callOperands);1570  if (memoryEffects)1571    newOp.setMemoryEffectsAttr(memoryEffects);1572  newOp.setNoUnwind(noUnwind);1573  newOp.setWillReturn(willReturn);1574 1575  return mlir::success();1576}1577 1578mlir::LogicalResult CIRToLLVMCallOpLowering::matchAndRewrite(1579    cir::CallOp op, OpAdaptor adaptor,1580    mlir::ConversionPatternRewriter &rewriter) const {1581  return rewriteCallOrInvoke(op.getOperation(), adaptor.getOperands(), rewriter,1582                             getTypeConverter(), op.getCalleeAttr());1583}1584 1585mlir::LogicalResult CIRToLLVMReturnAddrOpLowering::matchAndRewrite(1586    cir::ReturnAddrOp op, OpAdaptor adaptor,1587    mlir::ConversionPatternRewriter &rewriter) const {1588  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());1589  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.returnaddress",1590                                   llvmPtrTy, adaptor.getOperands());1591  return mlir::success();1592}1593 1594mlir::LogicalResult CIRToLLVMFrameAddrOpLowering::matchAndRewrite(1595    cir::FrameAddrOp op, OpAdaptor adaptor,1596    mlir::ConversionPatternRewriter &rewriter) const {1597  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());1598  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.frameaddress", llvmPtrTy,1599                                   adaptor.getOperands());1600  return mlir::success();1601}1602 1603mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(1604    cir::LoadOp op, OpAdaptor adaptor,1605    mlir::ConversionPatternRewriter &rewriter) const {1606  const mlir::Type llvmTy =1607      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());1608  mlir::LLVM::AtomicOrdering ordering = getLLVMMemOrder(op.getMemOrder());1609  std::optional<size_t> opAlign = op.getAlignment();1610  unsigned alignment =1611      (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));1612 1613  assert(!cir::MissingFeatures::lowerModeOptLevel());1614 1615  // TODO: nontemporal, syncscope.1616  assert(!cir::MissingFeatures::opLoadStoreNontemporal());1617  mlir::LLVM::LoadOp newLoad = mlir::LLVM::LoadOp::create(1618      rewriter, op->getLoc(), llvmTy, adaptor.getAddr(), alignment,1619      op.getIsVolatile(), /*isNonTemporal=*/false,1620      /*isInvariant=*/false, /*isInvariantGroup=*/false, ordering);1621 1622  // Convert adapted result to its original type if needed.1623  mlir::Value result =1624      emitFromMemory(rewriter, dataLayout, op, newLoad.getResult());1625  rewriter.replaceOp(op, result);1626  assert(!cir::MissingFeatures::opLoadStoreTbaa());1627  return mlir::LogicalResult::success();1628}1629 1630mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite(1631    cir::StoreOp op, OpAdaptor adaptor,1632    mlir::ConversionPatternRewriter &rewriter) const {1633  mlir::LLVM::AtomicOrdering memorder = getLLVMMemOrder(op.getMemOrder());1634  const mlir::Type llvmTy =1635      getTypeConverter()->convertType(op.getValue().getType());1636  std::optional<size_t> opAlign = op.getAlignment();1637  unsigned alignment =1638      (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));1639 1640  assert(!cir::MissingFeatures::lowerModeOptLevel());1641 1642  // Convert adapted value to its memory type if needed.1643  mlir::Value value = emitToMemory(rewriter, dataLayout,1644                                   op.getValue().getType(), adaptor.getValue());1645  // TODO: nontemporal, syncscope.1646  assert(!cir::MissingFeatures::opLoadStoreNontemporal());1647  assert(!cir::MissingFeatures::opLoadStoreTbaa());1648  mlir::LLVM::StoreOp storeOp = mlir::LLVM::StoreOp::create(1649      rewriter, op->getLoc(), value, adaptor.getAddr(), alignment,1650      op.getIsVolatile(),1651      /*isNonTemporal=*/false, /*isInvariantGroup=*/false, memorder);1652  rewriter.replaceOp(op, storeOp);1653  assert(!cir::MissingFeatures::opLoadStoreTbaa());1654  return mlir::LogicalResult::success();1655}1656 1657bool hasTrailingZeros(cir::ConstArrayAttr attr) {1658  auto array = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts());1659  return attr.hasTrailingZeros() ||1660         (array && std::count_if(array.begin(), array.end(), [](auto elt) {1661            auto ar = dyn_cast<cir::ConstArrayAttr>(elt);1662            return ar && hasTrailingZeros(ar);1663          }));1664}1665 1666mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(1667    cir::ConstantOp op, OpAdaptor adaptor,1668    mlir::ConversionPatternRewriter &rewriter) const {1669  mlir::Attribute attr = op.getValue();1670 1671  if (mlir::isa<cir::PoisonAttr>(attr)) {1672    rewriter.replaceOpWithNewOp<mlir::LLVM::PoisonOp>(1673        op, getTypeConverter()->convertType(op.getType()));1674    return mlir::success();1675  }1676 1677  if (mlir::isa<mlir::IntegerType>(op.getType())) {1678    // Verified cir.const operations cannot actually be of these types, but the1679    // lowering pass may generate temporary cir.const operations with these1680    // types. This is OK since MLIR allows unverified operations to be alive1681    // during a pass as long as they don't live past the end of the pass.1682    attr = op.getValue();1683  } else if (mlir::isa<cir::BoolType>(op.getType())) {1684    int value = mlir::cast<cir::BoolAttr>(op.getValue()).getValue();1685    attr = rewriter.getIntegerAttr(typeConverter->convertType(op.getType()),1686                                   value);1687  } else if (mlir::isa<cir::IntType>(op.getType())) {1688    // Lower GlobalViewAttr to llvm.mlir.addressof + llvm.mlir.ptrtoint1689    if (auto ga = mlir::dyn_cast<cir::GlobalViewAttr>(op.getValue())) {1690      // See the comment in visitCirAttr for why this isn't implemented.1691      assert(!cir::MissingFeatures::globalViewIntLowering());1692      op.emitError() << "global view with integer type";1693      return mlir::failure();1694    }1695 1696    attr = rewriter.getIntegerAttr(1697        typeConverter->convertType(op.getType()),1698        mlir::cast<cir::IntAttr>(op.getValue()).getValue());1699  } else if (mlir::isa<cir::FPTypeInterface>(op.getType())) {1700    attr = rewriter.getFloatAttr(1701        typeConverter->convertType(op.getType()),1702        mlir::cast<cir::FPAttr>(op.getValue()).getValue());1703  } else if (mlir::isa<cir::PointerType>(op.getType())) {1704    // Optimize with dedicated LLVM op for null pointers.1705    if (mlir::isa<cir::ConstPtrAttr>(op.getValue())) {1706      if (mlir::cast<cir::ConstPtrAttr>(op.getValue()).isNullValue()) {1707        rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(1708            op, typeConverter->convertType(op.getType()));1709        return mlir::success();1710      }1711    }1712    // Lower GlobalViewAttr to llvm.mlir.addressof1713    if (auto gv = mlir::dyn_cast<cir::GlobalViewAttr>(op.getValue())) {1714      auto newOp = lowerCirAttrAsValue(op, gv, rewriter, getTypeConverter());1715      rewriter.replaceOp(op, newOp);1716      return mlir::success();1717    }1718    attr = op.getValue();1719  } else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {1720    const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());1721    if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))1722      return op.emitError() << "array does not have a constant initializer";1723 1724    std::optional<mlir::Attribute> denseAttr;1725    if (constArr && hasTrailingZeros(constArr)) {1726      const mlir::Value newOp =1727          lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter());1728      rewriter.replaceOp(op, newOp);1729      return mlir::success();1730    } else if (constArr &&1731               (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {1732      attr = denseAttr.value();1733    } else {1734      const mlir::Value initVal =1735          lowerCirAttrAsValue(op, op.getValue(), rewriter, typeConverter);1736      rewriter.replaceOp(op, initVal);1737      return mlir::success();1738    }1739  } else if (const auto recordAttr =1740                 mlir::dyn_cast<cir::ConstRecordAttr>(op.getValue())) {1741    auto initVal = lowerCirAttrAsValue(op, recordAttr, rewriter, typeConverter);1742    rewriter.replaceOp(op, initVal);1743    return mlir::success();1744  } else if (const auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) {1745    rewriter.replaceOp(op, lowerCirAttrAsValue(op, op.getValue(), rewriter,1746                                               getTypeConverter()));1747    return mlir::success();1748  } else if (auto recTy = mlir::dyn_cast<cir::RecordType>(op.getType())) {1749    if (mlir::isa<cir::ZeroAttr, cir::UndefAttr>(attr)) {1750      mlir::Value initVal =1751          lowerCirAttrAsValue(op, attr, rewriter, typeConverter);1752      rewriter.replaceOp(op, initVal);1753      return mlir::success();1754    }1755    return op.emitError() << "unsupported lowering for record constant type "1756                          << op.getType();1757  } else if (auto complexTy = mlir::dyn_cast<cir::ComplexType>(op.getType())) {1758    mlir::Type complexElemTy = complexTy.getElementType();1759    mlir::Type complexElemLLVMTy = typeConverter->convertType(complexElemTy);1760 1761    if (auto zeroInitAttr = mlir::dyn_cast<cir::ZeroAttr>(op.getValue())) {1762      mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(complexElemLLVMTy);1763      mlir::ArrayAttr array = rewriter.getArrayAttr({zeroAttr, zeroAttr});1764      rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(1765          op, getTypeConverter()->convertType(op.getType()), array);1766      return mlir::success();1767    }1768 1769    auto complexAttr = mlir::cast<cir::ConstComplexAttr>(op.getValue());1770 1771    mlir::Attribute components[2];1772    if (mlir::isa<cir::IntType>(complexElemTy)) {1773      components[0] = rewriter.getIntegerAttr(1774          complexElemLLVMTy,1775          mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());1776      components[1] = rewriter.getIntegerAttr(1777          complexElemLLVMTy,1778          mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());1779    } else {1780      components[0] = rewriter.getFloatAttr(1781          complexElemLLVMTy,1782          mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());1783      components[1] = rewriter.getFloatAttr(1784          complexElemLLVMTy,1785          mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());1786    }1787 1788    attr = rewriter.getArrayAttr(components);1789  } else {1790    return op.emitError() << "unsupported constant type " << op.getType();1791  }1792 1793  rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(1794      op, getTypeConverter()->convertType(op.getType()), attr);1795 1796  return mlir::success();1797}1798 1799static uint64_t getTypeSize(mlir::Type type, mlir::Operation &op) {1800  mlir::DataLayout layout(op.getParentOfType<mlir::ModuleOp>());1801  // For LLVM purposes we treat void as u8.1802  if (isa<cir::VoidType>(type))1803    type = cir::IntType::get(type.getContext(), 8, /*isSigned=*/false);1804  return llvm::divideCeil(layout.getTypeSizeInBits(type), 8);1805}1806 1807mlir::LogicalResult CIRToLLVMPrefetchOpLowering::matchAndRewrite(1808    cir::PrefetchOp op, OpAdaptor adaptor,1809    mlir::ConversionPatternRewriter &rewriter) const {1810  rewriter.replaceOpWithNewOp<mlir::LLVM::Prefetch>(1811      op, adaptor.getAddr(), adaptor.getIsWrite(), adaptor.getLocality(),1812      /*DataCache=*/1);1813  return mlir::success();1814}1815 1816mlir::LogicalResult CIRToLLVMPtrDiffOpLowering::matchAndRewrite(1817    cir::PtrDiffOp op, OpAdaptor adaptor,1818    mlir::ConversionPatternRewriter &rewriter) const {1819  auto dstTy = mlir::cast<cir::IntType>(op.getType());1820  mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);1821 1822  auto lhs = mlir::LLVM::PtrToIntOp::create(rewriter, op.getLoc(), llvmDstTy,1823                                            adaptor.getLhs());1824  auto rhs = mlir::LLVM::PtrToIntOp::create(rewriter, op.getLoc(), llvmDstTy,1825                                            adaptor.getRhs());1826 1827  auto diff =1828      mlir::LLVM::SubOp::create(rewriter, op.getLoc(), llvmDstTy, lhs, rhs);1829 1830  cir::PointerType ptrTy = op.getLhs().getType();1831  assert(!cir::MissingFeatures::llvmLoweringPtrDiffConsidersPointee());1832  uint64_t typeSize = getTypeSize(ptrTy.getPointee(), *op);1833 1834  // Avoid silly division by 1.1835  mlir::Value resultVal = diff.getResult();1836  if (typeSize != 1) {1837    auto typeSizeVal = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),1838                                                      llvmDstTy, typeSize);1839 1840    if (dstTy.isUnsigned()) {1841      auto uDiv =1842          mlir::LLVM::UDivOp::create(rewriter, op.getLoc(), diff, typeSizeVal);1843      uDiv.setIsExact(true);1844      resultVal = uDiv.getResult();1845    } else {1846      auto sDiv =1847          mlir::LLVM::SDivOp::create(rewriter, op.getLoc(), diff, typeSizeVal);1848      sDiv.setIsExact(true);1849      resultVal = sDiv.getResult();1850    }1851  }1852  rewriter.replaceOp(op, resultVal);1853  return mlir::success();1854}1855 1856mlir::LogicalResult CIRToLLVMExpectOpLowering::matchAndRewrite(1857    cir::ExpectOp op, OpAdaptor adaptor,1858    mlir::ConversionPatternRewriter &rewriter) const {1859  // TODO(cir): do not generate LLVM intrinsics under -O01860  assert(!cir::MissingFeatures::optInfoAttr());1861 1862  std::optional<llvm::APFloat> prob = op.getProb();1863  if (prob)1864    rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectWithProbabilityOp>(1865        op, adaptor.getVal(), adaptor.getExpected(), prob.value());1866  else1867    rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectOp>(op, adaptor.getVal(),1868                                                      adaptor.getExpected());1869  return mlir::success();1870}1871 1872mlir::LogicalResult CIRToLLVMFAbsOpLowering::matchAndRewrite(1873    cir::FAbsOp op, OpAdaptor adaptor,1874    mlir::ConversionPatternRewriter &rewriter) const {1875  mlir::Type resTy = typeConverter->convertType(op.getType());1876  rewriter.replaceOpWithNewOp<mlir::LLVM::FAbsOp>(op, resTy,1877                                                  adaptor.getOperands()[0]);1878  return mlir::success();1879}1880 1881/// Convert the `cir.func` attributes to `llvm.func` attributes.1882/// Only retain those attributes that are not constructed by1883/// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out1884/// argument attributes.1885void CIRToLLVMFuncOpLowering::lowerFuncAttributes(1886    cir::FuncOp func, bool filterArgAndResAttrs,1887    SmallVectorImpl<mlir::NamedAttribute> &result) const {1888  assert(!cir::MissingFeatures::opFuncCallingConv());1889  for (mlir::NamedAttribute attr : func->getAttrs()) {1890    assert(!cir::MissingFeatures::opFuncCallingConv());1891    if (attr.getName() == mlir::SymbolTable::getSymbolAttrName() ||1892        attr.getName() == func.getFunctionTypeAttrName() ||1893        attr.getName() == getLinkageAttrNameString() ||1894        attr.getName() == func.getGlobalVisibilityAttrName() ||1895        attr.getName() == func.getDsoLocalAttrName() ||1896        attr.getName() == func.getInlineKindAttrName() ||1897        (filterArgAndResAttrs &&1898         (attr.getName() == func.getArgAttrsAttrName() ||1899          attr.getName() == func.getResAttrsAttrName())))1900      continue;1901 1902    assert(!cir::MissingFeatures::opFuncExtraAttrs());1903    result.push_back(attr);1904  }1905}1906 1907mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewriteAlias(1908    cir::FuncOp op, llvm::StringRef aliasee, mlir::Type ty, OpAdaptor adaptor,1909    mlir::ConversionPatternRewriter &rewriter) const {1910  SmallVector<mlir::NamedAttribute, 4> attributes;1911  lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);1912 1913  mlir::Location loc = op.getLoc();1914  auto aliasOp = rewriter.replaceOpWithNewOp<mlir::LLVM::AliasOp>(1915      op, ty, convertLinkage(op.getLinkage()), op.getName(), op.getDsoLocal(),1916      /*threadLocal=*/false, attributes);1917 1918  // Create the alias body1919  mlir::OpBuilder builder(op.getContext());1920  mlir::Block *block = builder.createBlock(&aliasOp.getInitializerRegion());1921  builder.setInsertionPointToStart(block);1922  // The type of AddressOfOp is always a pointer.1923  assert(!cir::MissingFeatures::addressSpace());1924  mlir::Type ptrTy = mlir::LLVM::LLVMPointerType::get(ty.getContext());1925  auto addrOp = mlir::LLVM::AddressOfOp::create(builder, loc, ptrTy, aliasee);1926  mlir::LLVM::ReturnOp::create(builder, loc, addrOp);1927 1928  return mlir::success();1929}1930 1931mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(1932    cir::FuncOp op, OpAdaptor adaptor,1933    mlir::ConversionPatternRewriter &rewriter) const {1934 1935  cir::FuncType fnType = op.getFunctionType();1936  bool isDsoLocal = op.getDsoLocal();1937  mlir::TypeConverter::SignatureConversion signatureConversion(1938      fnType.getNumInputs());1939 1940  for (const auto &argType : llvm::enumerate(fnType.getInputs())) {1941    mlir::Type convertedType = typeConverter->convertType(argType.value());1942    if (!convertedType)1943      return mlir::failure();1944    signatureConversion.addInputs(argType.index(), convertedType);1945  }1946 1947  mlir::Type resultType =1948      getTypeConverter()->convertType(fnType.getReturnType());1949 1950  // Create the LLVM function operation.1951  mlir::Type llvmFnTy = mlir::LLVM::LLVMFunctionType::get(1952      resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),1953      signatureConversion.getConvertedTypes(),1954      /*isVarArg=*/fnType.isVarArg());1955 1956  // If this is an alias, it needs to be lowered to llvm::AliasOp.1957  if (std::optional<llvm::StringRef> aliasee = op.getAliasee())1958    return matchAndRewriteAlias(op, *aliasee, llvmFnTy, adaptor, rewriter);1959 1960  // LLVMFuncOp expects a single FileLine Location instead of a fused1961  // location.1962  mlir::Location loc = op.getLoc();1963  if (mlir::FusedLoc fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc))1964    loc = fusedLoc.getLocations()[0];1965  assert((mlir::isa<mlir::FileLineColLoc>(loc) ||1966          mlir::isa<mlir::UnknownLoc>(loc)) &&1967         "expected single location or unknown location here");1968 1969  mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());1970  assert(!cir::MissingFeatures::opFuncCallingConv());1971  mlir::LLVM::CConv cconv = mlir::LLVM::CConv::C;1972  SmallVector<mlir::NamedAttribute, 4> attributes;1973  lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);1974 1975  mlir::LLVM::LLVMFuncOp fn = mlir::LLVM::LLVMFuncOp::create(1976      rewriter, loc, op.getName(), llvmFnTy, linkage, isDsoLocal, cconv,1977      mlir::SymbolRefAttr(), attributes);1978 1979  assert(!cir::MissingFeatures::opFuncMultipleReturnVals());1980 1981  if (auto inlineKind = op.getInlineKind()) {1982    fn.setNoInline(inlineKind == cir::InlineKind::NoInline);1983    fn.setInlineHint(inlineKind == cir::InlineKind::InlineHint);1984    fn.setAlwaysInline(inlineKind == cir::InlineKind::AlwaysInline);1985  }1986 1987  fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(1988      getContext(), lowerCIRVisibilityToLLVMVisibility(1989                        op.getGlobalVisibilityAttr().getValue())));1990 1991  rewriter.inlineRegionBefore(op.getBody(), fn.getBody(), fn.end());1992  if (failed(rewriter.convertRegionTypes(&fn.getBody(), *typeConverter,1993                                         &signatureConversion)))1994    return mlir::failure();1995 1996  rewriter.eraseOp(op);1997 1998  return mlir::LogicalResult::success();1999}2000 2001mlir::LogicalResult CIRToLLVMGetGlobalOpLowering::matchAndRewrite(2002    cir::GetGlobalOp op, OpAdaptor adaptor,2003    mlir::ConversionPatternRewriter &rewriter) const {2004  // FIXME(cir): Premature DCE to avoid lowering stuff we're not using.2005  // CIRGen should mitigate this and not emit the get_global.2006  if (op->getUses().empty()) {2007    rewriter.eraseOp(op);2008    return mlir::success();2009  }2010 2011  mlir::Type type = getTypeConverter()->convertType(op.getType());2012  mlir::Operation *newop = mlir::LLVM::AddressOfOp::create(2013      rewriter, op.getLoc(), type, op.getName());2014 2015  assert(!cir::MissingFeatures::opGlobalThreadLocal());2016 2017  rewriter.replaceOp(op, newop);2018  return mlir::success();2019}2020 2021/// Replace CIR global with a region initialized LLVM global and update2022/// insertion point to the end of the initializer block.2023void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(2024    cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {2025  const mlir::Type llvmType =2026      convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());2027 2028  // FIXME: These default values are placeholders until the the equivalent2029  //        attributes are available on cir.global ops. This duplicates code2030  //        in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go2031  //        away when the placeholders are no longer needed.2032  const bool isConst = op.getConstant();2033  assert(!cir::MissingFeatures::addressSpace());2034  const unsigned addrSpace = 0;2035  const bool isDsoLocal = op.getDsoLocal();2036  assert(!cir::MissingFeatures::opGlobalThreadLocal());2037  const bool isThreadLocal = false;2038  const uint64_t alignment = op.getAlignment().value_or(0);2039  const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());2040  const StringRef symbol = op.getSymName();2041  mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);2042 2043  SmallVector<mlir::NamedAttribute> attributes;2044  mlir::LLVM::GlobalOp newGlobalOp =2045      rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(2046          op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,2047          isDsoLocal, isThreadLocal, comdatAttr, attributes);2048  newGlobalOp.getRegion().emplaceBlock();2049  rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());2050}2051 2052mlir::LogicalResult2053CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(2054    cir::GlobalOp op, mlir::Attribute init,2055    mlir::ConversionPatternRewriter &rewriter) const {2056  // TODO: Generalize this handling when more types are needed here.2057  assert(2058      (isa<cir::ConstArrayAttr, cir::ConstRecordAttr, cir::ConstVectorAttr,2059           cir::ConstPtrAttr, cir::ConstComplexAttr, cir::GlobalViewAttr,2060           cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr, cir::ZeroAttr>(2061          init)));2062 2063  // TODO(cir): once LLVM's dialect has proper equivalent attributes this2064  // should be updated. For now, we use a custom op to initialize globals2065  // to the appropriate value.2066  const mlir::Location loc = op.getLoc();2067  setupRegionInitializedLLVMGlobalOp(op, rewriter);2068  CIRAttrToValue valueConverter(op, rewriter, typeConverter);2069  mlir::Value value = valueConverter.visit(init);2070  mlir::LLVM::ReturnOp::create(rewriter, loc, value);2071  return mlir::success();2072}2073 2074mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(2075    cir::GlobalOp op, OpAdaptor adaptor,2076    mlir::ConversionPatternRewriter &rewriter) const {2077  // If this global requires non-trivial initialization or destruction,2078  // that needs to be moved to runtime handlers during LoweringPrepare.2079  if (!op.getCtorRegion().empty() || !op.getDtorRegion().empty())2080    return op.emitError() << "GlobalOp ctor and dtor regions should be removed "2081                             "in LoweringPrepare";2082 2083  std::optional<mlir::Attribute> init = op.getInitialValue();2084 2085  // Fetch required values to create LLVM op.2086  const mlir::Type cirSymType = op.getSymType();2087 2088  // This is the LLVM dialect type.2089  const mlir::Type llvmType =2090      convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType);2091  // FIXME: These default values are placeholders until the the equivalent2092  //        attributes are available on cir.global ops.2093  const bool isConst = op.getConstant();2094  assert(!cir::MissingFeatures::addressSpace());2095  const unsigned addrSpace = 0;2096  const bool isDsoLocal = op.getDsoLocal();2097  assert(!cir::MissingFeatures::opGlobalThreadLocal());2098  const bool isThreadLocal = false;2099  const uint64_t alignment = op.getAlignment().value_or(0);2100  const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());2101  const StringRef symbol = op.getSymName();2102  SmallVector<mlir::NamedAttribute> attributes;2103 2104  if (init.has_value()) {2105    if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {2106      GlobalInitAttrRewriter initRewriter(llvmType, rewriter);2107      init = initRewriter.visit(init.value());2108      // If initRewriter returned a null attribute, init will have a value but2109      // the value will be null. If that happens, initRewriter didn't handle the2110      // attribute type. It probably needs to be added to2111      // GlobalInitAttrRewriter.2112      if (!init.value()) {2113        op.emitError() << "unsupported initializer '" << init.value() << "'";2114        return mlir::failure();2115      }2116    } else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,2117                         cir::ConstRecordAttr, cir::ConstPtrAttr,2118                         cir::ConstComplexAttr, cir::GlobalViewAttr,2119                         cir::TypeInfoAttr, cir::UndefAttr, cir::VTableAttr,2120                         cir::ZeroAttr>(init.value())) {2121      // TODO(cir): once LLVM's dialect has proper equivalent attributes this2122      // should be updated. For now, we use a custom op to initialize globals2123      // to the appropriate value.2124      return matchAndRewriteRegionInitializedGlobal(op, init.value(), rewriter);2125    } else {2126      // We will only get here if new initializer types are added and this2127      // code is not updated to handle them.2128      op.emitError() << "unsupported initializer '" << init.value() << "'";2129      return mlir::failure();2130    }2131  }2132 2133  // Rewrite op.2134  mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);2135  auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(2136      op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),2137      alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);2138  newOp.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(2139      getContext(), lowerCIRVisibilityToLLVMVisibility(2140                        op.getGlobalVisibilityAttr().getValue())));2141 2142  return mlir::success();2143}2144 2145mlir::SymbolRefAttr2146CIRToLLVMGlobalOpLowering::getComdatAttr(cir::GlobalOp &op,2147                                         mlir::OpBuilder &builder) const {2148  if (!op.getComdat())2149    return mlir::SymbolRefAttr{};2150 2151  mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();2152  mlir::OpBuilder::InsertionGuard guard(builder);2153  StringRef comdatName("__llvm_comdat_globals");2154  if (!comdatOp) {2155    builder.setInsertionPointToStart(module.getBody());2156    comdatOp =2157        mlir::LLVM::ComdatOp::create(builder, module.getLoc(), comdatName);2158  }2159 2160  if (auto comdatSelector = comdatOp.lookupSymbol<mlir::LLVM::ComdatSelectorOp>(2161          op.getSymName())) {2162    return mlir::SymbolRefAttr::get(2163        builder.getContext(), comdatName,2164        mlir::FlatSymbolRefAttr::get(comdatSelector.getSymNameAttr()));2165  }2166 2167  builder.setInsertionPointToStart(&comdatOp.getBody().back());2168  auto selectorOp = mlir::LLVM::ComdatSelectorOp::create(2169      builder, comdatOp.getLoc(), op.getSymName(),2170      mlir::LLVM::comdat::Comdat::Any);2171  return mlir::SymbolRefAttr::get(2172      builder.getContext(), comdatName,2173      mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr()));2174}2175 2176mlir::LogicalResult CIRToLLVMSwitchFlatOpLowering::matchAndRewrite(2177    cir::SwitchFlatOp op, OpAdaptor adaptor,2178    mlir::ConversionPatternRewriter &rewriter) const {2179 2180  llvm::SmallVector<mlir::APInt, 8> caseValues;2181  for (mlir::Attribute val : op.getCaseValues()) {2182    auto intAttr = cast<cir::IntAttr>(val);2183    caseValues.push_back(intAttr.getValue());2184  }2185 2186  llvm::SmallVector<mlir::Block *, 8> caseDestinations;2187  llvm::SmallVector<mlir::ValueRange, 8> caseOperands;2188 2189  for (mlir::Block *x : op.getCaseDestinations())2190    caseDestinations.push_back(x);2191 2192  for (mlir::OperandRange x : op.getCaseOperands())2193    caseOperands.push_back(x);2194 2195  // Set switch op to branch to the newly created blocks.2196  rewriter.setInsertionPoint(op);2197  rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(2198      op, adaptor.getCondition(), op.getDefaultDestination(),2199      op.getDefaultOperands(), caseValues, caseDestinations, caseOperands);2200  return mlir::success();2201}2202 2203mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(2204    cir::UnaryOp op, OpAdaptor adaptor,2205    mlir::ConversionPatternRewriter &rewriter) const {2206  assert(op.getType() == op.getInput().getType() &&2207         "Unary operation's operand type and result type are different");2208  mlir::Type type = op.getType();2209  mlir::Type elementType = elementTypeIfVector(type);2210  bool isVector = mlir::isa<cir::VectorType>(type);2211  mlir::Type llvmType = getTypeConverter()->convertType(type);2212  mlir::Location loc = op.getLoc();2213 2214  // Integer unary operations: + - ~ ++ --2215  if (mlir::isa<cir::IntType>(elementType)) {2216    mlir::LLVM::IntegerOverflowFlags maybeNSW =2217        op.getNoSignedWrap() ? mlir::LLVM::IntegerOverflowFlags::nsw2218                             : mlir::LLVM::IntegerOverflowFlags::none;2219    switch (op.getKind()) {2220    case cir::UnaryOpKind::Inc: {2221      assert(!isVector && "++ not allowed on vector types");2222      auto one = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, 1);2223      rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(2224          op, llvmType, adaptor.getInput(), one, maybeNSW);2225      return mlir::success();2226    }2227    case cir::UnaryOpKind::Dec: {2228      assert(!isVector && "-- not allowed on vector types");2229      auto one = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, 1);2230      rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, adaptor.getInput(),2231                                                     one, maybeNSW);2232      return mlir::success();2233    }2234    case cir::UnaryOpKind::Plus:2235      rewriter.replaceOp(op, adaptor.getInput());2236      return mlir::success();2237    case cir::UnaryOpKind::Minus: {2238      mlir::Value zero;2239      if (isVector)2240        zero = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmType);2241      else2242        zero = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, 0);2243      rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(2244          op, zero, adaptor.getInput(), maybeNSW);2245      return mlir::success();2246    }2247    case cir::UnaryOpKind::Not: {2248      // bit-wise compliment operator, implemented as an XOR with -1.2249      mlir::Value minusOne;2250      if (isVector) {2251        const uint64_t numElements =2252            mlir::dyn_cast<cir::VectorType>(type).getSize();2253        std::vector<int32_t> values(numElements, -1);2254        mlir::DenseIntElementsAttr denseVec = rewriter.getI32VectorAttr(values);2255        minusOne =2256            mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, denseVec);2257      } else {2258        minusOne = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, -1);2259      }2260      rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),2261                                                     minusOne);2262      return mlir::success();2263    }2264    }2265    llvm_unreachable("Unexpected unary op for int");2266  }2267 2268  // Floating point unary operations: + - ++ --2269  if (mlir::isa<cir::FPTypeInterface>(elementType)) {2270    switch (op.getKind()) {2271    case cir::UnaryOpKind::Inc: {2272      assert(!isVector && "++ not allowed on vector types");2273      mlir::LLVM::ConstantOp one = mlir::LLVM::ConstantOp::create(2274          rewriter, loc, llvmType, rewriter.getFloatAttr(llvmType, 1.0));2275      rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, one,2276                                                      adaptor.getInput());2277      return mlir::success();2278    }2279    case cir::UnaryOpKind::Dec: {2280      assert(!isVector && "-- not allowed on vector types");2281      mlir::LLVM::ConstantOp minusOne = mlir::LLVM::ConstantOp::create(2282          rewriter, loc, llvmType, rewriter.getFloatAttr(llvmType, -1.0));2283      rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, minusOne,2284                                                      adaptor.getInput());2285      return mlir::success();2286    }2287    case cir::UnaryOpKind::Plus:2288      rewriter.replaceOp(op, adaptor.getInput());2289      return mlir::success();2290    case cir::UnaryOpKind::Minus:2291      rewriter.replaceOpWithNewOp<mlir::LLVM::FNegOp>(op, llvmType,2292                                                      adaptor.getInput());2293      return mlir::success();2294    case cir::UnaryOpKind::Not:2295      return op.emitError() << "Unary not is invalid for floating-point types";2296    }2297    llvm_unreachable("Unexpected unary op for float");2298  }2299 2300  // Boolean unary operations: ! only. (For all others, the operand has2301  // already been promoted to int.)2302  if (mlir::isa<cir::BoolType>(elementType)) {2303    switch (op.getKind()) {2304    case cir::UnaryOpKind::Inc:2305    case cir::UnaryOpKind::Dec:2306    case cir::UnaryOpKind::Plus:2307    case cir::UnaryOpKind::Minus:2308      // Some of these are allowed in source code, but we shouldn't get here2309      // with a boolean type.2310      return op.emitError() << "Unsupported unary operation on boolean type";2311    case cir::UnaryOpKind::Not: {2312      assert(!isVector && "NYI: op! on vector mask");2313      auto one = mlir::LLVM::ConstantOp::create(rewriter, loc, llvmType, 1);2314      rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),2315                                                     one);2316      return mlir::success();2317    }2318    }2319    llvm_unreachable("Unexpected unary op for bool");2320  }2321 2322  // Pointer unary operations: + only.  (++ and -- of pointers are implemented2323  // with cir.ptr_stride, not cir.unary.)2324  if (mlir::isa<cir::PointerType>(elementType)) {2325    switch (op.getKind()) {2326    case cir::UnaryOpKind::Plus:2327      rewriter.replaceOp(op, adaptor.getInput());2328      return mlir::success();2329    default:2330      op.emitError() << "Unknown pointer unary operation during CIR lowering";2331      return mlir::failure();2332    }2333  }2334 2335  return op.emitError() << "Unary operation has unsupported type: "2336                        << elementType;2337}2338 2339mlir::LLVM::IntegerOverflowFlags2340CIRToLLVMBinOpLowering::getIntOverflowFlag(cir::BinOp op) const {2341  if (op.getNoUnsignedWrap())2342    return mlir::LLVM::IntegerOverflowFlags::nuw;2343 2344  if (op.getNoSignedWrap())2345    return mlir::LLVM::IntegerOverflowFlags::nsw;2346 2347  return mlir::LLVM::IntegerOverflowFlags::none;2348}2349 2350static bool isIntTypeUnsigned(mlir::Type type) {2351  // TODO: Ideally, we should only need to check cir::IntType here.2352  return mlir::isa<cir::IntType>(type)2353             ? mlir::cast<cir::IntType>(type).isUnsigned()2354             : mlir::cast<mlir::IntegerType>(type).isUnsigned();2355}2356 2357mlir::LogicalResult CIRToLLVMBinOpLowering::matchAndRewrite(2358    cir::BinOp op, OpAdaptor adaptor,2359    mlir::ConversionPatternRewriter &rewriter) const {2360  if (adaptor.getLhs().getType() != adaptor.getRhs().getType())2361    return op.emitError() << "inconsistent operands' types not supported yet";2362 2363  mlir::Type type = op.getRhs().getType();2364  if (!mlir::isa<cir::IntType, cir::BoolType, cir::FPTypeInterface,2365                 mlir::IntegerType, cir::VectorType>(type))2366    return op.emitError() << "operand type not supported yet";2367 2368  const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());2369  const mlir::Type llvmEltTy = elementTypeIfVector(llvmTy);2370 2371  const mlir::Value rhs = adaptor.getRhs();2372  const mlir::Value lhs = adaptor.getLhs();2373  type = elementTypeIfVector(type);2374 2375  switch (op.getKind()) {2376  case cir::BinOpKind::Add:2377    if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {2378      if (op.getSaturated()) {2379        if (isIntTypeUnsigned(type)) {2380          rewriter.replaceOpWithNewOp<mlir::LLVM::UAddSat>(op, lhs, rhs);2381          break;2382        }2383        rewriter.replaceOpWithNewOp<mlir::LLVM::SAddSat>(op, lhs, rhs);2384        break;2385      }2386      rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(op, llvmTy, lhs, rhs,2387                                                     getIntOverflowFlag(op));2388    } else {2389      rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, lhs, rhs);2390    }2391    break;2392  case cir::BinOpKind::Sub:2393    if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {2394      if (op.getSaturated()) {2395        if (isIntTypeUnsigned(type)) {2396          rewriter.replaceOpWithNewOp<mlir::LLVM::USubSat>(op, lhs, rhs);2397          break;2398        }2399        rewriter.replaceOpWithNewOp<mlir::LLVM::SSubSat>(op, lhs, rhs);2400        break;2401      }2402      rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmTy, lhs, rhs,2403                                                     getIntOverflowFlag(op));2404    } else {2405      rewriter.replaceOpWithNewOp<mlir::LLVM::FSubOp>(op, lhs, rhs);2406    }2407    break;2408  case cir::BinOpKind::Mul:2409    if (mlir::isa<mlir::IntegerType>(llvmEltTy))2410      rewriter.replaceOpWithNewOp<mlir::LLVM::MulOp>(op, llvmTy, lhs, rhs,2411                                                     getIntOverflowFlag(op));2412    else2413      rewriter.replaceOpWithNewOp<mlir::LLVM::FMulOp>(op, lhs, rhs);2414    break;2415  case cir::BinOpKind::Div:2416    if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {2417      auto isUnsigned = isIntTypeUnsigned(type);2418      if (isUnsigned)2419        rewriter.replaceOpWithNewOp<mlir::LLVM::UDivOp>(op, lhs, rhs);2420      else2421        rewriter.replaceOpWithNewOp<mlir::LLVM::SDivOp>(op, lhs, rhs);2422    } else {2423      rewriter.replaceOpWithNewOp<mlir::LLVM::FDivOp>(op, lhs, rhs);2424    }2425    break;2426  case cir::BinOpKind::Rem:2427    if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {2428      auto isUnsigned = isIntTypeUnsigned(type);2429      if (isUnsigned)2430        rewriter.replaceOpWithNewOp<mlir::LLVM::URemOp>(op, lhs, rhs);2431      else2432        rewriter.replaceOpWithNewOp<mlir::LLVM::SRemOp>(op, lhs, rhs);2433    } else {2434      rewriter.replaceOpWithNewOp<mlir::LLVM::FRemOp>(op, lhs, rhs);2435    }2436    break;2437  case cir::BinOpKind::And:2438    rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, lhs, rhs);2439    break;2440  case cir::BinOpKind::Or:2441    rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, lhs, rhs);2442    break;2443  case cir::BinOpKind::Xor:2444    rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, lhs, rhs);2445    break;2446  case cir::BinOpKind::Max:2447    if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {2448      auto isUnsigned = isIntTypeUnsigned(type);2449      if (isUnsigned)2450        rewriter.replaceOpWithNewOp<mlir::LLVM::UMaxOp>(op, llvmTy, lhs, rhs);2451      else2452        rewriter.replaceOpWithNewOp<mlir::LLVM::SMaxOp>(op, llvmTy, lhs, rhs);2453    }2454    break;2455  }2456  return mlir::LogicalResult::success();2457}2458 2459/// Convert from a CIR comparison kind to an LLVM IR integral comparison kind.2460static mlir::LLVM::ICmpPredicate2461convertCmpKindToICmpPredicate(cir::CmpOpKind kind, bool isSigned) {2462  using CIR = cir::CmpOpKind;2463  using LLVMICmp = mlir::LLVM::ICmpPredicate;2464  switch (kind) {2465  case CIR::eq:2466    return LLVMICmp::eq;2467  case CIR::ne:2468    return LLVMICmp::ne;2469  case CIR::lt:2470    return (isSigned ? LLVMICmp::slt : LLVMICmp::ult);2471  case CIR::le:2472    return (isSigned ? LLVMICmp::sle : LLVMICmp::ule);2473  case CIR::gt:2474    return (isSigned ? LLVMICmp::sgt : LLVMICmp::ugt);2475  case CIR::ge:2476    return (isSigned ? LLVMICmp::sge : LLVMICmp::uge);2477  }2478  llvm_unreachable("Unknown CmpOpKind");2479}2480 2481/// Convert from a CIR comparison kind to an LLVM IR floating-point comparison2482/// kind.2483static mlir::LLVM::FCmpPredicate2484convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {2485  using CIR = cir::CmpOpKind;2486  using LLVMFCmp = mlir::LLVM::FCmpPredicate;2487  switch (kind) {2488  case CIR::eq:2489    return LLVMFCmp::oeq;2490  case CIR::ne:2491    return LLVMFCmp::une;2492  case CIR::lt:2493    return LLVMFCmp::olt;2494  case CIR::le:2495    return LLVMFCmp::ole;2496  case CIR::gt:2497    return LLVMFCmp::ogt;2498  case CIR::ge:2499    return LLVMFCmp::oge;2500  }2501  llvm_unreachable("Unknown CmpOpKind");2502}2503 2504mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(2505    cir::CmpOp cmpOp, OpAdaptor adaptor,2506    mlir::ConversionPatternRewriter &rewriter) const {2507  mlir::Type type = cmpOp.getLhs().getType();2508 2509  assert(!cir::MissingFeatures::dataMemberType());2510  assert(!cir::MissingFeatures::methodType());2511 2512  if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) {2513    bool isSigned = mlir::isa<cir::IntType>(type)2514                        ? mlir::cast<cir::IntType>(type).isSigned()2515                        : mlir::cast<mlir::IntegerType>(type).isSigned();2516    mlir::LLVM::ICmpPredicate kind =2517        convertCmpKindToICmpPredicate(cmpOp.getKind(), isSigned);2518    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(2519        cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());2520    return mlir::success();2521  }2522 2523  if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {2524    mlir::LLVM::ICmpPredicate kind =2525        convertCmpKindToICmpPredicate(cmpOp.getKind(),2526                                      /* isSigned=*/false);2527    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(2528        cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());2529    return mlir::success();2530  }2531 2532  if (auto vptrTy = mlir::dyn_cast<cir::VPtrType>(type)) {2533    // !cir.vptr is a special case, but it's just a pointer to LLVM.2534    auto kind = convertCmpKindToICmpPredicate(cmpOp.getKind(),2535                                              /* isSigned=*/false);2536    rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(2537        cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());2538    return mlir::success();2539  }2540 2541  if (mlir::isa<cir::FPTypeInterface>(type)) {2542    mlir::LLVM::FCmpPredicate kind =2543        convertCmpKindToFCmpPredicate(cmpOp.getKind());2544    rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(2545        cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());2546    return mlir::success();2547  }2548 2549  if (mlir::isa<cir::ComplexType>(type)) {2550    mlir::Value lhs = adaptor.getLhs();2551    mlir::Value rhs = adaptor.getRhs();2552    mlir::Location loc = cmpOp.getLoc();2553 2554    auto complexType = mlir::cast<cir::ComplexType>(cmpOp.getLhs().getType());2555    mlir::Type complexElemTy =2556        getTypeConverter()->convertType(complexType.getElementType());2557 2558    auto lhsReal = mlir::LLVM::ExtractValueOp::create(2559        rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{0}));2560    auto lhsImag = mlir::LLVM::ExtractValueOp::create(2561        rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{1}));2562    auto rhsReal = mlir::LLVM::ExtractValueOp::create(2563        rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{0}));2564    auto rhsImag = mlir::LLVM::ExtractValueOp::create(2565        rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{1}));2566 2567    if (cmpOp.getKind() == cir::CmpOpKind::eq) {2568      if (complexElemTy.isInteger()) {2569        auto realCmp = mlir::LLVM::ICmpOp::create(2570            rewriter, loc, mlir::LLVM::ICmpPredicate::eq, lhsReal, rhsReal);2571        auto imagCmp = mlir::LLVM::ICmpOp::create(2572            rewriter, loc, mlir::LLVM::ICmpPredicate::eq, lhsImag, rhsImag);2573        rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);2574        return mlir::success();2575      }2576 2577      auto realCmp = mlir::LLVM::FCmpOp::create(2578          rewriter, loc, mlir::LLVM::FCmpPredicate::oeq, lhsReal, rhsReal);2579      auto imagCmp = mlir::LLVM::FCmpOp::create(2580          rewriter, loc, mlir::LLVM::FCmpPredicate::oeq, lhsImag, rhsImag);2581      rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);2582      return mlir::success();2583    }2584 2585    if (cmpOp.getKind() == cir::CmpOpKind::ne) {2586      if (complexElemTy.isInteger()) {2587        auto realCmp = mlir::LLVM::ICmpOp::create(2588            rewriter, loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);2589        auto imagCmp = mlir::LLVM::ICmpOp::create(2590            rewriter, loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);2591        rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);2592        return mlir::success();2593      }2594 2595      auto realCmp = mlir::LLVM::FCmpOp::create(2596          rewriter, loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);2597      auto imagCmp = mlir::LLVM::FCmpOp::create(2598          rewriter, loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);2599      rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);2600      return mlir::success();2601    }2602  }2603 2604  return cmpOp.emitError() << "unsupported type for CmpOp: " << type;2605}2606 2607mlir::LogicalResult CIRToLLVMBinOpOverflowOpLowering::matchAndRewrite(2608    cir::BinOpOverflowOp op, OpAdaptor adaptor,2609    mlir::ConversionPatternRewriter &rewriter) const {2610  mlir::Location loc = op.getLoc();2611  cir::BinOpOverflowKind arithKind = op.getKind();2612  cir::IntType operandTy = op.getLhs().getType();2613  cir::IntType resultTy = op.getResult().getType();2614 2615  EncompassedTypeInfo encompassedTyInfo =2616      computeEncompassedTypeWidth(operandTy, resultTy);2617  mlir::IntegerType encompassedLLVMTy =2618      rewriter.getIntegerType(encompassedTyInfo.width);2619 2620  mlir::Value lhs = adaptor.getLhs();2621  mlir::Value rhs = adaptor.getRhs();2622  if (operandTy.getWidth() < encompassedTyInfo.width) {2623    if (operandTy.isSigned()) {2624      lhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, lhs);2625      rhs = mlir::LLVM::SExtOp::create(rewriter, loc, encompassedLLVMTy, rhs);2626    } else {2627      lhs = mlir::LLVM::ZExtOp::create(rewriter, loc, encompassedLLVMTy, lhs);2628      rhs = mlir::LLVM::ZExtOp::create(rewriter, loc, encompassedLLVMTy, rhs);2629    }2630  }2631 2632  std::string intrinName = getLLVMIntrinName(arithKind, encompassedTyInfo.sign,2633                                             encompassedTyInfo.width);2634  auto intrinNameAttr = mlir::StringAttr::get(op.getContext(), intrinName);2635 2636  mlir::IntegerType overflowLLVMTy = rewriter.getI1Type();2637  auto intrinRetTy = mlir::LLVM::LLVMStructType::getLiteral(2638      rewriter.getContext(), {encompassedLLVMTy, overflowLLVMTy});2639 2640  auto callLLVMIntrinOp = mlir::LLVM::CallIntrinsicOp::create(2641      rewriter, loc, intrinRetTy, intrinNameAttr, mlir::ValueRange{lhs, rhs});2642  mlir::Value intrinRet = callLLVMIntrinOp.getResult(0);2643 2644  mlir::Value result = mlir::LLVM::ExtractValueOp::create(2645                           rewriter, loc, intrinRet, ArrayRef<int64_t>{0})2646                           .getResult();2647  mlir::Value overflow = mlir::LLVM::ExtractValueOp::create(2648                             rewriter, loc, intrinRet, ArrayRef<int64_t>{1})2649                             .getResult();2650 2651  if (resultTy.getWidth() < encompassedTyInfo.width) {2652    mlir::Type resultLLVMTy = getTypeConverter()->convertType(resultTy);2653    auto truncResult =2654        mlir::LLVM::TruncOp::create(rewriter, loc, resultLLVMTy, result);2655 2656    // Extend the truncated result back to the encompassing type to check for2657    // any overflows during the truncation.2658    mlir::Value truncResultExt;2659    if (resultTy.isSigned())2660      truncResultExt = mlir::LLVM::SExtOp::create(2661          rewriter, loc, encompassedLLVMTy, truncResult);2662    else2663      truncResultExt = mlir::LLVM::ZExtOp::create(2664          rewriter, loc, encompassedLLVMTy, truncResult);2665    auto truncOverflow = mlir::LLVM::ICmpOp::create(2666        rewriter, loc, mlir::LLVM::ICmpPredicate::ne, truncResultExt, result);2667 2668    result = truncResult;2669    overflow = mlir::LLVM::OrOp::create(rewriter, loc, overflow, truncOverflow);2670  }2671 2672  mlir::Type boolLLVMTy =2673      getTypeConverter()->convertType(op.getOverflow().getType());2674  if (boolLLVMTy != rewriter.getI1Type())2675    overflow = mlir::LLVM::ZExtOp::create(rewriter, loc, boolLLVMTy, overflow);2676 2677  rewriter.replaceOp(op, mlir::ValueRange{result, overflow});2678 2679  return mlir::success();2680}2681 2682std::string CIRToLLVMBinOpOverflowOpLowering::getLLVMIntrinName(2683    cir::BinOpOverflowKind opKind, bool isSigned, unsigned width) {2684  // The intrinsic name is `@llvm.{s|u}{opKind}.with.overflow.i{width}`2685 2686  std::string name = "llvm.";2687 2688  if (isSigned)2689    name.push_back('s');2690  else2691    name.push_back('u');2692 2693  switch (opKind) {2694  case cir::BinOpOverflowKind::Add:2695    name.append("add.");2696    break;2697  case cir::BinOpOverflowKind::Sub:2698    name.append("sub.");2699    break;2700  case cir::BinOpOverflowKind::Mul:2701    name.append("mul.");2702    break;2703  }2704 2705  name.append("with.overflow.i");2706  name.append(std::to_string(width));2707 2708  return name;2709}2710 2711CIRToLLVMBinOpOverflowOpLowering::EncompassedTypeInfo2712CIRToLLVMBinOpOverflowOpLowering::computeEncompassedTypeWidth(2713    cir::IntType operandTy, cir::IntType resultTy) {2714  bool sign = operandTy.getIsSigned() || resultTy.getIsSigned();2715  unsigned width =2716      std::max(operandTy.getWidth() + (sign && operandTy.isUnsigned()),2717               resultTy.getWidth() + (sign && resultTy.isUnsigned()));2718  return {sign, width};2719}2720 2721mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(2722    cir::ShiftOp op, OpAdaptor adaptor,2723    mlir::ConversionPatternRewriter &rewriter) const {2724  assert((op.getValue().getType() == op.getType()) &&2725         "inconsistent operands' types NYI");2726 2727  const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());2728  mlir::Value amt = adaptor.getAmount();2729  mlir::Value val = adaptor.getValue();2730 2731  auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType());2732  bool isUnsigned;2733  if (cirAmtTy) {2734    auto cirValTy = mlir::cast<cir::IntType>(op.getValue().getType());2735    isUnsigned = cirValTy.isUnsigned();2736 2737    // Ensure shift amount is the same type as the value. Some undefined2738    // behavior might occur in the casts below as per [C99 6.5.7.3].2739    // Vector type shift amount needs no cast as type consistency is expected to2740    // be already be enforced at CIRGen.2741    if (cirAmtTy)2742      amt = getLLVMIntCast(rewriter, amt, llvmTy, true, cirAmtTy.getWidth(),2743                           cirValTy.getWidth());2744  } else {2745    auto cirValVTy = mlir::cast<cir::VectorType>(op.getValue().getType());2746    isUnsigned =2747        mlir::cast<cir::IntType>(cirValVTy.getElementType()).isUnsigned();2748  }2749 2750  // Lower to the proper LLVM shift operation.2751  if (op.getIsShiftleft()) {2752    rewriter.replaceOpWithNewOp<mlir::LLVM::ShlOp>(op, llvmTy, val, amt);2753    return mlir::success();2754  }2755 2756  if (isUnsigned)2757    rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt);2758  else2759    rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt);2760  return mlir::success();2761}2762 2763mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(2764    cir::SelectOp op, OpAdaptor adaptor,2765    mlir::ConversionPatternRewriter &rewriter) const {2766  auto getConstantBool = [](mlir::Value value) -> cir::BoolAttr {2767    auto definingOp = value.getDefiningOp<cir::ConstantOp>();2768    if (!definingOp)2769      return {};2770 2771    auto constValue = definingOp.getValueAttr<cir::BoolAttr>();2772    if (!constValue)2773      return {};2774 2775    return constValue;2776  };2777 2778  // Two special cases in the LLVMIR codegen of select op:2779  // - select %0, %1, false => and %0, %12780  // - select %0, true, %1 => or %0, %12781  if (mlir::isa<cir::BoolType>(op.getTrueValue().getType())) {2782    cir::BoolAttr trueValue = getConstantBool(op.getTrueValue());2783    cir::BoolAttr falseValue = getConstantBool(op.getFalseValue());2784    if (falseValue && !falseValue.getValue()) {2785      // select %0, %1, false => and %0, %12786      rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, adaptor.getCondition(),2787                                                     adaptor.getTrueValue());2788      return mlir::success();2789    }2790    if (trueValue && trueValue.getValue()) {2791      // select %0, true, %1 => or %0, %12792      rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, adaptor.getCondition(),2793                                                    adaptor.getFalseValue());2794      return mlir::success();2795    }2796  }2797 2798  mlir::Value llvmCondition = adaptor.getCondition();2799  rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(2800      op, llvmCondition, adaptor.getTrueValue(), adaptor.getFalseValue());2801 2802  return mlir::success();2803}2804 2805static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,2806                                 mlir::DataLayout &dataLayout) {2807  converter.addConversion([&](cir::PointerType type) -> mlir::Type {2808    unsigned addrSpace =2809        type.getAddrSpace() ? type.getAddrSpace().getValue().getUInt() : 0;2810    return mlir::LLVM::LLVMPointerType::get(type.getContext(), addrSpace);2811  });2812  converter.addConversion([&](cir::VPtrType type) -> mlir::Type {2813    assert(!cir::MissingFeatures::addressSpace());2814    return mlir::LLVM::LLVMPointerType::get(type.getContext());2815  });2816  converter.addConversion([&](cir::ArrayType type) -> mlir::Type {2817    mlir::Type ty =2818        convertTypeForMemory(converter, dataLayout, type.getElementType());2819    return mlir::LLVM::LLVMArrayType::get(ty, type.getSize());2820  });2821  converter.addConversion([&](cir::VectorType type) -> mlir::Type {2822    const mlir::Type ty = converter.convertType(type.getElementType());2823    return mlir::VectorType::get(type.getSize(), ty);2824  });2825  converter.addConversion([&](cir::BoolType type) -> mlir::Type {2826    return mlir::IntegerType::get(type.getContext(), 1,2827                                  mlir::IntegerType::Signless);2828  });2829  converter.addConversion([&](cir::IntType type) -> mlir::Type {2830    // LLVM doesn't work with signed types, so we drop the CIR signs here.2831    return mlir::IntegerType::get(type.getContext(), type.getWidth());2832  });2833  converter.addConversion([&](cir::SingleType type) -> mlir::Type {2834    return mlir::Float32Type::get(type.getContext());2835  });2836  converter.addConversion([&](cir::DoubleType type) -> mlir::Type {2837    return mlir::Float64Type::get(type.getContext());2838  });2839  converter.addConversion([&](cir::FP80Type type) -> mlir::Type {2840    return mlir::Float80Type::get(type.getContext());2841  });2842  converter.addConversion([&](cir::FP128Type type) -> mlir::Type {2843    return mlir::Float128Type::get(type.getContext());2844  });2845  converter.addConversion([&](cir::LongDoubleType type) -> mlir::Type {2846    return converter.convertType(type.getUnderlying());2847  });2848  converter.addConversion([&](cir::FP16Type type) -> mlir::Type {2849    return mlir::Float16Type::get(type.getContext());2850  });2851  converter.addConversion([&](cir::BF16Type type) -> mlir::Type {2852    return mlir::BFloat16Type::get(type.getContext());2853  });2854  converter.addConversion([&](cir::ComplexType type) -> mlir::Type {2855    // A complex type is lowered to an LLVM struct that contains the real and2856    // imaginary part as data fields.2857    mlir::Type elementTy = converter.convertType(type.getElementType());2858    mlir::Type structFields[2] = {elementTy, elementTy};2859    return mlir::LLVM::LLVMStructType::getLiteral(type.getContext(),2860                                                  structFields);2861  });2862  converter.addConversion([&](cir::FuncType type) -> std::optional<mlir::Type> {2863    auto result = converter.convertType(type.getReturnType());2864    llvm::SmallVector<mlir::Type> arguments;2865    arguments.reserve(type.getNumInputs());2866    if (converter.convertTypes(type.getInputs(), arguments).failed())2867      return std::nullopt;2868    auto varArg = type.isVarArg();2869    return mlir::LLVM::LLVMFunctionType::get(result, arguments, varArg);2870  });2871  converter.addConversion([&](cir::RecordType type) -> mlir::Type {2872    // Convert struct members.2873    llvm::SmallVector<mlir::Type> llvmMembers;2874    switch (type.getKind()) {2875    case cir::RecordType::Class:2876    case cir::RecordType::Struct:2877      for (mlir::Type ty : type.getMembers())2878        llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));2879      break;2880    // Unions are lowered as only the largest member.2881    case cir::RecordType::Union:2882      if (auto largestMember = type.getLargestMember(dataLayout))2883        llvmMembers.push_back(2884            convertTypeForMemory(converter, dataLayout, largestMember));2885      if (type.getPadded()) {2886        auto last = *type.getMembers().rbegin();2887        llvmMembers.push_back(2888            convertTypeForMemory(converter, dataLayout, last));2889      }2890      break;2891    }2892 2893    // Record has a name: lower as an identified record.2894    mlir::LLVM::LLVMStructType llvmStruct;2895    if (type.getName()) {2896      llvmStruct = mlir::LLVM::LLVMStructType::getIdentified(2897          type.getContext(), type.getPrefixedName());2898      if (llvmStruct.setBody(llvmMembers, type.getPacked()).failed())2899        llvm_unreachable("Failed to set body of record");2900    } else { // Record has no name: lower as literal record.2901      llvmStruct = mlir::LLVM::LLVMStructType::getLiteral(2902          type.getContext(), llvmMembers, type.getPacked());2903    }2904 2905    return llvmStruct;2906  });2907  converter.addConversion([&](cir::VoidType type) -> mlir::Type {2908    return mlir::LLVM::LLVMVoidType::get(type.getContext());2909  });2910}2911 2912static void buildCtorDtorList(2913    mlir::ModuleOp module, StringRef globalXtorName, StringRef llvmXtorName,2914    llvm::function_ref<std::pair<StringRef, int>(mlir::Attribute)> createXtor) {2915  llvm::SmallVector<std::pair<StringRef, int>> globalXtors;2916  for (const mlir::NamedAttribute namedAttr : module->getAttrs()) {2917    if (namedAttr.getName() == globalXtorName) {2918      for (auto attr : mlir::cast<mlir::ArrayAttr>(namedAttr.getValue()))2919        globalXtors.emplace_back(createXtor(attr));2920      break;2921    }2922  }2923 2924  if (globalXtors.empty())2925    return;2926 2927  mlir::OpBuilder builder(module.getContext());2928  builder.setInsertionPointToEnd(&module.getBodyRegion().back());2929 2930  // Create a global array llvm.global_ctors with element type of2931  // struct { i32, ptr, ptr }2932  auto ctorPFTy = mlir::LLVM::LLVMPointerType::get(builder.getContext());2933  llvm::SmallVector<mlir::Type> ctorStructFields;2934  ctorStructFields.push_back(builder.getI32Type());2935  ctorStructFields.push_back(ctorPFTy);2936  ctorStructFields.push_back(ctorPFTy);2937 2938  auto ctorStructTy = mlir::LLVM::LLVMStructType::getLiteral(2939      builder.getContext(), ctorStructFields);2940  auto ctorStructArrayTy =2941      mlir::LLVM::LLVMArrayType::get(ctorStructTy, globalXtors.size());2942 2943  mlir::Location loc = module.getLoc();2944  auto newGlobalOp = mlir::LLVM::GlobalOp::create(2945      builder, loc, ctorStructArrayTy, /*constant=*/false,2946      mlir::LLVM::Linkage::Appending, llvmXtorName, mlir::Attribute());2947 2948  builder.createBlock(&newGlobalOp.getRegion());2949  builder.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());2950 2951  mlir::Value result =2952      mlir::LLVM::UndefOp::create(builder, loc, ctorStructArrayTy);2953 2954  for (auto [index, fn] : llvm::enumerate(globalXtors)) {2955    mlir::Value structInit =2956        mlir::LLVM::UndefOp::create(builder, loc, ctorStructTy);2957    mlir::Value initPriority = mlir::LLVM::ConstantOp::create(2958        builder, loc, ctorStructFields[0], fn.second);2959    mlir::Value initFuncAddr = mlir::LLVM::AddressOfOp::create(2960        builder, loc, ctorStructFields[1], fn.first);2961    mlir::Value initAssociate =2962        mlir::LLVM::ZeroOp::create(builder, loc, ctorStructFields[2]);2963    // Literal zero makes the InsertValueOp::create ambiguous.2964    llvm::SmallVector<int64_t> zero{0};2965    structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,2966                                                   initPriority, zero);2967    structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,2968                                                   initFuncAddr, 1);2969    // TODO: handle associated data for initializers.2970    structInit = mlir::LLVM::InsertValueOp::create(builder, loc, structInit,2971                                                   initAssociate, 2);2972    result = mlir::LLVM::InsertValueOp::create(builder, loc, result, structInit,2973                                               index);2974  }2975 2976  mlir::LLVM::ReturnOp::create(builder, loc, result);2977}2978 2979// The applyPartialConversion function traverses blocks in the dominance order,2980// so it does not lower and operations that are not reachachable from the2981// operations passed in as arguments. Since we do need to lower such code in2982// order to avoid verification errors occur, we cannot just pass the module op2983// to applyPartialConversion. We must build a set of unreachable ops and2984// explicitly add them, along with the module, to the vector we pass to2985// applyPartialConversion.2986//2987// For instance, this CIR code:2988//2989//    cir.func @foo(%arg0: !s32i) -> !s32i {2990//      %4 = cir.cast int_to_bool %arg0 : !s32i -> !cir.bool2991//      cir.if %4 {2992//        %5 = cir.const #cir.int<1> : !s32i2993//        cir.return %5 : !s32i2994//      } else {2995//        %5 = cir.const #cir.int<0> : !s32i2996//       cir.return %5 : !s32i2997//      }2998//      cir.return %arg0 : !s32i2999//    }3000//3001// contains an unreachable return operation (the last one). After the flattening3002// pass it will be placed into the unreachable block. The possible error3003// after the lowering pass is: error: 'cir.return' op expects parent op to be3004// one of 'cir.func, cir.scope, cir.if ... The reason that this operation was3005// not lowered and the new parent is llvm.func.3006//3007// In the future we may want to get rid of this function and use a DCE pass or3008// something similar. But for now we need to guarantee the absence of the3009// dialect verification errors.3010static void collectUnreachable(mlir::Operation *parent,3011                               llvm::SmallVector<mlir::Operation *> &ops) {3012 3013  llvm::SmallVector<mlir::Block *> unreachableBlocks;3014  parent->walk([&](mlir::Block *blk) { // check3015    if (blk->hasNoPredecessors() && !blk->isEntryBlock())3016      unreachableBlocks.push_back(blk);3017  });3018 3019  std::set<mlir::Block *> visited;3020  for (mlir::Block *root : unreachableBlocks) {3021    // We create a work list for each unreachable block.3022    // Thus we traverse operations in some order.3023    std::deque<mlir::Block *> workList;3024    workList.push_back(root);3025 3026    while (!workList.empty()) {3027      mlir::Block *blk = workList.back();3028      workList.pop_back();3029      if (visited.count(blk))3030        continue;3031      visited.emplace(blk);3032 3033      for (mlir::Operation &op : *blk)3034        ops.push_back(&op);3035 3036      for (mlir::Block *succ : blk->getSuccessors())3037        workList.push_back(succ);3038    }3039  }3040}3041 3042mlir::LogicalResult CIRToLLVMObjSizeOpLowering::matchAndRewrite(3043    cir::ObjSizeOp op, OpAdaptor adaptor,3044    mlir::ConversionPatternRewriter &rewriter) const {3045  mlir::Type llvmResTy = getTypeConverter()->convertType(op.getType());3046  mlir::Location loc = op->getLoc();3047 3048  mlir::IntegerType i1Ty = rewriter.getI1Type();3049 3050  auto i1Val = [&rewriter, &loc, &i1Ty](bool val) {3051    return mlir::LLVM::ConstantOp::create(rewriter, loc, i1Ty, val);3052  };3053 3054  replaceOpWithCallLLVMIntrinsicOp(rewriter, op, "llvm.objectsize", llvmResTy,3055                                   {3056                                       adaptor.getPtr(),3057                                       i1Val(op.getMin()),3058                                       i1Val(op.getNullunknown()),3059                                       i1Val(op.getDynamic()),3060                                   });3061 3062  return mlir::LogicalResult::success();3063}3064 3065void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {3066  // Lower the module attributes to LLVM equivalents.3067  if (mlir::Attribute tripleAttr =3068          module->getAttr(cir::CIRDialect::getTripleAttrName()))3069    module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),3070                    tripleAttr);3071 3072  if (mlir::Attribute asmAttr =3073          module->getAttr(cir::CIRDialect::getModuleLevelAsmAttrName()))3074    module->setAttr(mlir::LLVM::LLVMDialect::getModuleLevelAsmAttrName(),3075                    asmAttr);3076}3077 3078void ConvertCIRToLLVMPass::runOnOperation() {3079  llvm::TimeTraceScope scope("Convert CIR to LLVM Pass");3080 3081  mlir::ModuleOp module = getOperation();3082  mlir::DataLayout dl(module);3083  mlir::LLVMTypeConverter converter(&getContext());3084  prepareTypeConverter(converter, dl);3085 3086  mlir::RewritePatternSet patterns(&getContext());3087 3088  patterns.add<3089#define GET_LLVM_LOWERING_PATTERNS_LIST3090#include "clang/CIR/Dialect/IR/CIRLowering.inc"3091#undef GET_LLVM_LOWERING_PATTERNS_LIST3092      >(converter, patterns.getContext(), dl);3093 3094  processCIRAttrs(module);3095 3096  mlir::ConversionTarget target(getContext());3097  target.addLegalOp<mlir::ModuleOp>();3098  target.addLegalDialect<mlir::LLVM::LLVMDialect>();3099  target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect,3100                           mlir::func::FuncDialect>();3101 3102  llvm::SmallVector<mlir::Operation *> ops;3103  ops.push_back(module);3104  collectUnreachable(module, ops);3105 3106  if (failed(applyPartialConversion(ops, target, std::move(patterns))))3107    signalPassFailure();3108 3109  // Emit the llvm.global_ctors array.3110  buildCtorDtorList(module, cir::CIRDialect::getGlobalCtorsAttrName(),3111                    "llvm.global_ctors", [](mlir::Attribute attr) {3112                      auto ctorAttr = mlir::cast<cir::GlobalCtorAttr>(attr);3113                      return std::make_pair(ctorAttr.getName(),3114                                            ctorAttr.getPriority());3115                    });3116  // Emit the llvm.global_dtors array.3117  buildCtorDtorList(module, cir::CIRDialect::getGlobalDtorsAttrName(),3118                    "llvm.global_dtors", [](mlir::Attribute attr) {3119                      auto dtorAttr = mlir::cast<cir::GlobalDtorAttr>(attr);3120                      return std::make_pair(dtorAttr.getName(),3121                                            dtorAttr.getPriority());3122                    });3123}3124 3125mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite(3126    cir::BrOp op, OpAdaptor adaptor,3127    mlir::ConversionPatternRewriter &rewriter) const {3128  rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(op, adaptor.getOperands(),3129                                                op.getDest());3130  return mlir::LogicalResult::success();3131}3132 3133mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(3134    cir::GetMemberOp op, OpAdaptor adaptor,3135    mlir::ConversionPatternRewriter &rewriter) const {3136  mlir::Type llResTy = getTypeConverter()->convertType(op.getType());3137  const auto recordTy =3138      mlir::cast<cir::RecordType>(op.getAddrTy().getPointee());3139  assert(recordTy && "expected record type");3140 3141  switch (recordTy.getKind()) {3142  case cir::RecordType::Class:3143  case cir::RecordType::Struct: {3144    // Since the base address is a pointer to an aggregate, the first offset3145    // is always zero. The second offset tell us which member it will access.3146    llvm::SmallVector<mlir::LLVM::GEPArg, 2> offset{0, op.getIndex()};3147    const mlir::Type elementTy = getTypeConverter()->convertType(recordTy);3148    rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, llResTy, elementTy,3149                                                   adaptor.getAddr(), offset);3150    return mlir::success();3151  }3152  case cir::RecordType::Union:3153    // Union members share the address space, so we just need a bitcast to3154    // conform to type-checking.3155    rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(op, llResTy,3156                                                       adaptor.getAddr());3157    return mlir::success();3158  }3159}3160 3161mlir::LogicalResult CIRToLLVMUnreachableOpLowering::matchAndRewrite(3162    cir::UnreachableOp op, OpAdaptor adaptor,3163    mlir::ConversionPatternRewriter &rewriter) const {3164  rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(op);3165  return mlir::success();3166}3167 3168void createLLVMFuncOpIfNotExist(mlir::ConversionPatternRewriter &rewriter,3169                                mlir::Operation *srcOp, llvm::StringRef fnName,3170                                mlir::Type fnTy) {3171  auto modOp = srcOp->getParentOfType<mlir::ModuleOp>();3172  auto enclosingFnOp = srcOp->getParentOfType<mlir::LLVM::LLVMFuncOp>();3173  mlir::Operation *sourceSymbol =3174      mlir::SymbolTable::lookupSymbolIn(modOp, fnName);3175  if (!sourceSymbol) {3176    mlir::OpBuilder::InsertionGuard guard(rewriter);3177    rewriter.setInsertionPoint(enclosingFnOp);3178    mlir::LLVM::LLVMFuncOp::create(rewriter, srcOp->getLoc(), fnName, fnTy);3179  }3180}3181 3182mlir::LogicalResult CIRToLLVMThrowOpLowering::matchAndRewrite(3183    cir::ThrowOp op, OpAdaptor adaptor,3184    mlir::ConversionPatternRewriter &rewriter) const {3185  mlir::Location loc = op.getLoc();3186  auto voidTy = mlir::LLVM::LLVMVoidType::get(getContext());3187 3188  if (op.rethrows()) {3189    auto funcTy = mlir::LLVM::LLVMFunctionType::get(voidTy, {});3190 3191    // Get or create `declare void @__cxa_rethrow()`3192    const llvm::StringRef functionName = "__cxa_rethrow";3193    createLLVMFuncOpIfNotExist(rewriter, op, functionName, funcTy);3194 3195    auto cxaRethrow = mlir::LLVM::CallOp::create(3196        rewriter, loc, mlir::TypeRange{}, functionName);3197 3198    rewriter.replaceOp(op, cxaRethrow);3199    return mlir::success();3200  }3201 3202  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());3203  auto fnTy = mlir::LLVM::LLVMFunctionType::get(3204      voidTy, {llvmPtrTy, llvmPtrTy, llvmPtrTy});3205 3206  // Get or create `declare void @__cxa_throw(ptr, ptr, ptr)`3207  const llvm::StringRef fnName = "__cxa_throw";3208  createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);3209 3210  mlir::Value typeInfo = mlir::LLVM::AddressOfOp::create(3211      rewriter, loc, mlir::LLVM::LLVMPointerType::get(rewriter.getContext()),3212      adaptor.getTypeInfoAttr());3213 3214  mlir::Value dtor;3215  if (op.getDtor()) {3216    dtor = mlir::LLVM::AddressOfOp::create(rewriter, loc, llvmPtrTy,3217                                           adaptor.getDtorAttr());3218  } else {3219    dtor = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);3220  }3221 3222  auto cxaThrowCall = mlir::LLVM::CallOp::create(3223      rewriter, loc, mlir::TypeRange{}, fnName,3224      mlir::ValueRange{adaptor.getExceptionPtr(), typeInfo, dtor});3225 3226  rewriter.replaceOp(op, cxaThrowCall);3227  return mlir::success();3228}3229 3230mlir::LogicalResult CIRToLLVMAllocExceptionOpLowering::matchAndRewrite(3231    cir::AllocExceptionOp op, OpAdaptor adaptor,3232    mlir::ConversionPatternRewriter &rewriter) const {3233  // Get or create `declare ptr @__cxa_allocate_exception(i64)`3234  StringRef fnName = "__cxa_allocate_exception";3235  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());3236  auto int64Ty = mlir::IntegerType::get(rewriter.getContext(), 64);3237  auto fnTy = mlir::LLVM::LLVMFunctionType::get(llvmPtrTy, {int64Ty});3238 3239  createLLVMFuncOpIfNotExist(rewriter, op, fnName, fnTy);3240  auto exceptionSize = mlir::LLVM::ConstantOp::create(rewriter, op.getLoc(),3241                                                      adaptor.getSizeAttr());3242 3243  auto allocaExceptionCall = mlir::LLVM::CallOp::create(3244      rewriter, op.getLoc(), mlir::TypeRange{llvmPtrTy}, fnName,3245      mlir::ValueRange{exceptionSize});3246 3247  rewriter.replaceOp(op, allocaExceptionCall);3248  return mlir::success();3249}3250 3251static mlir::LLVM::LLVMStructType3252getLLVMLandingPadStructTy(mlir::ConversionPatternRewriter &rewriter) {3253  // Create the landing pad type: struct { ptr, i32 }3254  mlir::MLIRContext *ctx = rewriter.getContext();3255  auto llvmPtr = mlir::LLVM::LLVMPointerType::get(ctx);3256  llvm::SmallVector<mlir::Type> structFields = {llvmPtr, rewriter.getI32Type()};3257  return mlir::LLVM::LLVMStructType::getLiteral(ctx, structFields);3258}3259 3260mlir::LogicalResult CIRToLLVMEhInflightOpLowering::matchAndRewrite(3261    cir::EhInflightOp op, OpAdaptor adaptor,3262    mlir::ConversionPatternRewriter &rewriter) const {3263  auto llvmFn = op->getParentOfType<mlir::LLVM::LLVMFuncOp>();3264  assert(llvmFn && "expected LLVM function parent");3265  mlir::Block *entryBlock = &llvmFn.getRegion().front();3266  assert(entryBlock->isEntryBlock());3267 3268  mlir::ArrayAttr catchListAttr = op.getCatchTypeListAttr();3269  mlir::SmallVector<mlir::Value> catchSymAddrs;3270 3271  auto llvmPtrTy = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());3272  mlir::Location loc = op.getLoc();3273 3274  // %landingpad = landingpad { ptr, i32 }3275  // Note that since llvm.landingpad has to be the first operation on the3276  // block, any needed value for its operands has to be added somewhere else.3277  if (catchListAttr) {3278    //   catch ptr @_ZTIi3279    //   catch ptr @_ZTIPKc3280    for (mlir::Attribute catchAttr : catchListAttr) {3281      auto symAttr = cast<mlir::FlatSymbolRefAttr>(catchAttr);3282      // Generate `llvm.mlir.addressof` for each symbol, and place those3283      // operations in the LLVM function entry basic block.3284      mlir::OpBuilder::InsertionGuard guard(rewriter);3285      rewriter.setInsertionPointToStart(entryBlock);3286      mlir::Value addrOp = mlir::LLVM::AddressOfOp::create(3287          rewriter, loc, llvmPtrTy, symAttr.getValue());3288      catchSymAddrs.push_back(addrOp);3289    }3290  } else if (!op.getCleanup()) {3291    // We need to emit catch-all only if cleanup is not set, because when we3292    // have catch-all handler, there is no case when we set would unwind past3293    // the handler3294    mlir::OpBuilder::InsertionGuard guard(rewriter);3295    rewriter.setInsertionPointToStart(entryBlock);3296    mlir::Value nullOp = mlir::LLVM::ZeroOp::create(rewriter, loc, llvmPtrTy);3297    catchSymAddrs.push_back(nullOp);3298  }3299 3300  // %slot = extractvalue { ptr, i32 } %x, 03301  // %selector = extractvalue { ptr, i32 } %x, 13302  mlir::LLVM::LLVMStructType llvmLandingPadStructTy =3303      getLLVMLandingPadStructTy(rewriter);3304  auto landingPadOp = mlir::LLVM::LandingpadOp::create(3305      rewriter, loc, llvmLandingPadStructTy, catchSymAddrs);3306 3307  if (op.getCleanup())3308    landingPadOp.setCleanup(true);3309 3310  mlir::Value slot =3311      mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 0);3312  mlir::Value selector =3313      mlir::LLVM::ExtractValueOp::create(rewriter, loc, landingPadOp, 1);3314  rewriter.replaceOp(op, mlir::ValueRange{slot, selector});3315 3316  // Landing pads are required to be in LLVM functions with personality3317  // attribute.3318  // TODO(cir): for now hardcode personality creation in order to start3319  // adding exception tests, once we annotate CIR with such information,3320  // change it to be in FuncOp lowering instead.3321  mlir::OpBuilder::InsertionGuard guard(rewriter);3322  // Insert personality decl before the current function.3323  rewriter.setInsertionPoint(llvmFn);3324  auto personalityFnTy =3325      mlir::LLVM::LLVMFunctionType::get(rewriter.getI32Type(), {},3326                                        /*isVarArg=*/true);3327 3328  const StringRef fnName = "__gxx_personality_v0";3329  createLLVMFuncOpIfNotExist(rewriter, op, fnName, personalityFnTy);3330  llvmFn.setPersonality(fnName);3331 3332  return mlir::success();3333}3334 3335mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(3336    cir::TrapOp op, OpAdaptor adaptor,3337    mlir::ConversionPatternRewriter &rewriter) const {3338  mlir::Location loc = op->getLoc();3339  rewriter.eraseOp(op);3340 3341  mlir::LLVM::Trap::create(rewriter, loc);3342 3343  // Note that the call to llvm.trap is not a terminator in LLVM dialect.3344  // So we must emit an additional llvm.unreachable to terminate the current3345  // block.3346  mlir::LLVM::UnreachableOp::create(rewriter, loc);3347 3348  return mlir::success();3349}3350 3351static mlir::Value3352getValueForVTableSymbol(mlir::Operation *op,3353                        mlir::ConversionPatternRewriter &rewriter,3354                        const mlir::TypeConverter *converter,3355                        mlir::FlatSymbolRefAttr nameAttr, mlir::Type &eltType) {3356  auto module = op->getParentOfType<mlir::ModuleOp>();3357  mlir::Operation *symbol = mlir::SymbolTable::lookupSymbolIn(module, nameAttr);3358  if (auto llvmSymbol = mlir::dyn_cast<mlir::LLVM::GlobalOp>(symbol)) {3359    eltType = llvmSymbol.getType();3360  } else if (auto cirSymbol = mlir::dyn_cast<cir::GlobalOp>(symbol)) {3361    eltType = converter->convertType(cirSymbol.getSymType());3362  } else {3363    op->emitError() << "unexpected symbol type for " << symbol;3364    return {};3365  }3366 3367  return mlir::LLVM::AddressOfOp::create(3368      rewriter, op->getLoc(),3369      mlir::LLVM::LLVMPointerType::get(op->getContext()), nameAttr.getValue());3370}3371 3372mlir::LogicalResult CIRToLLVMVTableAddrPointOpLowering::matchAndRewrite(3373    cir::VTableAddrPointOp op, OpAdaptor adaptor,3374    mlir::ConversionPatternRewriter &rewriter) const {3375  const mlir::TypeConverter *converter = getTypeConverter();3376  mlir::Type targetType = converter->convertType(op.getType());3377  llvm::SmallVector<mlir::LLVM::GEPArg> offsets;3378  mlir::Type eltType;3379  mlir::Value symAddr = getValueForVTableSymbol(op, rewriter, converter,3380                                                op.getNameAttr(), eltType);3381  if (!symAddr)3382    return op.emitError() << "Unable to get value for vtable symbol";3383 3384  offsets = llvm::SmallVector<mlir::LLVM::GEPArg>{3385      0, op.getAddressPointAttr().getIndex(),3386      op.getAddressPointAttr().getOffset()};3387 3388  assert(eltType && "Shouldn't ever be missing an eltType here");3389  mlir::LLVM::GEPNoWrapFlags inboundsNuw =3390      mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;3391  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, targetType, eltType,3392                                                 symAddr, offsets, inboundsNuw);3393  return mlir::success();3394}3395 3396mlir::LogicalResult CIRToLLVMVTableGetVPtrOpLowering::matchAndRewrite(3397    cir::VTableGetVPtrOp op, OpAdaptor adaptor,3398    mlir::ConversionPatternRewriter &rewriter) const {3399  // cir.vtable.get_vptr is equivalent to a bitcast from the source object3400  // pointer to the vptr type. Since the LLVM dialect uses opaque pointers3401  // we can just replace uses of this operation with the original pointer.3402  mlir::Value srcVal = adaptor.getSrc();3403  rewriter.replaceOp(op, srcVal);3404  return mlir::success();3405}3406 3407mlir::LogicalResult CIRToLLVMVTableGetVirtualFnAddrOpLowering::matchAndRewrite(3408    cir::VTableGetVirtualFnAddrOp op, OpAdaptor adaptor,3409    mlir::ConversionPatternRewriter &rewriter) const {3410  mlir::Type targetType = getTypeConverter()->convertType(op.getType());3411  auto eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());3412  llvm::SmallVector<mlir::LLVM::GEPArg> offsets =3413      llvm::SmallVector<mlir::LLVM::GEPArg>{op.getIndex()};3414  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(3415      op, targetType, eltType, adaptor.getVptr(), offsets,3416      mlir::LLVM::GEPNoWrapFlags::inbounds);3417  return mlir::success();3418}3419 3420mlir::LogicalResult CIRToLLVMVTTAddrPointOpLowering::matchAndRewrite(3421    cir::VTTAddrPointOp op, OpAdaptor adaptor,3422    mlir::ConversionPatternRewriter &rewriter) const {3423  const mlir::Type resultType = getTypeConverter()->convertType(op.getType());3424  llvm::SmallVector<mlir::LLVM::GEPArg> offsets;3425  mlir::Type eltType;3426  mlir::Value llvmAddr = adaptor.getSymAddr();3427 3428  if (op.getSymAddr()) {3429    if (op.getOffset() == 0) {3430      rewriter.replaceOp(op, {llvmAddr});3431      return mlir::success();3432    }3433 3434    offsets.push_back(adaptor.getOffset());3435    eltType = mlir::LLVM::LLVMPointerType::get(rewriter.getContext());3436  } else {3437    llvmAddr = getValueForVTableSymbol(op, rewriter, getTypeConverter(),3438                                       op.getNameAttr(), eltType);3439    assert(eltType && "Shouldn't ever be missing an eltType here");3440    offsets.push_back(0);3441    offsets.push_back(adaptor.getOffset());3442  }3443  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(3444      op, resultType, eltType, llvmAddr, offsets,3445      mlir::LLVM::GEPNoWrapFlags::inbounds);3446  return mlir::success();3447}3448 3449mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite(3450    cir::StackSaveOp op, OpAdaptor adaptor,3451    mlir::ConversionPatternRewriter &rewriter) const {3452  const mlir::Type ptrTy = getTypeConverter()->convertType(op.getType());3453  rewriter.replaceOpWithNewOp<mlir::LLVM::StackSaveOp>(op, ptrTy);3454  return mlir::success();3455}3456 3457mlir::LogicalResult CIRToLLVMStackRestoreOpLowering::matchAndRewrite(3458    cir::StackRestoreOp op, OpAdaptor adaptor,3459    mlir::ConversionPatternRewriter &rewriter) const {3460  rewriter.replaceOpWithNewOp<mlir::LLVM::StackRestoreOp>(op, adaptor.getPtr());3461  return mlir::success();3462}3463 3464mlir::LogicalResult CIRToLLVMVecCreateOpLowering::matchAndRewrite(3465    cir::VecCreateOp op, OpAdaptor adaptor,3466    mlir::ConversionPatternRewriter &rewriter) const {3467  // Start with an 'undef' value for the vector.  Then 'insertelement' for3468  // each of the vector elements.3469  const auto vecTy = mlir::cast<cir::VectorType>(op.getType());3470  const mlir::Type llvmTy = typeConverter->convertType(vecTy);3471  const mlir::Location loc = op.getLoc();3472  mlir::Value result = mlir::LLVM::PoisonOp::create(rewriter, loc, llvmTy);3473  assert(vecTy.getSize() == op.getElements().size() &&3474         "cir.vec.create op count doesn't match vector type elements count");3475 3476  for (uint64_t i = 0; i < vecTy.getSize(); ++i) {3477    const mlir::Value indexValue =3478        mlir::LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), i);3479    result = mlir::LLVM::InsertElementOp::create(3480        rewriter, loc, result, adaptor.getElements()[i], indexValue);3481  }3482 3483  rewriter.replaceOp(op, result);3484  return mlir::success();3485}3486 3487mlir::LogicalResult CIRToLLVMVecExtractOpLowering::matchAndRewrite(3488    cir::VecExtractOp op, OpAdaptor adaptor,3489    mlir::ConversionPatternRewriter &rewriter) const {3490  rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractElementOp>(3491      op, adaptor.getVec(), adaptor.getIndex());3492  return mlir::success();3493}3494 3495mlir::LogicalResult CIRToLLVMVecInsertOpLowering::matchAndRewrite(3496    cir::VecInsertOp op, OpAdaptor adaptor,3497    mlir::ConversionPatternRewriter &rewriter) const {3498  rewriter.replaceOpWithNewOp<mlir::LLVM::InsertElementOp>(3499      op, adaptor.getVec(), adaptor.getValue(), adaptor.getIndex());3500  return mlir::success();3501}3502 3503mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(3504    cir::VecCmpOp op, OpAdaptor adaptor,3505    mlir::ConversionPatternRewriter &rewriter) const {3506  mlir::Type elementType = elementTypeIfVector(op.getLhs().getType());3507  mlir::Value bitResult;3508  if (auto intType = mlir::dyn_cast<cir::IntType>(elementType)) {3509    bitResult = mlir::LLVM::ICmpOp::create(3510        rewriter, op.getLoc(),3511        convertCmpKindToICmpPredicate(op.getKind(), intType.isSigned()),3512        adaptor.getLhs(), adaptor.getRhs());3513  } else if (mlir::isa<cir::FPTypeInterface>(elementType)) {3514    bitResult = mlir::LLVM::FCmpOp::create(3515        rewriter, op.getLoc(), convertCmpKindToFCmpPredicate(op.getKind()),3516        adaptor.getLhs(), adaptor.getRhs());3517  } else {3518    return op.emitError() << "unsupported type for VecCmpOp: " << elementType;3519  }3520 3521  // LLVM IR vector comparison returns a vector of i1. This one-bit vector3522  // must be sign-extended to the correct result type.3523  rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(3524      op, typeConverter->convertType(op.getType()), bitResult);3525  return mlir::success();3526}3527 3528mlir::LogicalResult CIRToLLVMVecSplatOpLowering::matchAndRewrite(3529    cir::VecSplatOp op, OpAdaptor adaptor,3530    mlir::ConversionPatternRewriter &rewriter) const {3531  // Vector splat can be implemented with an `insertelement` and a3532  // `shufflevector`, which is better than an `insertelement` for each3533  // element in the vector. Start with an undef vector. Insert the value into3534  // the first element. Then use a `shufflevector` with a mask of all 0 to3535  // fill out the entire vector with that value.3536  cir::VectorType vecTy = op.getType();3537  mlir::Type llvmTy = typeConverter->convertType(vecTy);3538  mlir::Location loc = op.getLoc();3539  mlir::Value poison = mlir::LLVM::PoisonOp::create(rewriter, loc, llvmTy);3540 3541  mlir::Value elementValue = adaptor.getValue();3542  if (elementValue.getDefiningOp<mlir::LLVM::PoisonOp>()) {3543    // If the splat value is poison, then we can just use poison value3544    // for the entire vector.3545    rewriter.replaceOp(op, poison);3546    return mlir::success();3547  }3548 3549  if (auto constValue = elementValue.getDefiningOp<mlir::LLVM::ConstantOp>()) {3550    if (auto intAttr = dyn_cast<mlir::IntegerAttr>(constValue.getValue())) {3551      mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get(3552          mlir::cast<mlir::ShapedType>(llvmTy), intAttr.getValue());3553      rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(3554          op, denseVec.getType(), denseVec);3555      return mlir::success();3556    }3557 3558    if (auto fpAttr = dyn_cast<mlir::FloatAttr>(constValue.getValue())) {3559      mlir::DenseFPElementsAttr denseVec = mlir::DenseFPElementsAttr::get(3560          mlir::cast<mlir::ShapedType>(llvmTy), fpAttr.getValue());3561      rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(3562          op, denseVec.getType(), denseVec);3563      return mlir::success();3564    }3565  }3566 3567  mlir::Value indexValue =3568      mlir::LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), 0);3569  mlir::Value oneElement = mlir::LLVM::InsertElementOp::create(3570      rewriter, loc, poison, elementValue, indexValue);3571  SmallVector<int32_t> zeroValues(vecTy.getSize(), 0);3572  rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(op, oneElement,3573                                                           poison, zeroValues);3574  return mlir::success();3575}3576 3577mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite(3578    cir::VecShuffleOp op, OpAdaptor adaptor,3579    mlir::ConversionPatternRewriter &rewriter) const {3580  // LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices.3581  // Convert the ClangIR ArrayAttr of IntAttr constants into a3582  // SmallVector<int>.3583  SmallVector<int, 8> indices;3584  std::transform(3585      op.getIndices().begin(), op.getIndices().end(),3586      std::back_inserter(indices), [](mlir::Attribute intAttr) {3587        return mlir::cast<cir::IntAttr>(intAttr).getValue().getSExtValue();3588      });3589  rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(3590      op, adaptor.getVec1(), adaptor.getVec2(), indices);3591  return mlir::success();3592}3593 3594mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite(3595    cir::VecShuffleDynamicOp op, OpAdaptor adaptor,3596    mlir::ConversionPatternRewriter &rewriter) const {3597  // LLVM IR does not have an operation that corresponds to this form of3598  // the built-in.3599  //     __builtin_shufflevector(V, I)3600  // is implemented as this pseudocode, where the for loop is unrolled3601  // and N is the number of elements:3602  //3603  // result = undef3604  // maskbits = NextPowerOf2(N - 1)3605  // masked = I & maskbits3606  // for (i in 0 <= i < N)3607  //    result[i] = V[masked[i]]3608  mlir::Location loc = op.getLoc();3609  mlir::Value input = adaptor.getVec();3610  mlir::Type llvmIndexVecType =3611      getTypeConverter()->convertType(op.getIndices().getType());3612  mlir::Type llvmIndexType = getTypeConverter()->convertType(3613      elementTypeIfVector(op.getIndices().getType()));3614  uint64_t numElements =3615      mlir::cast<cir::VectorType>(op.getVec().getType()).getSize();3616 3617  uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1;3618  mlir::Value maskValue = mlir::LLVM::ConstantOp::create(3619      rewriter, loc, llvmIndexType,3620      rewriter.getIntegerAttr(llvmIndexType, maskBits));3621  mlir::Value maskVector =3622      mlir::LLVM::UndefOp::create(rewriter, loc, llvmIndexVecType);3623 3624  for (uint64_t i = 0; i < numElements; ++i) {3625    mlir::Value idxValue =3626        mlir::LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), i);3627    maskVector = mlir::LLVM::InsertElementOp::create(rewriter, loc, maskVector,3628                                                     maskValue, idxValue);3629  }3630 3631  mlir::Value maskedIndices = mlir::LLVM::AndOp::create(3632      rewriter, loc, llvmIndexVecType, adaptor.getIndices(), maskVector);3633  mlir::Value result = mlir::LLVM::UndefOp::create(3634      rewriter, loc, getTypeConverter()->convertType(op.getVec().getType()));3635  for (uint64_t i = 0; i < numElements; ++i) {3636    mlir::Value iValue =3637        mlir::LLVM::ConstantOp::create(rewriter, loc, rewriter.getI64Type(), i);3638    mlir::Value indexValue = mlir::LLVM::ExtractElementOp::create(3639        rewriter, loc, maskedIndices, iValue);3640    mlir::Value valueAtIndex =3641        mlir::LLVM::ExtractElementOp::create(rewriter, loc, input, indexValue);3642    result = mlir::LLVM::InsertElementOp::create(rewriter, loc, result,3643                                                 valueAtIndex, iValue);3644  }3645  rewriter.replaceOp(op, result);3646  return mlir::success();3647}3648 3649mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite(3650    cir::VecTernaryOp op, OpAdaptor adaptor,3651    mlir::ConversionPatternRewriter &rewriter) const {3652  // Convert `cond` into a vector of i1, then use that in a `select` op.3653  mlir::Value bitVec = mlir::LLVM::ICmpOp::create(3654      rewriter, op.getLoc(), mlir::LLVM::ICmpPredicate::ne, adaptor.getCond(),3655      mlir::LLVM::ZeroOp::create(3656          rewriter, op.getCond().getLoc(),3657          typeConverter->convertType(op.getCond().getType())));3658  rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(3659      op, bitVec, adaptor.getLhs(), adaptor.getRhs());3660  return mlir::success();3661}3662 3663mlir::LogicalResult CIRToLLVMComplexAddOpLowering::matchAndRewrite(3664    cir::ComplexAddOp op, OpAdaptor adaptor,3665    mlir::ConversionPatternRewriter &rewriter) const {3666  mlir::Value lhs = adaptor.getLhs();3667  mlir::Value rhs = adaptor.getRhs();3668  mlir::Location loc = op.getLoc();3669 3670  auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());3671  mlir::Type complexElemTy =3672      getTypeConverter()->convertType(complexType.getElementType());3673  auto lhsReal = mlir::LLVM::ExtractValueOp::create(3674      rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{0}));3675  auto lhsImag = mlir::LLVM::ExtractValueOp::create(3676      rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{1}));3677  auto rhsReal = mlir::LLVM::ExtractValueOp::create(3678      rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{0}));3679  auto rhsImag = mlir::LLVM::ExtractValueOp::create(3680      rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{1}));3681 3682  mlir::Value newReal;3683  mlir::Value newImag;3684  if (complexElemTy.isInteger()) {3685    newReal = mlir::LLVM::AddOp::create(rewriter, loc, complexElemTy, lhsReal,3686                                        rhsReal);3687    newImag = mlir::LLVM::AddOp::create(rewriter, loc, complexElemTy, lhsImag,3688                                        rhsImag);3689  } else {3690    assert(!cir::MissingFeatures::fastMathFlags());3691    assert(!cir::MissingFeatures::fpConstraints());3692    newReal = mlir::LLVM::FAddOp::create(rewriter, loc, complexElemTy, lhsReal,3693                                         rhsReal);3694    newImag = mlir::LLVM::FAddOp::create(rewriter, loc, complexElemTy, lhsImag,3695                                         rhsImag);3696  }3697 3698  mlir::Type complexLLVMTy =3699      getTypeConverter()->convertType(op.getResult().getType());3700  auto initialComplex =3701      mlir::LLVM::PoisonOp::create(rewriter, op->getLoc(), complexLLVMTy);3702 3703  auto realComplex = mlir::LLVM::InsertValueOp::create(3704      rewriter, op->getLoc(), initialComplex, newReal, ArrayRef(int64_t{0}));3705 3706  rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(3707      op, realComplex, newImag, ArrayRef(int64_t{1}));3708 3709  return mlir::success();3710}3711 3712mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite(3713    cir::ComplexCreateOp op, OpAdaptor adaptor,3714    mlir::ConversionPatternRewriter &rewriter) const {3715  mlir::Type complexLLVMTy =3716      getTypeConverter()->convertType(op.getResult().getType());3717  auto initialComplex =3718      mlir::LLVM::UndefOp::create(rewriter, op->getLoc(), complexLLVMTy);3719 3720  auto realComplex = mlir::LLVM::InsertValueOp::create(3721      rewriter, op->getLoc(), initialComplex, adaptor.getReal(),3722      ArrayRef(int64_t{0}));3723 3724  auto complex = mlir::LLVM::InsertValueOp::create(3725      rewriter, op->getLoc(), realComplex, adaptor.getImag(),3726      ArrayRef(int64_t{1}));3727 3728  rewriter.replaceOp(op, complex);3729  return mlir::success();3730}3731 3732mlir::LogicalResult CIRToLLVMComplexRealOpLowering::matchAndRewrite(3733    cir::ComplexRealOp op, OpAdaptor adaptor,3734    mlir::ConversionPatternRewriter &rewriter) const {3735  mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());3736  mlir::Value operand = adaptor.getOperand();3737  if (mlir::isa<cir::ComplexType>(op.getOperand().getType())) {3738    operand = mlir::LLVM::ExtractValueOp::create(3739        rewriter, op.getLoc(), resultLLVMTy, operand,3740        llvm::ArrayRef<std::int64_t>{0});3741  }3742  rewriter.replaceOp(op, operand);3743  return mlir::success();3744}3745 3746mlir::LogicalResult CIRToLLVMComplexSubOpLowering::matchAndRewrite(3747    cir::ComplexSubOp op, OpAdaptor adaptor,3748    mlir::ConversionPatternRewriter &rewriter) const {3749  mlir::Value lhs = adaptor.getLhs();3750  mlir::Value rhs = adaptor.getRhs();3751  mlir::Location loc = op.getLoc();3752 3753  auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());3754  mlir::Type complexElemTy =3755      getTypeConverter()->convertType(complexType.getElementType());3756  auto lhsReal = mlir::LLVM::ExtractValueOp::create(3757      rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{0}));3758  auto lhsImag = mlir::LLVM::ExtractValueOp::create(3759      rewriter, loc, complexElemTy, lhs, ArrayRef(int64_t{1}));3760  auto rhsReal = mlir::LLVM::ExtractValueOp::create(3761      rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{0}));3762  auto rhsImag = mlir::LLVM::ExtractValueOp::create(3763      rewriter, loc, complexElemTy, rhs, ArrayRef(int64_t{1}));3764 3765  mlir::Value newReal;3766  mlir::Value newImag;3767  if (complexElemTy.isInteger()) {3768    newReal = mlir::LLVM::SubOp::create(rewriter, loc, complexElemTy, lhsReal,3769                                        rhsReal);3770    newImag = mlir::LLVM::SubOp::create(rewriter, loc, complexElemTy, lhsImag,3771                                        rhsImag);3772  } else {3773    assert(!cir::MissingFeatures::fastMathFlags());3774    assert(!cir::MissingFeatures::fpConstraints());3775    newReal = mlir::LLVM::FSubOp::create(rewriter, loc, complexElemTy, lhsReal,3776                                         rhsReal);3777    newImag = mlir::LLVM::FSubOp::create(rewriter, loc, complexElemTy, lhsImag,3778                                         rhsImag);3779  }3780 3781  mlir::Type complexLLVMTy =3782      getTypeConverter()->convertType(op.getResult().getType());3783  auto initialComplex =3784      mlir::LLVM::PoisonOp::create(rewriter, op->getLoc(), complexLLVMTy);3785 3786  auto realComplex = mlir::LLVM::InsertValueOp::create(3787      rewriter, op->getLoc(), initialComplex, newReal, ArrayRef(int64_t{0}));3788 3789  rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(3790      op, realComplex, newImag, ArrayRef(int64_t{1}));3791 3792  return mlir::success();3793}3794 3795mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(3796    cir::ComplexImagOp op, OpAdaptor adaptor,3797    mlir::ConversionPatternRewriter &rewriter) const {3798  mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());3799  mlir::Value operand = adaptor.getOperand();3800  mlir::Location loc = op.getLoc();3801 3802  if (mlir::isa<cir::ComplexType>(op.getOperand().getType())) {3803    operand = mlir::LLVM::ExtractValueOp::create(3804        rewriter, loc, resultLLVMTy, operand, llvm::ArrayRef<std::int64_t>{1});3805  } else {3806    mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(resultLLVMTy);3807    operand =3808        mlir::LLVM::ConstantOp::create(rewriter, loc, resultLLVMTy, zeroAttr);3809  }3810 3811  rewriter.replaceOp(op, operand);3812  return mlir::success();3813}3814 3815mlir::IntegerType computeBitfieldIntType(mlir::Type storageType,3816                                         mlir::MLIRContext *context,3817                                         unsigned &storageSize) {3818  return TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)3819      .Case<cir::ArrayType>([&](cir::ArrayType atTy) {3820        storageSize = atTy.getSize() * 8;3821        return mlir::IntegerType::get(context, storageSize);3822      })3823      .Case<cir::IntType>([&](cir::IntType intTy) {3824        storageSize = intTy.getWidth();3825        return mlir::IntegerType::get(context, storageSize);3826      })3827      .Default([](mlir::Type) -> mlir::IntegerType {3828        llvm_unreachable(3829            "Either ArrayType or IntType expected for bitfields storage");3830      });3831}3832 3833mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite(3834    cir::SetBitfieldOp op, OpAdaptor adaptor,3835    mlir::ConversionPatternRewriter &rewriter) const {3836  mlir::OpBuilder::InsertionGuard guard(rewriter);3837  rewriter.setInsertionPoint(op);3838 3839  cir::BitfieldInfoAttr info = op.getBitfieldInfo();3840  uint64_t size = info.getSize();3841  uint64_t offset = info.getOffset();3842  mlir::Type storageType = info.getStorageType();3843  mlir::MLIRContext *context = storageType.getContext();3844 3845  unsigned storageSize = 0;3846 3847  mlir::IntegerType intType =3848      computeBitfieldIntType(storageType, context, storageSize);3849 3850  mlir::Value srcVal = createIntCast(rewriter, adaptor.getSrc(), intType);3851  unsigned srcWidth = storageSize;3852  mlir::Value resultVal = srcVal;3853 3854  if (storageSize != size) {3855    assert(storageSize > size && "Invalid bitfield size.");3856 3857    mlir::Value val = mlir::LLVM::LoadOp::create(3858        rewriter, op.getLoc(), intType, adaptor.getAddr(), op.getAlignment(),3859        op.getIsVolatile());3860 3861    srcVal =3862        createAnd(rewriter, srcVal, llvm::APInt::getLowBitsSet(srcWidth, size));3863    resultVal = srcVal;3864    srcVal = createShL(rewriter, srcVal, offset);3865 3866    // Mask out the original value.3867    val = createAnd(rewriter, val,3868                    ~llvm::APInt::getBitsSet(srcWidth, offset, offset + size));3869 3870    // Or together the unchanged values and the source value.3871    srcVal = mlir::LLVM::OrOp::create(rewriter, op.getLoc(), val, srcVal);3872  }3873 3874  mlir::LLVM::StoreOp::create(rewriter, op.getLoc(), srcVal, adaptor.getAddr(),3875                              op.getAlignment(), op.getIsVolatile());3876 3877  mlir::Type resultTy = getTypeConverter()->convertType(op.getType());3878 3879  if (info.getIsSigned()) {3880    assert(size <= storageSize);3881    unsigned highBits = storageSize - size;3882 3883    if (highBits) {3884      resultVal = createShL(rewriter, resultVal, highBits);3885      resultVal = createAShR(rewriter, resultVal, highBits);3886    }3887  }3888 3889  resultVal = createIntCast(rewriter, resultVal,3890                            mlir::cast<mlir::IntegerType>(resultTy),3891                            info.getIsSigned());3892 3893  rewriter.replaceOp(op, resultVal);3894  return mlir::success();3895}3896 3897mlir::LogicalResult CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite(3898    cir::ComplexImagPtrOp op, OpAdaptor adaptor,3899    mlir::ConversionPatternRewriter &rewriter) const {3900  cir::PointerType operandTy = op.getOperand().getType();3901  mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());3902  mlir::Type elementLLVMTy =3903      getTypeConverter()->convertType(operandTy.getPointee());3904 3905  mlir::LLVM::GEPArg gepIndices[2] = {{0}, {1}};3906  mlir::LLVM::GEPNoWrapFlags inboundsNuw =3907      mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;3908  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(3909      op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,3910      inboundsNuw);3911  return mlir::success();3912}3913 3914mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite(3915    cir::ComplexRealPtrOp op, OpAdaptor adaptor,3916    mlir::ConversionPatternRewriter &rewriter) const {3917  cir::PointerType operandTy = op.getOperand().getType();3918  mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());3919  mlir::Type elementLLVMTy =3920      getTypeConverter()->convertType(operandTy.getPointee());3921 3922  mlir::LLVM::GEPArg gepIndices[2] = {0, 0};3923  mlir::LLVM::GEPNoWrapFlags inboundsNuw =3924      mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;3925  rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(3926      op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,3927      inboundsNuw);3928  return mlir::success();3929}3930 3931mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(3932    cir::GetBitfieldOp op, OpAdaptor adaptor,3933    mlir::ConversionPatternRewriter &rewriter) const {3934 3935  mlir::OpBuilder::InsertionGuard guard(rewriter);3936  rewriter.setInsertionPoint(op);3937 3938  cir::BitfieldInfoAttr info = op.getBitfieldInfo();3939  uint64_t size = info.getSize();3940  uint64_t offset = info.getOffset();3941  mlir::Type storageType = info.getStorageType();3942  mlir::MLIRContext *context = storageType.getContext();3943  unsigned storageSize = 0;3944 3945  mlir::IntegerType intType =3946      computeBitfieldIntType(storageType, context, storageSize);3947 3948  mlir::Value val = mlir::LLVM::LoadOp::create(3949      rewriter, op.getLoc(), intType, adaptor.getAddr(), op.getAlignment(),3950      op.getIsVolatile());3951  val = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), intType, val);3952 3953  if (info.getIsSigned()) {3954    assert(static_cast<unsigned>(offset + size) <= storageSize);3955    unsigned highBits = storageSize - offset - size;3956    val = createShL(rewriter, val, highBits);3957    val = createAShR(rewriter, val, offset + highBits);3958  } else {3959    val = createLShR(rewriter, val, offset);3960 3961    if (static_cast<unsigned>(offset) + size < storageSize)3962      val = createAnd(rewriter, val,3963                      llvm::APInt::getLowBitsSet(storageSize, size));3964  }3965 3966  mlir::Type resTy = getTypeConverter()->convertType(op.getType());3967  mlir::Value newOp = createIntCast(3968      rewriter, val, mlir::cast<mlir::IntegerType>(resTy), info.getIsSigned());3969  rewriter.replaceOp(op, newOp);3970  return mlir::success();3971}3972 3973mlir::LogicalResult CIRToLLVMInlineAsmOpLowering::matchAndRewrite(3974    cir::InlineAsmOp op, OpAdaptor adaptor,3975    mlir::ConversionPatternRewriter &rewriter) const {3976  mlir::Type llResTy;3977  if (op.getNumResults())3978    llResTy = getTypeConverter()->convertType(op.getType(0));3979 3980  cir::AsmFlavor dialect = op.getAsmFlavor();3981  mlir::LLVM::AsmDialect llDialect = dialect == cir::AsmFlavor::x86_att3982                                         ? mlir::LLVM::AsmDialect::AD_ATT3983                                         : mlir::LLVM::AsmDialect::AD_Intel;3984 3985  SmallVector<mlir::Attribute> opAttrs;3986  StringRef llvmAttrName = mlir::LLVM::InlineAsmOp::getElementTypeAttrName();3987 3988  // this is for the lowering to LLVM from LLVM dialect. Otherwise, if we3989  // don't have the result (i.e. void type as a result of operation), the3990  // element type attribute will be attached to the whole instruction, but not3991  // to the operand3992  if (!op.getNumResults())3993    opAttrs.push_back(mlir::Attribute());3994 3995  SmallVector<mlir::Value> llvmOperands;3996  SmallVector<mlir::Value> cirOperands;3997  for (auto const &[llvmOp, cirOp] :3998       zip(adaptor.getAsmOperands(), op.getAsmOperands())) {3999    append_range(llvmOperands, llvmOp);4000    append_range(cirOperands, cirOp);4001  }4002 4003  // so far we infer the llvm dialect element type attr from4004  // CIR operand type.4005  for (auto const &[cirOpAttr, cirOp] :4006       zip(op.getOperandAttrs(), cirOperands)) {4007    if (!cirOpAttr) {4008      opAttrs.push_back(mlir::Attribute());4009      continue;4010    }4011 4012    llvm::SmallVector<mlir::NamedAttribute, 1> attrs;4013    cir::PointerType typ = mlir::cast<cir::PointerType>(cirOp.getType());4014    mlir::TypeAttr typAttr = mlir::TypeAttr::get(convertTypeForMemory(4015        *getTypeConverter(), dataLayout, typ.getPointee()));4016 4017    attrs.push_back(rewriter.getNamedAttr(llvmAttrName, typAttr));4018    mlir::DictionaryAttr newDict = rewriter.getDictionaryAttr(attrs);4019    opAttrs.push_back(newDict);4020  }4021 4022  rewriter.replaceOpWithNewOp<mlir::LLVM::InlineAsmOp>(4023      op, llResTy, llvmOperands, op.getAsmStringAttr(), op.getConstraintsAttr(),4024      op.getSideEffectsAttr(),4025      /*is_align_stack*/ mlir::UnitAttr(),4026      /*tail_call_kind*/4027      mlir::LLVM::TailCallKindAttr::get(4028          getContext(), mlir::LLVM::tailcallkind::TailCallKind::None),4029      mlir::LLVM::AsmDialectAttr::get(getContext(), llDialect),4030      rewriter.getArrayAttr(opAttrs));4031 4032  return mlir::success();4033}4034 4035mlir::LogicalResult CIRToLLVMVAStartOpLowering::matchAndRewrite(4036    cir::VAStartOp op, OpAdaptor adaptor,4037    mlir::ConversionPatternRewriter &rewriter) const {4038  auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());4039  auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,4040                                              adaptor.getArgList());4041  rewriter.replaceOpWithNewOp<mlir::LLVM::VaStartOp>(op, vaList);4042  return mlir::success();4043}4044 4045mlir::LogicalResult CIRToLLVMVAEndOpLowering::matchAndRewrite(4046    cir::VAEndOp op, OpAdaptor adaptor,4047    mlir::ConversionPatternRewriter &rewriter) const {4048  auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());4049  auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,4050                                              adaptor.getArgList());4051  rewriter.replaceOpWithNewOp<mlir::LLVM::VaEndOp>(op, vaList);4052  return mlir::success();4053}4054 4055mlir::LogicalResult CIRToLLVMVAArgOpLowering::matchAndRewrite(4056    cir::VAArgOp op, OpAdaptor adaptor,4057    mlir::ConversionPatternRewriter &rewriter) const {4058  assert(!cir::MissingFeatures::vaArgABILowering());4059  auto opaquePtr = mlir::LLVM::LLVMPointerType::get(getContext());4060  auto vaList = mlir::LLVM::BitcastOp::create(rewriter, op.getLoc(), opaquePtr,4061                                              adaptor.getArgList());4062 4063  mlir::Type llvmType =4064      getTypeConverter()->convertType(op->getResultTypes().front());4065  if (!llvmType)4066    return mlir::failure();4067 4068  rewriter.replaceOpWithNewOp<mlir::LLVM::VaArgOp>(op, llvmType, vaList);4069  return mlir::success();4070}4071 4072mlir::LogicalResult CIRToLLVMBlockAddressOpLowering::matchAndRewrite(4073    cir::BlockAddressOp op, OpAdaptor adaptor,4074    mlir::ConversionPatternRewriter &rewriter) const {4075  return mlir::failure();4076}4077 4078mlir::LogicalResult CIRToLLVMAwaitOpLowering::matchAndRewrite(4079    cir::AwaitOp op, OpAdaptor adaptor,4080    mlir::ConversionPatternRewriter &rewriter) const {4081  return mlir::failure();4082}4083 4084std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {4085  return std::make_unique<ConvertCIRToLLVMPass>();4086}4087 4088void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {4089  mlir::populateCIRPreLoweringPasses(pm);4090  pm.addPass(createConvertCIRToLLVMPass());4091}4092 4093std::unique_ptr<llvm::Module>4094lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) {4095  llvm::TimeTraceScope scope("lower from CIR to LLVM directly");4096 4097  mlir::MLIRContext *mlirCtx = mlirModule.getContext();4098 4099  mlir::PassManager pm(mlirCtx);4100  populateCIRToLLVMPasses(pm);4101 4102  (void)mlir::applyPassManagerCLOptions(pm);4103 4104  if (mlir::failed(pm.run(mlirModule))) {4105    // FIXME: Handle any errors where they occurs and return a nullptr here.4106    report_fatal_error(4107        "The pass manager failed to lower CIR to LLVMIR dialect!");4108  }4109 4110  mlir::registerBuiltinDialectTranslation(*mlirCtx);4111  mlir::registerLLVMDialectTranslation(*mlirCtx);4112  mlir::registerCIRDialectTranslation(*mlirCtx);4113 4114  llvm::TimeTraceScope translateScope("translateModuleToLLVMIR");4115 4116  StringRef moduleName = mlirModule.getName().value_or("CIRToLLVMModule");4117  std::unique_ptr<llvm::Module> llvmModule =4118      mlir::translateModuleToLLVMIR(mlirModule, llvmCtx, moduleName);4119 4120  if (!llvmModule) {4121    // FIXME: Handle any errors where they occurs and return a nullptr here.4122    report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!");4123  }4124 4125  return llvmModule;4126}4127} // namespace direct4128} // namespace cir4129