Path: blob/main/contrib/llvm-project/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp
213845 views
//====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===//1//2// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.3// See https://llvm.org/LICENSE.txt for license information.4// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception5//6//===----------------------------------------------------------------------===//7//8// This file implements lowering of CIR operations to LLVMIR.9//10//===----------------------------------------------------------------------===//1112#include "LowerToLLVM.h"1314#include <deque>15#include <optional>1617#include "mlir/Conversion/LLVMCommon/TypeConverter.h"18#include "mlir/Dialect/DLTI/DLTI.h"19#include "mlir/Dialect/Func/IR/FuncOps.h"20#include "mlir/Dialect/LLVMIR/LLVMDialect.h"21#include "mlir/Dialect/LLVMIR/LLVMTypes.h"22#include "mlir/IR/BuiltinAttributes.h"23#include "mlir/IR/BuiltinDialect.h"24#include "mlir/IR/BuiltinOps.h"25#include "mlir/IR/Types.h"26#include "mlir/Pass/Pass.h"27#include "mlir/Pass/PassManager.h"28#include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"29#include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"30#include "mlir/Target/LLVMIR/Export.h"31#include "mlir/Transforms/DialectConversion.h"32#include "clang/CIR/Dialect/IR/CIRAttrs.h"33#include "clang/CIR/Dialect/IR/CIRDialect.h"34#include "clang/CIR/Dialect/Passes.h"35#include "clang/CIR/LoweringHelpers.h"36#include "clang/CIR/MissingFeatures.h"37#include "clang/CIR/Passes.h"38#include "llvm/ADT/TypeSwitch.h"39#include "llvm/IR/Module.h"40#include "llvm/Support/ErrorHandling.h"41#include "llvm/Support/TimeProfiler.h"4243using namespace cir;44using namespace llvm;4546namespace cir {47namespace direct {4849//===----------------------------------------------------------------------===//50// Helper Methods51//===----------------------------------------------------------------------===//5253namespace {54/// If the given type is a vector type, return the vector's element type.55/// Otherwise return the given type unchanged.56mlir::Type elementTypeIfVector(mlir::Type type) {57return llvm::TypeSwitch<mlir::Type, mlir::Type>(type)58.Case<cir::VectorType, mlir::VectorType>(59[](auto p) { return p.getElementType(); })60.Default([](mlir::Type p) { return p; });61}62} // namespace6364/// Given a type convertor and a data layout, convert the given type to a type65/// that is suitable for memory operations. For example, this can be used to66/// lower cir.bool accesses to i8.67static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,68mlir::DataLayout const &dataLayout,69mlir::Type type) {70// TODO(cir): Handle other types similarly to clang's codegen71// convertTypeForMemory72if (isa<cir::BoolType>(type)) {73return mlir::IntegerType::get(type.getContext(),74dataLayout.getTypeSizeInBits(type));75}7677return converter.convertType(type);78}7980static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,81mlir::IntegerType dstTy,82bool isSigned = false) {83mlir::Type srcTy = src.getType();84assert(mlir::isa<mlir::IntegerType>(srcTy));8586unsigned srcWidth = mlir::cast<mlir::IntegerType>(srcTy).getWidth();87unsigned dstWidth = mlir::cast<mlir::IntegerType>(dstTy).getWidth();88mlir::Location loc = src.getLoc();8990if (dstWidth > srcWidth && isSigned)91return bld.create<mlir::LLVM::SExtOp>(loc, dstTy, src);92if (dstWidth > srcWidth)93return bld.create<mlir::LLVM::ZExtOp>(loc, dstTy, src);94if (dstWidth < srcWidth)95return bld.create<mlir::LLVM::TruncOp>(loc, dstTy, src);96return bld.create<mlir::LLVM::BitcastOp>(loc, dstTy, src);97}9899static mlir::LLVM::Visibility100lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) {101switch (visibilityKind) {102case cir::VisibilityKind::Default:103return ::mlir::LLVM::Visibility::Default;104case cir::VisibilityKind::Hidden:105return ::mlir::LLVM::Visibility::Hidden;106case cir::VisibilityKind::Protected:107return ::mlir::LLVM::Visibility::Protected;108}109}110111/// Emits the value from memory as expected by its users. Should be called when112/// the memory represetnation of a CIR type is not equal to its scalar113/// representation.114static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,115mlir::DataLayout const &dataLayout,116cir::LoadOp op, mlir::Value value) {117118// TODO(cir): Handle other types similarly to clang's codegen EmitFromMemory119if (auto boolTy = mlir::dyn_cast<cir::BoolType>(op.getType())) {120// Create a cast value from specified size in datalayout to i1121assert(value.getType().isInteger(dataLayout.getTypeSizeInBits(boolTy)));122return createIntCast(rewriter, value, rewriter.getI1Type());123}124125return value;126}127128/// Emits a value to memory with the expected scalar type. Should be called when129/// the memory represetnation of a CIR type is not equal to its scalar130/// representation.131static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,132mlir::DataLayout const &dataLayout,133mlir::Type origType, mlir::Value value) {134135// TODO(cir): Handle other types similarly to clang's codegen EmitToMemory136if (auto boolTy = mlir::dyn_cast<cir::BoolType>(origType)) {137// Create zext of value from i1 to i8138mlir::IntegerType memType =139rewriter.getIntegerType(dataLayout.getTypeSizeInBits(boolTy));140return createIntCast(rewriter, value, memType);141}142143return value;144}145146mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {147using CIR = cir::GlobalLinkageKind;148using LLVM = mlir::LLVM::Linkage;149150switch (linkage) {151case CIR::AvailableExternallyLinkage:152return LLVM::AvailableExternally;153case CIR::CommonLinkage:154return LLVM::Common;155case CIR::ExternalLinkage:156return LLVM::External;157case CIR::ExternalWeakLinkage:158return LLVM::ExternWeak;159case CIR::InternalLinkage:160return LLVM::Internal;161case CIR::LinkOnceAnyLinkage:162return LLVM::Linkonce;163case CIR::LinkOnceODRLinkage:164return LLVM::LinkonceODR;165case CIR::PrivateLinkage:166return LLVM::Private;167case CIR::WeakAnyLinkage:168return LLVM::Weak;169case CIR::WeakODRLinkage:170return LLVM::WeakODR;171};172llvm_unreachable("Unknown CIR linkage type");173}174175static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,176mlir::Value llvmSrc, mlir::Type llvmDstIntTy,177bool isUnsigned, uint64_t cirSrcWidth,178uint64_t cirDstIntWidth) {179if (cirSrcWidth == cirDstIntWidth)180return llvmSrc;181182auto loc = llvmSrc.getLoc();183if (cirSrcWidth < cirDstIntWidth) {184if (isUnsigned)185return rewriter.create<mlir::LLVM::ZExtOp>(loc, llvmDstIntTy, llvmSrc);186return rewriter.create<mlir::LLVM::SExtOp>(loc, llvmDstIntTy, llvmSrc);187}188189// Otherwise truncate190return rewriter.create<mlir::LLVM::TruncOp>(loc, llvmDstIntTy, llvmSrc);191}192193class CIRAttrToValue {194public:195CIRAttrToValue(mlir::Operation *parentOp,196mlir::ConversionPatternRewriter &rewriter,197const mlir::TypeConverter *converter)198: parentOp(parentOp), rewriter(rewriter), converter(converter) {}199200mlir::Value visit(mlir::Attribute attr) {201return llvm::TypeSwitch<mlir::Attribute, mlir::Value>(attr)202.Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr,203cir::ConstArrayAttr, cir::ConstVectorAttr, cir::ConstPtrAttr,204cir::ZeroAttr>([&](auto attrT) { return visitCirAttr(attrT); })205.Default([&](auto attrT) { return mlir::Value(); });206}207208mlir::Value visitCirAttr(cir::IntAttr intAttr);209mlir::Value visitCirAttr(cir::FPAttr fltAttr);210mlir::Value visitCirAttr(cir::ConstComplexAttr complexAttr);211mlir::Value visitCirAttr(cir::ConstPtrAttr ptrAttr);212mlir::Value visitCirAttr(cir::ConstArrayAttr attr);213mlir::Value visitCirAttr(cir::ConstVectorAttr attr);214mlir::Value visitCirAttr(cir::ZeroAttr attr);215216private:217mlir::Operation *parentOp;218mlir::ConversionPatternRewriter &rewriter;219const mlir::TypeConverter *converter;220};221222/// Switches on the type of attribute and calls the appropriate conversion.223mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,224const mlir::Attribute attr,225mlir::ConversionPatternRewriter &rewriter,226const mlir::TypeConverter *converter) {227CIRAttrToValue valueConverter(parentOp, rewriter, converter);228mlir::Value value = valueConverter.visit(attr);229if (!value)230llvm_unreachable("unhandled attribute type");231return value;232}233234void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,235cir::SideEffect sideEffect,236mlir::LLVM::MemoryEffectsAttr &memoryEffect,237bool &noUnwind, bool &willReturn) {238using mlir::LLVM::ModRefInfo;239240switch (sideEffect) {241case cir::SideEffect::All:242memoryEffect = {};243noUnwind = isNothrow;244willReturn = false;245break;246247case cir::SideEffect::Pure:248memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(249callOp->getContext(), /*other=*/ModRefInfo::Ref,250/*argMem=*/ModRefInfo::Ref,251/*inaccessibleMem=*/ModRefInfo::Ref);252noUnwind = true;253willReturn = true;254break;255256case cir::SideEffect::Const:257memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(258callOp->getContext(), /*other=*/ModRefInfo::NoModRef,259/*argMem=*/ModRefInfo::NoModRef,260/*inaccessibleMem=*/ModRefInfo::NoModRef);261noUnwind = true;262willReturn = true;263break;264}265}266267/// IntAttr visitor.268mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {269mlir::Location loc = parentOp->getLoc();270return rewriter.create<mlir::LLVM::ConstantOp>(271loc, converter->convertType(intAttr.getType()), intAttr.getValue());272}273274/// FPAttr visitor.275mlir::Value CIRAttrToValue::visitCirAttr(cir::FPAttr fltAttr) {276mlir::Location loc = parentOp->getLoc();277return rewriter.create<mlir::LLVM::ConstantOp>(278loc, converter->convertType(fltAttr.getType()), fltAttr.getValue());279}280281/// ConstComplexAttr visitor.282mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstComplexAttr complexAttr) {283auto complexType = mlir::cast<cir::ComplexType>(complexAttr.getType());284mlir::Type complexElemTy = complexType.getElementType();285mlir::Type complexElemLLVMTy = converter->convertType(complexElemTy);286287mlir::Attribute components[2];288if (const auto intType = mlir::dyn_cast<cir::IntType>(complexElemTy)) {289components[0] = rewriter.getIntegerAttr(290complexElemLLVMTy,291mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());292components[1] = rewriter.getIntegerAttr(293complexElemLLVMTy,294mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());295} else {296components[0] = rewriter.getFloatAttr(297complexElemLLVMTy,298mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());299components[1] = rewriter.getFloatAttr(300complexElemLLVMTy,301mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());302}303304mlir::Location loc = parentOp->getLoc();305return rewriter.create<mlir::LLVM::ConstantOp>(306loc, converter->convertType(complexAttr.getType()),307rewriter.getArrayAttr(components));308}309310/// ConstPtrAttr visitor.311mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstPtrAttr ptrAttr) {312mlir::Location loc = parentOp->getLoc();313if (ptrAttr.isNullValue()) {314return rewriter.create<mlir::LLVM::ZeroOp>(315loc, converter->convertType(ptrAttr.getType()));316}317mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());318mlir::Value ptrVal = rewriter.create<mlir::LLVM::ConstantOp>(319loc, rewriter.getIntegerType(layout.getTypeSizeInBits(ptrAttr.getType())),320ptrAttr.getValue().getInt());321return rewriter.create<mlir::LLVM::IntToPtrOp>(322loc, converter->convertType(ptrAttr.getType()), ptrVal);323}324325// ConstArrayAttr visitor326mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {327mlir::Type llvmTy = converter->convertType(attr.getType());328mlir::Location loc = parentOp->getLoc();329mlir::Value result;330331if (attr.hasTrailingZeros()) {332mlir::Type arrayTy = attr.getType();333result = rewriter.create<mlir::LLVM::ZeroOp>(334loc, converter->convertType(arrayTy));335} else {336result = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmTy);337}338339// Iteratively lower each constant element of the array.340if (auto arrayAttr = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts())) {341for (auto [idx, elt] : llvm::enumerate(arrayAttr)) {342mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());343mlir::Value init = visit(elt);344result =345rewriter.create<mlir::LLVM::InsertValueOp>(loc, result, init, idx);346}347} else if (auto strAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) {348// TODO(cir): this diverges from traditional lowering. Normally the string349// would be a global constant that is memcopied.350auto arrayTy = mlir::dyn_cast<cir::ArrayType>(strAttr.getType());351assert(arrayTy && "String attribute must have an array type");352mlir::Type eltTy = arrayTy.getElementType();353for (auto [idx, elt] : llvm::enumerate(strAttr)) {354auto init = rewriter.create<mlir::LLVM::ConstantOp>(355loc, converter->convertType(eltTy), elt);356result =357rewriter.create<mlir::LLVM::InsertValueOp>(loc, result, init, idx);358}359} else {360llvm_unreachable("unexpected ConstArrayAttr elements");361}362363return result;364}365366/// ConstVectorAttr visitor.367mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstVectorAttr attr) {368const mlir::Type llvmTy = converter->convertType(attr.getType());369const mlir::Location loc = parentOp->getLoc();370371SmallVector<mlir::Attribute> mlirValues;372for (const mlir::Attribute elementAttr : attr.getElts()) {373mlir::Attribute mlirAttr;374if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(elementAttr)) {375mlirAttr = rewriter.getIntegerAttr(376converter->convertType(intAttr.getType()), intAttr.getValue());377} else if (auto floatAttr = mlir::dyn_cast<cir::FPAttr>(elementAttr)) {378mlirAttr = rewriter.getFloatAttr(379converter->convertType(floatAttr.getType()), floatAttr.getValue());380} else {381llvm_unreachable(382"vector constant with an element that is neither an int nor a float");383}384mlirValues.push_back(mlirAttr);385}386387return rewriter.create<mlir::LLVM::ConstantOp>(388loc, llvmTy,389mlir::DenseElementsAttr::get(mlir::cast<mlir::ShapedType>(llvmTy),390mlirValues));391}392393/// ZeroAttr visitor.394mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr attr) {395mlir::Location loc = parentOp->getLoc();396return rewriter.create<mlir::LLVM::ZeroOp>(397loc, converter->convertType(attr.getType()));398}399400// This class handles rewriting initializer attributes for types that do not401// require region initialization.402class GlobalInitAttrRewriter {403public:404GlobalInitAttrRewriter(mlir::Type type,405mlir::ConversionPatternRewriter &rewriter)406: llvmType(type), rewriter(rewriter) {}407408mlir::Attribute visit(mlir::Attribute attr) {409return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)410.Case<cir::IntAttr, cir::FPAttr, cir::BoolAttr>(411[&](auto attrT) { return visitCirAttr(attrT); })412.Default([&](auto attrT) { return mlir::Attribute(); });413}414415mlir::Attribute visitCirAttr(cir::IntAttr attr) {416return rewriter.getIntegerAttr(llvmType, attr.getValue());417}418419mlir::Attribute visitCirAttr(cir::FPAttr attr) {420return rewriter.getFloatAttr(llvmType, attr.getValue());421}422423mlir::Attribute visitCirAttr(cir::BoolAttr attr) {424return rewriter.getBoolAttr(attr.getValue());425}426427private:428mlir::Type llvmType;429mlir::ConversionPatternRewriter &rewriter;430};431432// This pass requires the CIR to be in a "flat" state. All blocks in each433// function must belong to the parent region. Once scopes and control flow434// are implemented in CIR, a pass will be run before this one to flatten435// the CIR and get it into the state that this pass requires.436struct ConvertCIRToLLVMPass437: public mlir::PassWrapper<ConvertCIRToLLVMPass,438mlir::OperationPass<mlir::ModuleOp>> {439void getDependentDialects(mlir::DialectRegistry ®istry) const override {440registry.insert<mlir::BuiltinDialect, mlir::DLTIDialect,441mlir::LLVM::LLVMDialect, mlir::func::FuncDialect>();442}443void runOnOperation() final;444445void processCIRAttrs(mlir::ModuleOp module);446447StringRef getDescription() const override {448return "Convert the prepared CIR dialect module to LLVM dialect";449}450451StringRef getArgument() const override { return "cir-flat-to-llvm"; }452};453454mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(455cir::AssumeOp op, OpAdaptor adaptor,456mlir::ConversionPatternRewriter &rewriter) const {457auto cond = adaptor.getPredicate();458rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(op, cond);459return mlir::success();460}461462mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite(463cir::BitClrsbOp op, OpAdaptor adaptor,464mlir::ConversionPatternRewriter &rewriter) const {465auto zero = rewriter.create<mlir::LLVM::ConstantOp>(466op.getLoc(), adaptor.getInput().getType(), 0);467auto isNeg = rewriter.create<mlir::LLVM::ICmpOp>(468op.getLoc(),469mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(),470mlir::LLVM::ICmpPredicate::slt),471adaptor.getInput(), zero);472473auto negOne = rewriter.create<mlir::LLVM::ConstantOp>(474op.getLoc(), adaptor.getInput().getType(), -1);475auto flipped = rewriter.create<mlir::LLVM::XOrOp>(op.getLoc(),476adaptor.getInput(), negOne);477478auto select = rewriter.create<mlir::LLVM::SelectOp>(479op.getLoc(), isNeg, flipped, adaptor.getInput());480481auto resTy = getTypeConverter()->convertType(op.getType());482auto clz = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(483op.getLoc(), resTy, select, /*is_zero_poison=*/false);484485auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);486auto res = rewriter.create<mlir::LLVM::SubOp>(op.getLoc(), clz, one);487rewriter.replaceOp(op, res);488489return mlir::LogicalResult::success();490}491492mlir::LogicalResult CIRToLLVMBitClzOpLowering::matchAndRewrite(493cir::BitClzOp op, OpAdaptor adaptor,494mlir::ConversionPatternRewriter &rewriter) const {495auto resTy = getTypeConverter()->convertType(op.getType());496auto llvmOp = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(497op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());498rewriter.replaceOp(op, llvmOp);499return mlir::LogicalResult::success();500}501502mlir::LogicalResult CIRToLLVMBitCtzOpLowering::matchAndRewrite(503cir::BitCtzOp op, OpAdaptor adaptor,504mlir::ConversionPatternRewriter &rewriter) const {505auto resTy = getTypeConverter()->convertType(op.getType());506auto llvmOp = rewriter.create<mlir::LLVM::CountTrailingZerosOp>(507op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());508rewriter.replaceOp(op, llvmOp);509return mlir::LogicalResult::success();510}511512mlir::LogicalResult CIRToLLVMBitParityOpLowering::matchAndRewrite(513cir::BitParityOp op, OpAdaptor adaptor,514mlir::ConversionPatternRewriter &rewriter) const {515auto resTy = getTypeConverter()->convertType(op.getType());516auto popcnt = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,517adaptor.getInput());518519auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);520auto popcntMod2 =521rewriter.create<mlir::LLVM::AndOp>(op.getLoc(), popcnt, one);522rewriter.replaceOp(op, popcntMod2);523524return mlir::LogicalResult::success();525}526527mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(528cir::BitPopcountOp op, OpAdaptor adaptor,529mlir::ConversionPatternRewriter &rewriter) const {530auto resTy = getTypeConverter()->convertType(op.getType());531auto llvmOp = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,532adaptor.getInput());533rewriter.replaceOp(op, llvmOp);534return mlir::LogicalResult::success();535}536537mlir::LogicalResult CIRToLLVMBitReverseOpLowering::matchAndRewrite(538cir::BitReverseOp op, OpAdaptor adaptor,539mlir::ConversionPatternRewriter &rewriter) const {540rewriter.replaceOpWithNewOp<mlir::LLVM::BitReverseOp>(op, adaptor.getInput());541return mlir::success();542}543544mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(545cir::BrCondOp brOp, OpAdaptor adaptor,546mlir::ConversionPatternRewriter &rewriter) const {547// When ZExtOp is implemented, we'll need to check if the condition is a548// ZExtOp and if so, delete it if it has a single use.549assert(!cir::MissingFeatures::zextOp());550551mlir::Value i1Condition = adaptor.getCond();552553rewriter.replaceOpWithNewOp<mlir::LLVM::CondBrOp>(554brOp, i1Condition, brOp.getDestTrue(), adaptor.getDestOperandsTrue(),555brOp.getDestFalse(), adaptor.getDestOperandsFalse());556557return mlir::success();558}559560mlir::LogicalResult CIRToLLVMByteSwapOpLowering::matchAndRewrite(561cir::ByteSwapOp op, OpAdaptor adaptor,562mlir::ConversionPatternRewriter &rewriter) const {563rewriter.replaceOpWithNewOp<mlir::LLVM::ByteSwapOp>(op, adaptor.getInput());564return mlir::LogicalResult::success();565}566567mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {568return getTypeConverter()->convertType(ty);569}570571mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(572cir::CastOp castOp, OpAdaptor adaptor,573mlir::ConversionPatternRewriter &rewriter) const {574// For arithmetic conversions, LLVM IR uses the same instruction to convert575// both individual scalars and entire vectors. This lowering pass handles576// both situations.577578switch (castOp.getKind()) {579case cir::CastKind::array_to_ptrdecay: {580const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType());581mlir::Value sourceValue = adaptor.getSrc();582mlir::Type targetType = convertTy(ptrTy);583mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,584ptrTy.getPointee());585llvm::SmallVector<mlir::LLVM::GEPArg> offset{0};586rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(587castOp, targetType, elementTy, sourceValue, offset);588break;589}590case cir::CastKind::int_to_bool: {591mlir::Value llvmSrcVal = adaptor.getSrc();592mlir::Value zeroInt = rewriter.create<mlir::LLVM::ConstantOp>(593castOp.getLoc(), llvmSrcVal.getType(), 0);594rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(595castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroInt);596break;597}598case cir::CastKind::integral: {599mlir::Type srcType = castOp.getSrc().getType();600mlir::Type dstType = castOp.getType();601mlir::Value llvmSrcVal = adaptor.getSrc();602mlir::Type llvmDstType = getTypeConverter()->convertType(dstType);603cir::IntType srcIntType =604mlir::cast<cir::IntType>(elementTypeIfVector(srcType));605cir::IntType dstIntType =606mlir::cast<cir::IntType>(elementTypeIfVector(dstType));607rewriter.replaceOp(castOp, getLLVMIntCast(rewriter, llvmSrcVal, llvmDstType,608srcIntType.isUnsigned(),609srcIntType.getWidth(),610dstIntType.getWidth()));611break;612}613case cir::CastKind::floating: {614mlir::Value llvmSrcVal = adaptor.getSrc();615mlir::Type llvmDstTy = getTypeConverter()->convertType(castOp.getType());616617mlir::Type srcTy = elementTypeIfVector(castOp.getSrc().getType());618mlir::Type dstTy = elementTypeIfVector(castOp.getType());619620if (!mlir::isa<cir::FPTypeInterface>(dstTy) ||621!mlir::isa<cir::FPTypeInterface>(srcTy))622return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy;623624auto getFloatWidth = [](mlir::Type ty) -> unsigned {625return mlir::cast<cir::FPTypeInterface>(ty).getWidth();626};627628if (getFloatWidth(srcTy) > getFloatWidth(dstTy))629rewriter.replaceOpWithNewOp<mlir::LLVM::FPTruncOp>(castOp, llvmDstTy,630llvmSrcVal);631else632rewriter.replaceOpWithNewOp<mlir::LLVM::FPExtOp>(castOp, llvmDstTy,633llvmSrcVal);634return mlir::success();635}636case cir::CastKind::int_to_ptr: {637auto dstTy = mlir::cast<cir::PointerType>(castOp.getType());638mlir::Value llvmSrcVal = adaptor.getSrc();639mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);640rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(castOp, llvmDstTy,641llvmSrcVal);642return mlir::success();643}644case cir::CastKind::ptr_to_int: {645auto dstTy = mlir::cast<cir::IntType>(castOp.getType());646mlir::Value llvmSrcVal = adaptor.getSrc();647mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);648rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(castOp, llvmDstTy,649llvmSrcVal);650return mlir::success();651}652case cir::CastKind::float_to_bool: {653mlir::Value llvmSrcVal = adaptor.getSrc();654auto kind = mlir::LLVM::FCmpPredicate::une;655656// Check if float is not equal to zero.657auto zeroFloat = rewriter.create<mlir::LLVM::ConstantOp>(658castOp.getLoc(), llvmSrcVal.getType(),659mlir::FloatAttr::get(llvmSrcVal.getType(), 0.0));660661// Extend comparison result to either bool (C++) or int (C).662rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(castOp, kind, llvmSrcVal,663zeroFloat);664665return mlir::success();666}667case cir::CastKind::bool_to_int: {668auto dstTy = mlir::cast<cir::IntType>(castOp.getType());669mlir::Value llvmSrcVal = adaptor.getSrc();670auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType());671auto llvmDstTy =672mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy));673if (llvmSrcTy.getWidth() == llvmDstTy.getWidth())674rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,675llvmSrcVal);676else677rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(castOp, llvmDstTy,678llvmSrcVal);679return mlir::success();680}681case cir::CastKind::bool_to_float: {682mlir::Type dstTy = castOp.getType();683mlir::Value llvmSrcVal = adaptor.getSrc();684mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);685rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,686llvmSrcVal);687return mlir::success();688}689case cir::CastKind::int_to_float: {690mlir::Type dstTy = castOp.getType();691mlir::Value llvmSrcVal = adaptor.getSrc();692mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);693if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getSrc().getType()))694.isSigned())695rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(castOp, llvmDstTy,696llvmSrcVal);697else698rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,699llvmSrcVal);700return mlir::success();701}702case cir::CastKind::float_to_int: {703mlir::Type dstTy = castOp.getType();704mlir::Value llvmSrcVal = adaptor.getSrc();705mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);706if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getType()))707.isSigned())708rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(castOp, llvmDstTy,709llvmSrcVal);710else711rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(castOp, llvmDstTy,712llvmSrcVal);713return mlir::success();714}715case cir::CastKind::bitcast: {716mlir::Type dstTy = castOp.getType();717mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);718719assert(!MissingFeatures::cxxABI());720assert(!MissingFeatures::dataMemberType());721722mlir::Value llvmSrcVal = adaptor.getSrc();723rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,724llvmSrcVal);725return mlir::success();726}727case cir::CastKind::ptr_to_bool: {728mlir::Value llvmSrcVal = adaptor.getSrc();729mlir::Value zeroPtr = rewriter.create<mlir::LLVM::ZeroOp>(730castOp.getLoc(), llvmSrcVal.getType());731rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(732castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroPtr);733break;734}735case cir::CastKind::address_space: {736mlir::Type dstTy = castOp.getType();737mlir::Value llvmSrcVal = adaptor.getSrc();738mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);739rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(castOp, llvmDstTy,740llvmSrcVal);741break;742}743case cir::CastKind::member_ptr_to_bool:744assert(!MissingFeatures::cxxABI());745assert(!MissingFeatures::methodType());746break;747default: {748return castOp.emitError("Unhandled cast kind: ")749<< castOp.getKindAttrName();750}751}752753return mlir::success();754}755756mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(757cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,758mlir::ConversionPatternRewriter &rewriter) const {759760const mlir::TypeConverter *tc = getTypeConverter();761const mlir::Type resultTy = tc->convertType(ptrStrideOp.getType());762763mlir::Type elementTy =764convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementTy());765mlir::MLIRContext *ctx = elementTy.getContext();766767// void and function types doesn't really have a layout to use in GEPs,768// make it i8 instead.769if (mlir::isa<mlir::LLVM::LLVMVoidType>(elementTy) ||770mlir::isa<mlir::LLVM::LLVMFunctionType>(elementTy))771elementTy = mlir::IntegerType::get(elementTy.getContext(), 8,772mlir::IntegerType::Signless);773// Zero-extend, sign-extend or trunc the pointer value.774mlir::Value index = adaptor.getStride();775const unsigned width =776mlir::cast<mlir::IntegerType>(index.getType()).getWidth();777const std::optional<std::uint64_t> layoutWidth =778dataLayout.getTypeIndexBitwidth(adaptor.getBase().getType());779780mlir::Operation *indexOp = index.getDefiningOp();781if (indexOp && layoutWidth && width != *layoutWidth) {782// If the index comes from a subtraction, make sure the extension happens783// before it. To achieve that, look at unary minus, which already got784// lowered to "sub 0, x".785const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp);786auto unary = dyn_cast_if_present<cir::UnaryOp>(787ptrStrideOp.getStride().getDefiningOp());788bool rewriteSub =789unary && unary.getKind() == cir::UnaryOpKind::Minus && sub;790if (rewriteSub)791index = indexOp->getOperand(1);792793// Handle the cast794const auto llvmDstType = mlir::IntegerType::get(ctx, *layoutWidth);795index = getLLVMIntCast(rewriter, index, llvmDstType,796ptrStrideOp.getStride().getType().isUnsigned(),797width, *layoutWidth);798799// Rewrite the sub in front of extensions/trunc800if (rewriteSub) {801index = rewriter.create<mlir::LLVM::SubOp>(802index.getLoc(), index.getType(),803rewriter.create<mlir::LLVM::ConstantOp>(index.getLoc(),804index.getType(), 0),805index);806rewriter.eraseOp(sub);807}808}809810rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(811ptrStrideOp, resultTy, elementTy, adaptor.getBase(), index);812return mlir::success();813}814815mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(816cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,817mlir::ConversionPatternRewriter &rewriter) const {818const mlir::Type resultType =819getTypeConverter()->convertType(baseClassOp.getType());820mlir::Value derivedAddr = adaptor.getDerivedAddr();821llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {822adaptor.getOffset().getZExtValue()};823mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8,824mlir::IntegerType::Signless);825if (adaptor.getOffset().getZExtValue() == 0) {826rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(827baseClassOp, resultType, adaptor.getDerivedAddr());828return mlir::success();829}830831if (baseClassOp.getAssumeNotNull()) {832rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(833baseClassOp, resultType, byteType, derivedAddr, offset);834} else {835auto loc = baseClassOp.getLoc();836mlir::Value isNull = rewriter.create<mlir::LLVM::ICmpOp>(837loc, mlir::LLVM::ICmpPredicate::eq, derivedAddr,838rewriter.create<mlir::LLVM::ZeroOp>(loc, derivedAddr.getType()));839mlir::Value adjusted = rewriter.create<mlir::LLVM::GEPOp>(840loc, resultType, byteType, derivedAddr, offset);841rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(baseClassOp, isNull,842derivedAddr, adjusted);843}844return mlir::success();845}846847mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(848cir::AllocaOp op, OpAdaptor adaptor,849mlir::ConversionPatternRewriter &rewriter) const {850assert(!cir::MissingFeatures::opAllocaDynAllocSize());851mlir::Value size = rewriter.create<mlir::LLVM::ConstantOp>(852op.getLoc(), typeConverter->convertType(rewriter.getIndexType()), 1);853mlir::Type elementTy =854convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType());855mlir::Type resultTy =856convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());857858assert(!cir::MissingFeatures::addressSpace());859assert(!cir::MissingFeatures::opAllocaAnnotations());860861rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(862op, resultTy, elementTy, size, op.getAlignmentAttr().getInt());863864return mlir::success();865}866867mlir::LogicalResult CIRToLLVMReturnOpLowering::matchAndRewrite(868cir::ReturnOp op, OpAdaptor adaptor,869mlir::ConversionPatternRewriter &rewriter) const {870rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op, adaptor.getOperands());871return mlir::LogicalResult::success();872}873874static mlir::LogicalResult875rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,876mlir::ConversionPatternRewriter &rewriter,877const mlir::TypeConverter *converter,878mlir::FlatSymbolRefAttr calleeAttr) {879llvm::SmallVector<mlir::Type, 8> llvmResults;880mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes();881auto call = cast<cir::CIRCallOpInterface>(op);882883if (converter->convertTypes(cirResults, llvmResults).failed())884return mlir::failure();885886assert(!cir::MissingFeatures::opCallCallConv());887888mlir::LLVM::MemoryEffectsAttr memoryEffects;889bool noUnwind = false;890bool willReturn = false;891convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),892memoryEffects, noUnwind, willReturn);893894mlir::LLVM::LLVMFunctionType llvmFnTy;895if (calleeAttr) { // direct call896mlir::FunctionOpInterface fn =897mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(898op, calleeAttr);899assert(fn && "Did not find function for call");900llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(901converter->convertType(fn.getFunctionType()));902} else { // indirect call903assert(!op->getOperands().empty() &&904"operands list must no be empty for the indirect call");905auto calleeTy = op->getOperands().front().getType();906auto calleePtrTy = cast<cir::PointerType>(calleeTy);907auto calleeFuncTy = cast<cir::FuncType>(calleePtrTy.getPointee());908calleeFuncTy.dump();909converter->convertType(calleeFuncTy).dump();910llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(911converter->convertType(calleeFuncTy));912}913914assert(!cir::MissingFeatures::opCallLandingPad());915assert(!cir::MissingFeatures::opCallContinueBlock());916assert(!cir::MissingFeatures::opCallCallConv());917918auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(919op, llvmFnTy, calleeAttr, callOperands);920if (memoryEffects)921newOp.setMemoryEffectsAttr(memoryEffects);922newOp.setNoUnwind(noUnwind);923newOp.setWillReturn(willReturn);924925return mlir::success();926}927928mlir::LogicalResult CIRToLLVMCallOpLowering::matchAndRewrite(929cir::CallOp op, OpAdaptor adaptor,930mlir::ConversionPatternRewriter &rewriter) const {931return rewriteCallOrInvoke(op.getOperation(), adaptor.getOperands(), rewriter,932getTypeConverter(), op.getCalleeAttr());933}934935mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(936cir::LoadOp op, OpAdaptor adaptor,937mlir::ConversionPatternRewriter &rewriter) const {938const mlir::Type llvmTy =939convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());940assert(!cir::MissingFeatures::opLoadStoreMemOrder());941std::optional<size_t> opAlign = op.getAlignment();942unsigned alignment =943(unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));944945assert(!cir::MissingFeatures::lowerModeOptLevel());946947// TODO: nontemporal, syncscope.948assert(!cir::MissingFeatures::opLoadStoreVolatile());949mlir::LLVM::LoadOp newLoad = rewriter.create<mlir::LLVM::LoadOp>(950op->getLoc(), llvmTy, adaptor.getAddr(), alignment,951/*volatile=*/false, /*nontemporal=*/false,952/*invariant=*/false, /*invariantGroup=*/false,953mlir::LLVM::AtomicOrdering::not_atomic);954955// Convert adapted result to its original type if needed.956mlir::Value result =957emitFromMemory(rewriter, dataLayout, op, newLoad.getResult());958rewriter.replaceOp(op, result);959assert(!cir::MissingFeatures::opLoadStoreTbaa());960return mlir::LogicalResult::success();961}962963mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite(964cir::StoreOp op, OpAdaptor adaptor,965mlir::ConversionPatternRewriter &rewriter) const {966assert(!cir::MissingFeatures::opLoadStoreMemOrder());967const mlir::Type llvmTy =968getTypeConverter()->convertType(op.getValue().getType());969std::optional<size_t> opAlign = op.getAlignment();970unsigned alignment =971(unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));972973assert(!cir::MissingFeatures::lowerModeOptLevel());974975// Convert adapted value to its memory type if needed.976mlir::Value value = emitToMemory(rewriter, dataLayout,977op.getValue().getType(), adaptor.getValue());978// TODO: nontemporal, syncscope.979assert(!cir::MissingFeatures::opLoadStoreVolatile());980mlir::LLVM::StoreOp storeOp = rewriter.create<mlir::LLVM::StoreOp>(981op->getLoc(), value, adaptor.getAddr(), alignment, /*volatile=*/false,982/*nontemporal=*/false, /*invariantGroup=*/false,983mlir::LLVM::AtomicOrdering::not_atomic);984rewriter.replaceOp(op, storeOp);985assert(!cir::MissingFeatures::opLoadStoreTbaa());986return mlir::LogicalResult::success();987}988989bool hasTrailingZeros(cir::ConstArrayAttr attr) {990auto array = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts());991return attr.hasTrailingZeros() ||992(array && std::count_if(array.begin(), array.end(), [](auto elt) {993auto ar = dyn_cast<cir::ConstArrayAttr>(elt);994return ar && hasTrailingZeros(ar);995}));996}997998mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(999cir::ConstantOp op, OpAdaptor adaptor,1000mlir::ConversionPatternRewriter &rewriter) const {1001mlir::Attribute attr = op.getValue();10021003if (mlir::isa<mlir::IntegerType>(op.getType())) {1004// Verified cir.const operations cannot actually be of these types, but the1005// lowering pass may generate temporary cir.const operations with these1006// types. This is OK since MLIR allows unverified operations to be alive1007// during a pass as long as they don't live past the end of the pass.1008attr = op.getValue();1009} else if (mlir::isa<cir::BoolType>(op.getType())) {1010int value = mlir::cast<cir::BoolAttr>(op.getValue()).getValue();1011attr = rewriter.getIntegerAttr(typeConverter->convertType(op.getType()),1012value);1013} else if (mlir::isa<cir::IntType>(op.getType())) {1014assert(!cir::MissingFeatures::opGlobalViewAttr());10151016attr = rewriter.getIntegerAttr(1017typeConverter->convertType(op.getType()),1018mlir::cast<cir::IntAttr>(op.getValue()).getValue());1019} else if (mlir::isa<cir::FPTypeInterface>(op.getType())) {1020attr = rewriter.getFloatAttr(1021typeConverter->convertType(op.getType()),1022mlir::cast<cir::FPAttr>(op.getValue()).getValue());1023} else if (mlir::isa<cir::PointerType>(op.getType())) {1024// Optimize with dedicated LLVM op for null pointers.1025if (mlir::isa<cir::ConstPtrAttr>(op.getValue())) {1026if (mlir::cast<cir::ConstPtrAttr>(op.getValue()).isNullValue()) {1027rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(1028op, typeConverter->convertType(op.getType()));1029return mlir::success();1030}1031}1032assert(!cir::MissingFeatures::opGlobalViewAttr());1033attr = op.getValue();1034} else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {1035const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());1036if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))1037return op.emitError() << "array does not have a constant initializer";10381039std::optional<mlir::Attribute> denseAttr;1040if (constArr && hasTrailingZeros(constArr)) {1041const mlir::Value newOp =1042lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter());1043rewriter.replaceOp(op, newOp);1044return mlir::success();1045} else if (constArr &&1046(denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {1047attr = denseAttr.value();1048} else {1049const mlir::Value initVal =1050lowerCirAttrAsValue(op, op.getValue(), rewriter, typeConverter);1051rewriter.replaceAllUsesWith(op, initVal);1052rewriter.eraseOp(op);1053return mlir::success();1054}1055} else if (const auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) {1056rewriter.replaceOp(op, lowerCirAttrAsValue(op, op.getValue(), rewriter,1057getTypeConverter()));1058return mlir::success();1059} else if (auto complexTy = mlir::dyn_cast<cir::ComplexType>(op.getType())) {1060mlir::Type complexElemTy = complexTy.getElementType();1061mlir::Type complexElemLLVMTy = typeConverter->convertType(complexElemTy);10621063if (auto zeroInitAttr = mlir::dyn_cast<cir::ZeroAttr>(op.getValue())) {1064mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(complexElemLLVMTy);1065mlir::ArrayAttr array = rewriter.getArrayAttr({zeroAttr, zeroAttr});1066rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(1067op, getTypeConverter()->convertType(op.getType()), array);1068return mlir::success();1069}10701071auto complexAttr = mlir::cast<cir::ConstComplexAttr>(op.getValue());10721073mlir::Attribute components[2];1074if (mlir::isa<cir::IntType>(complexElemTy)) {1075components[0] = rewriter.getIntegerAttr(1076complexElemLLVMTy,1077mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());1078components[1] = rewriter.getIntegerAttr(1079complexElemLLVMTy,1080mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());1081} else {1082components[0] = rewriter.getFloatAttr(1083complexElemLLVMTy,1084mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());1085components[1] = rewriter.getFloatAttr(1086complexElemLLVMTy,1087mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());1088}10891090attr = rewriter.getArrayAttr(components);1091} else {1092return op.emitError() << "unsupported constant type " << op.getType();1093}10941095rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(1096op, getTypeConverter()->convertType(op.getType()), attr);10971098return mlir::success();1099}11001101mlir::LogicalResult CIRToLLVMExpectOpLowering::matchAndRewrite(1102cir::ExpectOp op, OpAdaptor adaptor,1103mlir::ConversionPatternRewriter &rewriter) const {1104// TODO(cir): do not generate LLVM intrinsics under -O01105assert(!cir::MissingFeatures::optInfoAttr());11061107std::optional<llvm::APFloat> prob = op.getProb();1108if (prob)1109rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectWithProbabilityOp>(1110op, adaptor.getVal(), adaptor.getExpected(), prob.value());1111else1112rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectOp>(op, adaptor.getVal(),1113adaptor.getExpected());1114return mlir::success();1115}11161117/// Convert the `cir.func` attributes to `llvm.func` attributes.1118/// Only retain those attributes that are not constructed by1119/// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out1120/// argument attributes.1121void CIRToLLVMFuncOpLowering::lowerFuncAttributes(1122cir::FuncOp func, bool filterArgAndResAttrs,1123SmallVectorImpl<mlir::NamedAttribute> &result) const {1124assert(!cir::MissingFeatures::opFuncCallingConv());1125for (mlir::NamedAttribute attr : func->getAttrs()) {1126assert(!cir::MissingFeatures::opFuncCallingConv());1127if (attr.getName() == mlir::SymbolTable::getSymbolAttrName() ||1128attr.getName() == func.getFunctionTypeAttrName() ||1129attr.getName() == getLinkageAttrNameString() ||1130attr.getName() == func.getGlobalVisibilityAttrName() ||1131attr.getName() == func.getDsoLocalAttrName() ||1132(filterArgAndResAttrs &&1133(attr.getName() == func.getArgAttrsAttrName() ||1134attr.getName() == func.getResAttrsAttrName())))1135continue;11361137assert(!cir::MissingFeatures::opFuncExtraAttrs());1138result.push_back(attr);1139}1140}11411142mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(1143cir::FuncOp op, OpAdaptor adaptor,1144mlir::ConversionPatternRewriter &rewriter) const {11451146cir::FuncType fnType = op.getFunctionType();1147bool isDsoLocal = op.getDsoLocal();1148mlir::TypeConverter::SignatureConversion signatureConversion(1149fnType.getNumInputs());11501151for (const auto &argType : llvm::enumerate(fnType.getInputs())) {1152mlir::Type convertedType = typeConverter->convertType(argType.value());1153if (!convertedType)1154return mlir::failure();1155signatureConversion.addInputs(argType.index(), convertedType);1156}11571158mlir::Type resultType =1159getTypeConverter()->convertType(fnType.getReturnType());11601161// Create the LLVM function operation.1162mlir::Type llvmFnTy = mlir::LLVM::LLVMFunctionType::get(1163resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),1164signatureConversion.getConvertedTypes(),1165/*isVarArg=*/fnType.isVarArg());1166// LLVMFuncOp expects a single FileLine Location instead of a fused1167// location.1168mlir::Location loc = op.getLoc();1169if (mlir::FusedLoc fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc))1170loc = fusedLoc.getLocations()[0];1171assert((mlir::isa<mlir::FileLineColLoc>(loc) ||1172mlir::isa<mlir::UnknownLoc>(loc)) &&1173"expected single location or unknown location here");11741175mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());1176assert(!cir::MissingFeatures::opFuncCallingConv());1177mlir::LLVM::CConv cconv = mlir::LLVM::CConv::C;1178SmallVector<mlir::NamedAttribute, 4> attributes;1179lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);11801181mlir::LLVM::LLVMFuncOp fn = rewriter.create<mlir::LLVM::LLVMFuncOp>(1182loc, op.getName(), llvmFnTy, linkage, isDsoLocal, cconv,1183mlir::SymbolRefAttr(), attributes);11841185assert(!cir::MissingFeatures::opFuncMultipleReturnVals());11861187fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(1188getContext(), lowerCIRVisibilityToLLVMVisibility(1189op.getGlobalVisibilityAttr().getValue())));11901191rewriter.inlineRegionBefore(op.getBody(), fn.getBody(), fn.end());1192if (failed(rewriter.convertRegionTypes(&fn.getBody(), *typeConverter,1193&signatureConversion)))1194return mlir::failure();11951196rewriter.eraseOp(op);11971198return mlir::LogicalResult::success();1199}12001201mlir::LogicalResult CIRToLLVMGetGlobalOpLowering::matchAndRewrite(1202cir::GetGlobalOp op, OpAdaptor adaptor,1203mlir::ConversionPatternRewriter &rewriter) const {1204// FIXME(cir): Premature DCE to avoid lowering stuff we're not using.1205// CIRGen should mitigate this and not emit the get_global.1206if (op->getUses().empty()) {1207rewriter.eraseOp(op);1208return mlir::success();1209}12101211mlir::Type type = getTypeConverter()->convertType(op.getType());1212mlir::Operation *newop =1213rewriter.create<mlir::LLVM::AddressOfOp>(op.getLoc(), type, op.getName());12141215assert(!cir::MissingFeatures::opGlobalThreadLocal());12161217rewriter.replaceOp(op, newop);1218return mlir::success();1219}12201221/// Replace CIR global with a region initialized LLVM global and update1222/// insertion point to the end of the initializer block.1223void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(1224cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {1225const mlir::Type llvmType =1226convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());12271228// FIXME: These default values are placeholders until the the equivalent1229// attributes are available on cir.global ops. This duplicates code1230// in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go1231// away when the placeholders are no longer needed.1232assert(!cir::MissingFeatures::opGlobalConstant());1233const bool isConst = false;1234assert(!cir::MissingFeatures::addressSpace());1235const unsigned addrSpace = 0;1236const bool isDsoLocal = op.getDsoLocal();1237assert(!cir::MissingFeatures::opGlobalThreadLocal());1238const bool isThreadLocal = false;1239const uint64_t alignment = op.getAlignment().value_or(0);1240const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());1241const StringRef symbol = op.getSymName();1242mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);12431244SmallVector<mlir::NamedAttribute> attributes;1245mlir::LLVM::GlobalOp newGlobalOp =1246rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(1247op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,1248isDsoLocal, isThreadLocal, comdatAttr, attributes);1249newGlobalOp.getRegion().emplaceBlock();1250rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());1251}12521253mlir::LogicalResult1254CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(1255cir::GlobalOp op, mlir::Attribute init,1256mlir::ConversionPatternRewriter &rewriter) const {1257// TODO: Generalize this handling when more types are needed here.1258assert((isa<cir::ConstArrayAttr, cir::ConstVectorAttr, cir::ConstPtrAttr,1259cir::ConstComplexAttr, cir::ZeroAttr>(init)));12601261// TODO(cir): once LLVM's dialect has proper equivalent attributes this1262// should be updated. For now, we use a custom op to initialize globals1263// to the appropriate value.1264const mlir::Location loc = op.getLoc();1265setupRegionInitializedLLVMGlobalOp(op, rewriter);1266CIRAttrToValue valueConverter(op, rewriter, typeConverter);1267mlir::Value value = valueConverter.visit(init);1268rewriter.create<mlir::LLVM::ReturnOp>(loc, value);1269return mlir::success();1270}12711272mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(1273cir::GlobalOp op, OpAdaptor adaptor,1274mlir::ConversionPatternRewriter &rewriter) const {12751276std::optional<mlir::Attribute> init = op.getInitialValue();12771278// Fetch required values to create LLVM op.1279const mlir::Type cirSymType = op.getSymType();12801281// This is the LLVM dialect type.1282const mlir::Type llvmType =1283convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType);1284// FIXME: These default values are placeholders until the the equivalent1285// attributes are available on cir.global ops.1286assert(!cir::MissingFeatures::opGlobalConstant());1287const bool isConst = false;1288assert(!cir::MissingFeatures::addressSpace());1289const unsigned addrSpace = 0;1290const bool isDsoLocal = op.getDsoLocal();1291assert(!cir::MissingFeatures::opGlobalThreadLocal());1292const bool isThreadLocal = false;1293const uint64_t alignment = op.getAlignment().value_or(0);1294const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());1295const StringRef symbol = op.getSymName();1296SmallVector<mlir::NamedAttribute> attributes;1297mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);12981299if (init.has_value()) {1300if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {1301GlobalInitAttrRewriter initRewriter(llvmType, rewriter);1302init = initRewriter.visit(init.value());1303// If initRewriter returned a null attribute, init will have a value but1304// the value will be null. If that happens, initRewriter didn't handle the1305// attribute type. It probably needs to be added to1306// GlobalInitAttrRewriter.1307if (!init.value()) {1308op.emitError() << "unsupported initializer '" << init.value() << "'";1309return mlir::failure();1310}1311} else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,1312cir::ConstPtrAttr, cir::ConstComplexAttr,1313cir::ZeroAttr>(init.value())) {1314// TODO(cir): once LLVM's dialect has proper equivalent attributes this1315// should be updated. For now, we use a custom op to initialize globals1316// to the appropriate value.1317return matchAndRewriteRegionInitializedGlobal(op, init.value(), rewriter);1318} else {1319// We will only get here if new initializer types are added and this1320// code is not updated to handle them.1321op.emitError() << "unsupported initializer '" << init.value() << "'";1322return mlir::failure();1323}1324}13251326// Rewrite op.1327rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(1328op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),1329alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);1330return mlir::success();1331}13321333mlir::SymbolRefAttr1334CIRToLLVMGlobalOpLowering::getComdatAttr(cir::GlobalOp &op,1335mlir::OpBuilder &builder) const {1336if (!op.getComdat())1337return mlir::SymbolRefAttr{};13381339mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();1340mlir::OpBuilder::InsertionGuard guard(builder);1341StringRef comdatName("__llvm_comdat_globals");1342if (!comdatOp) {1343builder.setInsertionPointToStart(module.getBody());1344comdatOp =1345builder.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);1346}13471348builder.setInsertionPointToStart(&comdatOp.getBody().back());1349auto selectorOp = builder.create<mlir::LLVM::ComdatSelectorOp>(1350comdatOp.getLoc(), op.getSymName(), mlir::LLVM::comdat::Comdat::Any);1351return mlir::SymbolRefAttr::get(1352builder.getContext(), comdatName,1353mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr()));1354}13551356mlir::LogicalResult CIRToLLVMSwitchFlatOpLowering::matchAndRewrite(1357cir::SwitchFlatOp op, OpAdaptor adaptor,1358mlir::ConversionPatternRewriter &rewriter) const {13591360llvm::SmallVector<mlir::APInt, 8> caseValues;1361for (mlir::Attribute val : op.getCaseValues()) {1362auto intAttr = cast<cir::IntAttr>(val);1363caseValues.push_back(intAttr.getValue());1364}13651366llvm::SmallVector<mlir::Block *, 8> caseDestinations;1367llvm::SmallVector<mlir::ValueRange, 8> caseOperands;13681369for (mlir::Block *x : op.getCaseDestinations())1370caseDestinations.push_back(x);13711372for (mlir::OperandRange x : op.getCaseOperands())1373caseOperands.push_back(x);13741375// Set switch op to branch to the newly created blocks.1376rewriter.setInsertionPoint(op);1377rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(1378op, adaptor.getCondition(), op.getDefaultDestination(),1379op.getDefaultOperands(), caseValues, caseDestinations, caseOperands);1380return mlir::success();1381}13821383mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(1384cir::UnaryOp op, OpAdaptor adaptor,1385mlir::ConversionPatternRewriter &rewriter) const {1386assert(op.getType() == op.getInput().getType() &&1387"Unary operation's operand type and result type are different");1388mlir::Type type = op.getType();1389mlir::Type elementType = elementTypeIfVector(type);1390bool isVector = mlir::isa<cir::VectorType>(type);1391mlir::Type llvmType = getTypeConverter()->convertType(type);1392mlir::Location loc = op.getLoc();13931394// Integer unary operations: + - ~ ++ --1395if (mlir::isa<cir::IntType>(elementType)) {1396mlir::LLVM::IntegerOverflowFlags maybeNSW =1397op.getNoSignedWrap() ? mlir::LLVM::IntegerOverflowFlags::nsw1398: mlir::LLVM::IntegerOverflowFlags::none;1399switch (op.getKind()) {1400case cir::UnaryOpKind::Inc: {1401assert(!isVector && "++ not allowed on vector types");1402auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);1403rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(1404op, llvmType, adaptor.getInput(), one, maybeNSW);1405return mlir::success();1406}1407case cir::UnaryOpKind::Dec: {1408assert(!isVector && "-- not allowed on vector types");1409auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);1410rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, adaptor.getInput(),1411one, maybeNSW);1412return mlir::success();1413}1414case cir::UnaryOpKind::Plus:1415rewriter.replaceOp(op, adaptor.getInput());1416return mlir::success();1417case cir::UnaryOpKind::Minus: {1418mlir::Value zero;1419if (isVector)1420zero = rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmType);1421else1422zero = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 0);1423rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(1424op, zero, adaptor.getInput(), maybeNSW);1425return mlir::success();1426}1427case cir::UnaryOpKind::Not: {1428// bit-wise compliment operator, implemented as an XOR with -1.1429mlir::Value minusOne;1430if (isVector) {1431const uint64_t numElements =1432mlir::dyn_cast<cir::VectorType>(type).getSize();1433std::vector<int32_t> values(numElements, -1);1434mlir::DenseIntElementsAttr denseVec = rewriter.getI32VectorAttr(values);1435minusOne =1436rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, denseVec);1437} else {1438minusOne = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, -1);1439}1440rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),1441minusOne);1442return mlir::success();1443}1444}1445llvm_unreachable("Unexpected unary op for int");1446}14471448// Floating point unary operations: + - ++ --1449if (mlir::isa<cir::FPTypeInterface>(elementType)) {1450switch (op.getKind()) {1451case cir::UnaryOpKind::Inc: {1452assert(!isVector && "++ not allowed on vector types");1453mlir::LLVM::ConstantOp one = rewriter.create<mlir::LLVM::ConstantOp>(1454loc, llvmType, rewriter.getFloatAttr(llvmType, 1.0));1455rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, one,1456adaptor.getInput());1457return mlir::success();1458}1459case cir::UnaryOpKind::Dec: {1460assert(!isVector && "-- not allowed on vector types");1461mlir::LLVM::ConstantOp minusOne = rewriter.create<mlir::LLVM::ConstantOp>(1462loc, llvmType, rewriter.getFloatAttr(llvmType, -1.0));1463rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, minusOne,1464adaptor.getInput());1465return mlir::success();1466}1467case cir::UnaryOpKind::Plus:1468rewriter.replaceOp(op, adaptor.getInput());1469return mlir::success();1470case cir::UnaryOpKind::Minus:1471rewriter.replaceOpWithNewOp<mlir::LLVM::FNegOp>(op, llvmType,1472adaptor.getInput());1473return mlir::success();1474case cir::UnaryOpKind::Not:1475return op.emitError() << "Unary not is invalid for floating-point types";1476}1477llvm_unreachable("Unexpected unary op for float");1478}14791480// Boolean unary operations: ! only. (For all others, the operand has1481// already been promoted to int.)1482if (mlir::isa<cir::BoolType>(elementType)) {1483switch (op.getKind()) {1484case cir::UnaryOpKind::Inc:1485case cir::UnaryOpKind::Dec:1486case cir::UnaryOpKind::Plus:1487case cir::UnaryOpKind::Minus:1488// Some of these are allowed in source code, but we shouldn't get here1489// with a boolean type.1490return op.emitError() << "Unsupported unary operation on boolean type";1491case cir::UnaryOpKind::Not: {1492assert(!isVector && "NYI: op! on vector mask");1493auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);1494rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),1495one);1496return mlir::success();1497}1498}1499llvm_unreachable("Unexpected unary op for bool");1500}15011502// Pointer unary operations: + only. (++ and -- of pointers are implemented1503// with cir.ptr_stride, not cir.unary.)1504if (mlir::isa<cir::PointerType>(elementType)) {1505return op.emitError()1506<< "Unary operation on pointer types is not yet implemented";1507}15081509return op.emitError() << "Unary operation has unsupported type: "1510<< elementType;1511}15121513mlir::LLVM::IntegerOverflowFlags1514CIRToLLVMBinOpLowering::getIntOverflowFlag(cir::BinOp op) const {1515if (op.getNoUnsignedWrap())1516return mlir::LLVM::IntegerOverflowFlags::nuw;15171518if (op.getNoSignedWrap())1519return mlir::LLVM::IntegerOverflowFlags::nsw;15201521return mlir::LLVM::IntegerOverflowFlags::none;1522}15231524static bool isIntTypeUnsigned(mlir::Type type) {1525// TODO: Ideally, we should only need to check cir::IntType here.1526return mlir::isa<cir::IntType>(type)1527? mlir::cast<cir::IntType>(type).isUnsigned()1528: mlir::cast<mlir::IntegerType>(type).isUnsigned();1529}15301531mlir::LogicalResult CIRToLLVMBinOpLowering::matchAndRewrite(1532cir::BinOp op, OpAdaptor adaptor,1533mlir::ConversionPatternRewriter &rewriter) const {1534if (adaptor.getLhs().getType() != adaptor.getRhs().getType())1535return op.emitError() << "inconsistent operands' types not supported yet";15361537mlir::Type type = op.getRhs().getType();1538if (!mlir::isa<cir::IntType, cir::BoolType, cir::FPTypeInterface,1539mlir::IntegerType, cir::VectorType>(type))1540return op.emitError() << "operand type not supported yet";15411542const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());1543const mlir::Type llvmEltTy = elementTypeIfVector(llvmTy);15441545const mlir::Value rhs = adaptor.getRhs();1546const mlir::Value lhs = adaptor.getLhs();1547type = elementTypeIfVector(type);15481549switch (op.getKind()) {1550case cir::BinOpKind::Add:1551if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {1552if (op.getSaturated()) {1553if (isIntTypeUnsigned(type)) {1554rewriter.replaceOpWithNewOp<mlir::LLVM::UAddSat>(op, lhs, rhs);1555break;1556}1557rewriter.replaceOpWithNewOp<mlir::LLVM::SAddSat>(op, lhs, rhs);1558break;1559}1560rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(op, llvmTy, lhs, rhs,1561getIntOverflowFlag(op));1562} else {1563rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, lhs, rhs);1564}1565break;1566case cir::BinOpKind::Sub:1567if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {1568if (op.getSaturated()) {1569if (isIntTypeUnsigned(type)) {1570rewriter.replaceOpWithNewOp<mlir::LLVM::USubSat>(op, lhs, rhs);1571break;1572}1573rewriter.replaceOpWithNewOp<mlir::LLVM::SSubSat>(op, lhs, rhs);1574break;1575}1576rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmTy, lhs, rhs,1577getIntOverflowFlag(op));1578} else {1579rewriter.replaceOpWithNewOp<mlir::LLVM::FSubOp>(op, lhs, rhs);1580}1581break;1582case cir::BinOpKind::Mul:1583if (mlir::isa<mlir::IntegerType>(llvmEltTy))1584rewriter.replaceOpWithNewOp<mlir::LLVM::MulOp>(op, llvmTy, lhs, rhs,1585getIntOverflowFlag(op));1586else1587rewriter.replaceOpWithNewOp<mlir::LLVM::FMulOp>(op, lhs, rhs);1588break;1589case cir::BinOpKind::Div:1590if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {1591auto isUnsigned = isIntTypeUnsigned(type);1592if (isUnsigned)1593rewriter.replaceOpWithNewOp<mlir::LLVM::UDivOp>(op, lhs, rhs);1594else1595rewriter.replaceOpWithNewOp<mlir::LLVM::SDivOp>(op, lhs, rhs);1596} else {1597rewriter.replaceOpWithNewOp<mlir::LLVM::FDivOp>(op, lhs, rhs);1598}1599break;1600case cir::BinOpKind::Rem:1601if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {1602auto isUnsigned = isIntTypeUnsigned(type);1603if (isUnsigned)1604rewriter.replaceOpWithNewOp<mlir::LLVM::URemOp>(op, lhs, rhs);1605else1606rewriter.replaceOpWithNewOp<mlir::LLVM::SRemOp>(op, lhs, rhs);1607} else {1608rewriter.replaceOpWithNewOp<mlir::LLVM::FRemOp>(op, lhs, rhs);1609}1610break;1611case cir::BinOpKind::And:1612rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, lhs, rhs);1613break;1614case cir::BinOpKind::Or:1615rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, lhs, rhs);1616break;1617case cir::BinOpKind::Xor:1618rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, lhs, rhs);1619break;1620case cir::BinOpKind::Max:1621if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {1622auto isUnsigned = isIntTypeUnsigned(type);1623if (isUnsigned)1624rewriter.replaceOpWithNewOp<mlir::LLVM::UMaxOp>(op, llvmTy, lhs, rhs);1625else1626rewriter.replaceOpWithNewOp<mlir::LLVM::SMaxOp>(op, llvmTy, lhs, rhs);1627}1628break;1629}1630return mlir::LogicalResult::success();1631}16321633/// Convert from a CIR comparison kind to an LLVM IR integral comparison kind.1634static mlir::LLVM::ICmpPredicate1635convertCmpKindToICmpPredicate(cir::CmpOpKind kind, bool isSigned) {1636using CIR = cir::CmpOpKind;1637using LLVMICmp = mlir::LLVM::ICmpPredicate;1638switch (kind) {1639case CIR::eq:1640return LLVMICmp::eq;1641case CIR::ne:1642return LLVMICmp::ne;1643case CIR::lt:1644return (isSigned ? LLVMICmp::slt : LLVMICmp::ult);1645case CIR::le:1646return (isSigned ? LLVMICmp::sle : LLVMICmp::ule);1647case CIR::gt:1648return (isSigned ? LLVMICmp::sgt : LLVMICmp::ugt);1649case CIR::ge:1650return (isSigned ? LLVMICmp::sge : LLVMICmp::uge);1651}1652llvm_unreachable("Unknown CmpOpKind");1653}16541655/// Convert from a CIR comparison kind to an LLVM IR floating-point comparison1656/// kind.1657static mlir::LLVM::FCmpPredicate1658convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {1659using CIR = cir::CmpOpKind;1660using LLVMFCmp = mlir::LLVM::FCmpPredicate;1661switch (kind) {1662case CIR::eq:1663return LLVMFCmp::oeq;1664case CIR::ne:1665return LLVMFCmp::une;1666case CIR::lt:1667return LLVMFCmp::olt;1668case CIR::le:1669return LLVMFCmp::ole;1670case CIR::gt:1671return LLVMFCmp::ogt;1672case CIR::ge:1673return LLVMFCmp::oge;1674}1675llvm_unreachable("Unknown CmpOpKind");1676}16771678mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(1679cir::CmpOp cmpOp, OpAdaptor adaptor,1680mlir::ConversionPatternRewriter &rewriter) const {1681mlir::Type type = cmpOp.getLhs().getType();16821683assert(!cir::MissingFeatures::dataMemberType());1684assert(!cir::MissingFeatures::methodType());16851686if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) {1687bool isSigned = mlir::isa<cir::IntType>(type)1688? mlir::cast<cir::IntType>(type).isSigned()1689: mlir::cast<mlir::IntegerType>(type).isSigned();1690mlir::LLVM::ICmpPredicate kind =1691convertCmpKindToICmpPredicate(cmpOp.getKind(), isSigned);1692rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(1693cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());1694return mlir::success();1695}16961697if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {1698mlir::LLVM::ICmpPredicate kind =1699convertCmpKindToICmpPredicate(cmpOp.getKind(),1700/* isSigned=*/false);1701rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(1702cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());1703return mlir::success();1704}17051706if (mlir::isa<cir::FPTypeInterface>(type)) {1707mlir::LLVM::FCmpPredicate kind =1708convertCmpKindToFCmpPredicate(cmpOp.getKind());1709rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(1710cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());1711return mlir::success();1712}17131714if (mlir::isa<cir::ComplexType>(type)) {1715mlir::Value lhs = adaptor.getLhs();1716mlir::Value rhs = adaptor.getRhs();1717mlir::Location loc = cmpOp.getLoc();17181719auto complexType = mlir::cast<cir::ComplexType>(cmpOp.getLhs().getType());1720mlir::Type complexElemTy =1721getTypeConverter()->convertType(complexType.getElementType());17221723auto lhsReal =1724rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);1725auto lhsImag =1726rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);1727auto rhsReal =1728rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);1729auto rhsImag =1730rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);17311732if (cmpOp.getKind() == cir::CmpOpKind::eq) {1733if (complexElemTy.isInteger()) {1734auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(1735loc, mlir::LLVM::ICmpPredicate::eq, lhsReal, rhsReal);1736auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(1737loc, mlir::LLVM::ICmpPredicate::eq, lhsImag, rhsImag);1738rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);1739return mlir::success();1740}17411742auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(1743loc, mlir::LLVM::FCmpPredicate::oeq, lhsReal, rhsReal);1744auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(1745loc, mlir::LLVM::FCmpPredicate::oeq, lhsImag, rhsImag);1746rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);1747return mlir::success();1748}17491750if (cmpOp.getKind() == cir::CmpOpKind::ne) {1751if (complexElemTy.isInteger()) {1752auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(1753loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);1754auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(1755loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);1756rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);1757return mlir::success();1758}17591760auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(1761loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);1762auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(1763loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);1764rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);1765return mlir::success();1766}1767}17681769return cmpOp.emitError() << "unsupported type for CmpOp: " << type;1770}17711772mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(1773cir::ShiftOp op, OpAdaptor adaptor,1774mlir::ConversionPatternRewriter &rewriter) const {1775assert((op.getValue().getType() == op.getType()) &&1776"inconsistent operands' types NYI");17771778const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());1779mlir::Value amt = adaptor.getAmount();1780mlir::Value val = adaptor.getValue();17811782auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType());1783bool isUnsigned;1784if (cirAmtTy) {1785auto cirValTy = mlir::cast<cir::IntType>(op.getValue().getType());1786isUnsigned = cirValTy.isUnsigned();17871788// Ensure shift amount is the same type as the value. Some undefined1789// behavior might occur in the casts below as per [C99 6.5.7.3].1790// Vector type shift amount needs no cast as type consistency is expected to1791// be already be enforced at CIRGen.1792if (cirAmtTy)1793amt = getLLVMIntCast(rewriter, amt, llvmTy, true, cirAmtTy.getWidth(),1794cirValTy.getWidth());1795} else {1796auto cirValVTy = mlir::cast<cir::VectorType>(op.getValue().getType());1797isUnsigned =1798mlir::cast<cir::IntType>(cirValVTy.getElementType()).isUnsigned();1799}18001801// Lower to the proper LLVM shift operation.1802if (op.getIsShiftleft()) {1803rewriter.replaceOpWithNewOp<mlir::LLVM::ShlOp>(op, llvmTy, val, amt);1804return mlir::success();1805}18061807if (isUnsigned)1808rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt);1809else1810rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt);1811return mlir::success();1812}18131814mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(1815cir::SelectOp op, OpAdaptor adaptor,1816mlir::ConversionPatternRewriter &rewriter) const {1817auto getConstantBool = [](mlir::Value value) -> cir::BoolAttr {1818auto definingOp =1819mlir::dyn_cast_if_present<cir::ConstantOp>(value.getDefiningOp());1820if (!definingOp)1821return {};18221823auto constValue = mlir::dyn_cast<cir::BoolAttr>(definingOp.getValue());1824if (!constValue)1825return {};18261827return constValue;1828};18291830// Two special cases in the LLVMIR codegen of select op:1831// - select %0, %1, false => and %0, %11832// - select %0, true, %1 => or %0, %11833if (mlir::isa<cir::BoolType>(op.getTrueValue().getType())) {1834cir::BoolAttr trueValue = getConstantBool(op.getTrueValue());1835cir::BoolAttr falseValue = getConstantBool(op.getFalseValue());1836if (falseValue && !falseValue.getValue()) {1837// select %0, %1, false => and %0, %11838rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, adaptor.getCondition(),1839adaptor.getTrueValue());1840return mlir::success();1841}1842if (trueValue && trueValue.getValue()) {1843// select %0, true, %1 => or %0, %11844rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, adaptor.getCondition(),1845adaptor.getFalseValue());1846return mlir::success();1847}1848}18491850mlir::Value llvmCondition = adaptor.getCondition();1851rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(1852op, llvmCondition, adaptor.getTrueValue(), adaptor.getFalseValue());18531854return mlir::success();1855}18561857static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,1858mlir::DataLayout &dataLayout) {1859converter.addConversion([&](cir::PointerType type) -> mlir::Type {1860// Drop pointee type since LLVM dialect only allows opaque pointers.1861assert(!cir::MissingFeatures::addressSpace());1862unsigned targetAS = 0;18631864return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);1865});1866converter.addConversion([&](cir::ArrayType type) -> mlir::Type {1867mlir::Type ty =1868convertTypeForMemory(converter, dataLayout, type.getElementType());1869return mlir::LLVM::LLVMArrayType::get(ty, type.getSize());1870});1871converter.addConversion([&](cir::VectorType type) -> mlir::Type {1872const mlir::Type ty = converter.convertType(type.getElementType());1873return mlir::VectorType::get(type.getSize(), ty);1874});1875converter.addConversion([&](cir::BoolType type) -> mlir::Type {1876return mlir::IntegerType::get(type.getContext(), 1,1877mlir::IntegerType::Signless);1878});1879converter.addConversion([&](cir::IntType type) -> mlir::Type {1880// LLVM doesn't work with signed types, so we drop the CIR signs here.1881return mlir::IntegerType::get(type.getContext(), type.getWidth());1882});1883converter.addConversion([&](cir::SingleType type) -> mlir::Type {1884return mlir::Float32Type::get(type.getContext());1885});1886converter.addConversion([&](cir::DoubleType type) -> mlir::Type {1887return mlir::Float64Type::get(type.getContext());1888});1889converter.addConversion([&](cir::FP80Type type) -> mlir::Type {1890return mlir::Float80Type::get(type.getContext());1891});1892converter.addConversion([&](cir::FP128Type type) -> mlir::Type {1893return mlir::Float128Type::get(type.getContext());1894});1895converter.addConversion([&](cir::LongDoubleType type) -> mlir::Type {1896return converter.convertType(type.getUnderlying());1897});1898converter.addConversion([&](cir::FP16Type type) -> mlir::Type {1899return mlir::Float16Type::get(type.getContext());1900});1901converter.addConversion([&](cir::BF16Type type) -> mlir::Type {1902return mlir::BFloat16Type::get(type.getContext());1903});1904converter.addConversion([&](cir::ComplexType type) -> mlir::Type {1905// A complex type is lowered to an LLVM struct that contains the real and1906// imaginary part as data fields.1907mlir::Type elementTy = converter.convertType(type.getElementType());1908mlir::Type structFields[2] = {elementTy, elementTy};1909return mlir::LLVM::LLVMStructType::getLiteral(type.getContext(),1910structFields);1911});1912converter.addConversion([&](cir::FuncType type) -> std::optional<mlir::Type> {1913auto result = converter.convertType(type.getReturnType());1914llvm::SmallVector<mlir::Type> arguments;1915arguments.reserve(type.getNumInputs());1916if (converter.convertTypes(type.getInputs(), arguments).failed())1917return std::nullopt;1918auto varArg = type.isVarArg();1919return mlir::LLVM::LLVMFunctionType::get(result, arguments, varArg);1920});1921converter.addConversion([&](cir::RecordType type) -> mlir::Type {1922// Convert struct members.1923llvm::SmallVector<mlir::Type> llvmMembers;1924switch (type.getKind()) {1925case cir::RecordType::Class:1926case cir::RecordType::Struct:1927for (mlir::Type ty : type.getMembers())1928llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));1929break;1930// Unions are lowered as only the largest member.1931case cir::RecordType::Union:1932if (auto largestMember = type.getLargestMember(dataLayout))1933llvmMembers.push_back(1934convertTypeForMemory(converter, dataLayout, largestMember));1935if (type.getPadded()) {1936auto last = *type.getMembers().rbegin();1937llvmMembers.push_back(1938convertTypeForMemory(converter, dataLayout, last));1939}1940break;1941}19421943// Record has a name: lower as an identified record.1944mlir::LLVM::LLVMStructType llvmStruct;1945if (type.getName()) {1946llvmStruct = mlir::LLVM::LLVMStructType::getIdentified(1947type.getContext(), type.getPrefixedName());1948if (llvmStruct.setBody(llvmMembers, type.getPacked()).failed())1949llvm_unreachable("Failed to set body of record");1950} else { // Record has no name: lower as literal record.1951llvmStruct = mlir::LLVM::LLVMStructType::getLiteral(1952type.getContext(), llvmMembers, type.getPacked());1953}19541955return llvmStruct;1956});1957}19581959// The applyPartialConversion function traverses blocks in the dominance order,1960// so it does not lower and operations that are not reachachable from the1961// operations passed in as arguments. Since we do need to lower such code in1962// order to avoid verification errors occur, we cannot just pass the module op1963// to applyPartialConversion. We must build a set of unreachable ops and1964// explicitly add them, along with the module, to the vector we pass to1965// applyPartialConversion.1966//1967// For instance, this CIR code:1968//1969// cir.func @foo(%arg0: !s32i) -> !s32i {1970// %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool1971// cir.if %4 {1972// %5 = cir.const #cir.int<1> : !s32i1973// cir.return %5 : !s32i1974// } else {1975// %5 = cir.const #cir.int<0> : !s32i1976// cir.return %5 : !s32i1977// }1978// cir.return %arg0 : !s32i1979// }1980//1981// contains an unreachable return operation (the last one). After the flattening1982// pass it will be placed into the unreachable block. The possible error1983// after the lowering pass is: error: 'cir.return' op expects parent op to be1984// one of 'cir.func, cir.scope, cir.if ... The reason that this operation was1985// not lowered and the new parent is llvm.func.1986//1987// In the future we may want to get rid of this function and use a DCE pass or1988// something similar. But for now we need to guarantee the absence of the1989// dialect verification errors.1990static void collectUnreachable(mlir::Operation *parent,1991llvm::SmallVector<mlir::Operation *> &ops) {19921993llvm::SmallVector<mlir::Block *> unreachableBlocks;1994parent->walk([&](mlir::Block *blk) { // check1995if (blk->hasNoPredecessors() && !blk->isEntryBlock())1996unreachableBlocks.push_back(blk);1997});19981999std::set<mlir::Block *> visited;2000for (mlir::Block *root : unreachableBlocks) {2001// We create a work list for each unreachable block.2002// Thus we traverse operations in some order.2003std::deque<mlir::Block *> workList;2004workList.push_back(root);20052006while (!workList.empty()) {2007mlir::Block *blk = workList.back();2008workList.pop_back();2009if (visited.count(blk))2010continue;2011visited.emplace(blk);20122013for (mlir::Operation &op : *blk)2014ops.push_back(&op);20152016for (mlir::Block *succ : blk->getSuccessors())2017workList.push_back(succ);2018}2019}2020}20212022void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {2023// Lower the module attributes to LLVM equivalents.2024if (mlir::Attribute tripleAttr =2025module->getAttr(cir::CIRDialect::getTripleAttrName()))2026module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),2027tripleAttr);2028}20292030void ConvertCIRToLLVMPass::runOnOperation() {2031llvm::TimeTraceScope scope("Convert CIR to LLVM Pass");20322033mlir::ModuleOp module = getOperation();2034mlir::DataLayout dl(module);2035mlir::LLVMTypeConverter converter(&getContext());2036prepareTypeConverter(converter, dl);20372038mlir::RewritePatternSet patterns(&getContext());20392040patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());2041// This could currently be merged with the group below, but it will get more2042// arguments later, so we'll keep it separate for now.2043patterns.add<CIRToLLVMAllocaOpLowering>(converter, patterns.getContext(), dl);2044patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);2045patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);2046patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);2047patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);2048patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),2049dl);2050patterns.add<2051// clang-format off2052CIRToLLVMAssumeOpLowering,2053CIRToLLVMBaseClassAddrOpLowering,2054CIRToLLVMBinOpLowering,2055CIRToLLVMBitClrsbOpLowering,2056CIRToLLVMBitClzOpLowering,2057CIRToLLVMBitCtzOpLowering,2058CIRToLLVMBitParityOpLowering,2059CIRToLLVMBitPopcountOpLowering,2060CIRToLLVMBitReverseOpLowering,2061CIRToLLVMBrCondOpLowering,2062CIRToLLVMBrOpLowering,2063CIRToLLVMByteSwapOpLowering,2064CIRToLLVMCallOpLowering,2065CIRToLLVMCmpOpLowering,2066CIRToLLVMComplexAddOpLowering,2067CIRToLLVMComplexCreateOpLowering,2068CIRToLLVMComplexImagOpLowering,2069CIRToLLVMComplexImagPtrOpLowering,2070CIRToLLVMComplexRealOpLowering,2071CIRToLLVMComplexRealPtrOpLowering,2072CIRToLLVMComplexSubOpLowering,2073CIRToLLVMConstantOpLowering,2074CIRToLLVMExpectOpLowering,2075CIRToLLVMFuncOpLowering,2076CIRToLLVMGetBitfieldOpLowering,2077CIRToLLVMGetGlobalOpLowering,2078CIRToLLVMGetMemberOpLowering,2079CIRToLLVMSelectOpLowering,2080CIRToLLVMSetBitfieldOpLowering,2081CIRToLLVMShiftOpLowering,2082CIRToLLVMStackRestoreOpLowering,2083CIRToLLVMStackSaveOpLowering,2084CIRToLLVMSwitchFlatOpLowering,2085CIRToLLVMTrapOpLowering,2086CIRToLLVMUnaryOpLowering,2087CIRToLLVMVecCmpOpLowering,2088CIRToLLVMVecCreateOpLowering,2089CIRToLLVMVecExtractOpLowering,2090CIRToLLVMVecInsertOpLowering,2091CIRToLLVMVecShuffleDynamicOpLowering,2092CIRToLLVMVecShuffleOpLowering,2093CIRToLLVMVecSplatOpLowering,2094CIRToLLVMVecTernaryOpLowering2095// clang-format on2096>(converter, patterns.getContext());20972098processCIRAttrs(module);20992100mlir::ConversionTarget target(getContext());2101target.addLegalOp<mlir::ModuleOp>();2102target.addLegalDialect<mlir::LLVM::LLVMDialect>();2103target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect,2104mlir::func::FuncDialect>();21052106llvm::SmallVector<mlir::Operation *> ops;2107ops.push_back(module);2108collectUnreachable(module, ops);21092110if (failed(applyPartialConversion(ops, target, std::move(patterns))))2111signalPassFailure();2112}21132114mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite(2115cir::BrOp op, OpAdaptor adaptor,2116mlir::ConversionPatternRewriter &rewriter) const {2117rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(op, adaptor.getOperands(),2118op.getDest());2119return mlir::LogicalResult::success();2120}21212122mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(2123cir::GetMemberOp op, OpAdaptor adaptor,2124mlir::ConversionPatternRewriter &rewriter) const {2125mlir::Type llResTy = getTypeConverter()->convertType(op.getType());2126const auto recordTy =2127mlir::cast<cir::RecordType>(op.getAddrTy().getPointee());2128assert(recordTy && "expected record type");21292130switch (recordTy.getKind()) {2131case cir::RecordType::Class:2132case cir::RecordType::Struct: {2133// Since the base address is a pointer to an aggregate, the first offset2134// is always zero. The second offset tell us which member it will access.2135llvm::SmallVector<mlir::LLVM::GEPArg, 2> offset{0, op.getIndex()};2136const mlir::Type elementTy = getTypeConverter()->convertType(recordTy);2137rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, llResTy, elementTy,2138adaptor.getAddr(), offset);2139return mlir::success();2140}2141case cir::RecordType::Union:2142// Union members share the address space, so we just need a bitcast to2143// conform to type-checking.2144rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(op, llResTy,2145adaptor.getAddr());2146return mlir::success();2147}2148}21492150mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(2151cir::TrapOp op, OpAdaptor adaptor,2152mlir::ConversionPatternRewriter &rewriter) const {2153mlir::Location loc = op->getLoc();2154rewriter.eraseOp(op);21552156rewriter.create<mlir::LLVM::Trap>(loc);21572158// Note that the call to llvm.trap is not a terminator in LLVM dialect.2159// So we must emit an additional llvm.unreachable to terminate the current2160// block.2161rewriter.create<mlir::LLVM::UnreachableOp>(loc);21622163return mlir::success();2164}21652166mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite(2167cir::StackSaveOp op, OpAdaptor adaptor,2168mlir::ConversionPatternRewriter &rewriter) const {2169const mlir::Type ptrTy = getTypeConverter()->convertType(op.getType());2170rewriter.replaceOpWithNewOp<mlir::LLVM::StackSaveOp>(op, ptrTy);2171return mlir::success();2172}21732174mlir::LogicalResult CIRToLLVMStackRestoreOpLowering::matchAndRewrite(2175cir::StackRestoreOp op, OpAdaptor adaptor,2176mlir::ConversionPatternRewriter &rewriter) const {2177rewriter.replaceOpWithNewOp<mlir::LLVM::StackRestoreOp>(op, adaptor.getPtr());2178return mlir::success();2179}21802181mlir::LogicalResult CIRToLLVMVecCreateOpLowering::matchAndRewrite(2182cir::VecCreateOp op, OpAdaptor adaptor,2183mlir::ConversionPatternRewriter &rewriter) const {2184// Start with an 'undef' value for the vector. Then 'insertelement' for2185// each of the vector elements.2186const auto vecTy = mlir::cast<cir::VectorType>(op.getType());2187const mlir::Type llvmTy = typeConverter->convertType(vecTy);2188const mlir::Location loc = op.getLoc();2189mlir::Value result = rewriter.create<mlir::LLVM::PoisonOp>(loc, llvmTy);2190assert(vecTy.getSize() == op.getElements().size() &&2191"cir.vec.create op count doesn't match vector type elements count");21922193for (uint64_t i = 0; i < vecTy.getSize(); ++i) {2194const mlir::Value indexValue =2195rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);2196result = rewriter.create<mlir::LLVM::InsertElementOp>(2197loc, result, adaptor.getElements()[i], indexValue);2198}21992200rewriter.replaceOp(op, result);2201return mlir::success();2202}22032204mlir::LogicalResult CIRToLLVMVecExtractOpLowering::matchAndRewrite(2205cir::VecExtractOp op, OpAdaptor adaptor,2206mlir::ConversionPatternRewriter &rewriter) const {2207rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractElementOp>(2208op, adaptor.getVec(), adaptor.getIndex());2209return mlir::success();2210}22112212mlir::LogicalResult CIRToLLVMVecInsertOpLowering::matchAndRewrite(2213cir::VecInsertOp op, OpAdaptor adaptor,2214mlir::ConversionPatternRewriter &rewriter) const {2215rewriter.replaceOpWithNewOp<mlir::LLVM::InsertElementOp>(2216op, adaptor.getVec(), adaptor.getValue(), adaptor.getIndex());2217return mlir::success();2218}22192220mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(2221cir::VecCmpOp op, OpAdaptor adaptor,2222mlir::ConversionPatternRewriter &rewriter) const {2223mlir::Type elementType = elementTypeIfVector(op.getLhs().getType());2224mlir::Value bitResult;2225if (auto intType = mlir::dyn_cast<cir::IntType>(elementType)) {2226bitResult = rewriter.create<mlir::LLVM::ICmpOp>(2227op.getLoc(),2228convertCmpKindToICmpPredicate(op.getKind(), intType.isSigned()),2229adaptor.getLhs(), adaptor.getRhs());2230} else if (mlir::isa<cir::FPTypeInterface>(elementType)) {2231bitResult = rewriter.create<mlir::LLVM::FCmpOp>(2232op.getLoc(), convertCmpKindToFCmpPredicate(op.getKind()),2233adaptor.getLhs(), adaptor.getRhs());2234} else {2235return op.emitError() << "unsupported type for VecCmpOp: " << elementType;2236}22372238// LLVM IR vector comparison returns a vector of i1. This one-bit vector2239// must be sign-extended to the correct result type.2240rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(2241op, typeConverter->convertType(op.getType()), bitResult);2242return mlir::success();2243}22442245mlir::LogicalResult CIRToLLVMVecSplatOpLowering::matchAndRewrite(2246cir::VecSplatOp op, OpAdaptor adaptor,2247mlir::ConversionPatternRewriter &rewriter) const {2248// Vector splat can be implemented with an `insertelement` and a2249// `shufflevector`, which is better than an `insertelement` for each2250// element in the vector. Start with an undef vector. Insert the value into2251// the first element. Then use a `shufflevector` with a mask of all 0 to2252// fill out the entire vector with that value.2253cir::VectorType vecTy = op.getType();2254mlir::Type llvmTy = typeConverter->convertType(vecTy);2255mlir::Location loc = op.getLoc();2256mlir::Value poison = rewriter.create<mlir::LLVM::PoisonOp>(loc, llvmTy);22572258mlir::Value elementValue = adaptor.getValue();2259if (mlir::isa<mlir::LLVM::PoisonOp>(elementValue.getDefiningOp())) {2260// If the splat value is poison, then we can just use poison value2261// for the entire vector.2262rewriter.replaceOp(op, poison);2263return mlir::success();2264}22652266if (auto constValue =2267dyn_cast<mlir::LLVM::ConstantOp>(elementValue.getDefiningOp())) {2268if (auto intAttr = dyn_cast<mlir::IntegerAttr>(constValue.getValue())) {2269mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get(2270mlir::cast<mlir::ShapedType>(llvmTy), intAttr.getValue());2271rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(2272op, denseVec.getType(), denseVec);2273return mlir::success();2274}22752276if (auto fpAttr = dyn_cast<mlir::FloatAttr>(constValue.getValue())) {2277mlir::DenseFPElementsAttr denseVec = mlir::DenseFPElementsAttr::get(2278mlir::cast<mlir::ShapedType>(llvmTy), fpAttr.getValue());2279rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(2280op, denseVec.getType(), denseVec);2281return mlir::success();2282}2283}22842285mlir::Value indexValue =2286rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), 0);2287mlir::Value oneElement = rewriter.create<mlir::LLVM::InsertElementOp>(2288loc, poison, elementValue, indexValue);2289SmallVector<int32_t> zeroValues(vecTy.getSize(), 0);2290rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(op, oneElement,2291poison, zeroValues);2292return mlir::success();2293}22942295mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite(2296cir::VecShuffleOp op, OpAdaptor adaptor,2297mlir::ConversionPatternRewriter &rewriter) const {2298// LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices.2299// Convert the ClangIR ArrayAttr of IntAttr constants into a2300// SmallVector<int>.2301SmallVector<int, 8> indices;2302std::transform(2303op.getIndices().begin(), op.getIndices().end(),2304std::back_inserter(indices), [](mlir::Attribute intAttr) {2305return mlir::cast<cir::IntAttr>(intAttr).getValue().getSExtValue();2306});2307rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(2308op, adaptor.getVec1(), adaptor.getVec2(), indices);2309return mlir::success();2310}23112312mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite(2313cir::VecShuffleDynamicOp op, OpAdaptor adaptor,2314mlir::ConversionPatternRewriter &rewriter) const {2315// LLVM IR does not have an operation that corresponds to this form of2316// the built-in.2317// __builtin_shufflevector(V, I)2318// is implemented as this pseudocode, where the for loop is unrolled2319// and N is the number of elements:2320//2321// result = undef2322// maskbits = NextPowerOf2(N - 1)2323// masked = I & maskbits2324// for (i in 0 <= i < N)2325// result[i] = V[masked[i]]2326mlir::Location loc = op.getLoc();2327mlir::Value input = adaptor.getVec();2328mlir::Type llvmIndexVecType =2329getTypeConverter()->convertType(op.getIndices().getType());2330mlir::Type llvmIndexType = getTypeConverter()->convertType(2331elementTypeIfVector(op.getIndices().getType()));2332uint64_t numElements =2333mlir::cast<cir::VectorType>(op.getVec().getType()).getSize();23342335uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1;2336mlir::Value maskValue = rewriter.create<mlir::LLVM::ConstantOp>(2337loc, llvmIndexType, rewriter.getIntegerAttr(llvmIndexType, maskBits));2338mlir::Value maskVector =2339rewriter.create<mlir::LLVM::UndefOp>(loc, llvmIndexVecType);23402341for (uint64_t i = 0; i < numElements; ++i) {2342mlir::Value idxValue =2343rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);2344maskVector = rewriter.create<mlir::LLVM::InsertElementOp>(2345loc, maskVector, maskValue, idxValue);2346}23472348mlir::Value maskedIndices = rewriter.create<mlir::LLVM::AndOp>(2349loc, llvmIndexVecType, adaptor.getIndices(), maskVector);2350mlir::Value result = rewriter.create<mlir::LLVM::UndefOp>(2351loc, getTypeConverter()->convertType(op.getVec().getType()));2352for (uint64_t i = 0; i < numElements; ++i) {2353mlir::Value iValue =2354rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);2355mlir::Value indexValue = rewriter.create<mlir::LLVM::ExtractElementOp>(2356loc, maskedIndices, iValue);2357mlir::Value valueAtIndex =2358rewriter.create<mlir::LLVM::ExtractElementOp>(loc, input, indexValue);2359result = rewriter.create<mlir::LLVM::InsertElementOp>(loc, result,2360valueAtIndex, iValue);2361}2362rewriter.replaceOp(op, result);2363return mlir::success();2364}23652366mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite(2367cir::VecTernaryOp op, OpAdaptor adaptor,2368mlir::ConversionPatternRewriter &rewriter) const {2369// Convert `cond` into a vector of i1, then use that in a `select` op.2370mlir::Value bitVec = rewriter.create<mlir::LLVM::ICmpOp>(2371op.getLoc(), mlir::LLVM::ICmpPredicate::ne, adaptor.getCond(),2372rewriter.create<mlir::LLVM::ZeroOp>(2373op.getCond().getLoc(),2374typeConverter->convertType(op.getCond().getType())));2375rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(2376op, bitVec, adaptor.getLhs(), adaptor.getRhs());2377return mlir::success();2378}23792380mlir::LogicalResult CIRToLLVMComplexAddOpLowering::matchAndRewrite(2381cir::ComplexAddOp op, OpAdaptor adaptor,2382mlir::ConversionPatternRewriter &rewriter) const {2383mlir::Value lhs = adaptor.getLhs();2384mlir::Value rhs = adaptor.getRhs();2385mlir::Location loc = op.getLoc();23862387auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());2388mlir::Type complexElemTy =2389getTypeConverter()->convertType(complexType.getElementType());2390auto lhsReal =2391rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);2392auto lhsImag =2393rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);2394auto rhsReal =2395rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);2396auto rhsImag =2397rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);23982399mlir::Value newReal;2400mlir::Value newImag;2401if (complexElemTy.isInteger()) {2402newReal = rewriter.create<mlir::LLVM::AddOp>(loc, complexElemTy, lhsReal,2403rhsReal);2404newImag = rewriter.create<mlir::LLVM::AddOp>(loc, complexElemTy, lhsImag,2405rhsImag);2406} else {2407assert(!cir::MissingFeatures::fastMathFlags());2408assert(!cir::MissingFeatures::fpConstraints());2409newReal = rewriter.create<mlir::LLVM::FAddOp>(loc, complexElemTy, lhsReal,2410rhsReal);2411newImag = rewriter.create<mlir::LLVM::FAddOp>(loc, complexElemTy, lhsImag,2412rhsImag);2413}24142415mlir::Type complexLLVMTy =2416getTypeConverter()->convertType(op.getResult().getType());2417auto initialComplex =2418rewriter.create<mlir::LLVM::PoisonOp>(op->getLoc(), complexLLVMTy);24192420auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(2421op->getLoc(), initialComplex, newReal, 0);24222423rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(op, realComplex,2424newImag, 1);24252426return mlir::success();2427}24282429mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite(2430cir::ComplexCreateOp op, OpAdaptor adaptor,2431mlir::ConversionPatternRewriter &rewriter) const {2432mlir::Type complexLLVMTy =2433getTypeConverter()->convertType(op.getResult().getType());2434auto initialComplex =2435rewriter.create<mlir::LLVM::UndefOp>(op->getLoc(), complexLLVMTy);24362437auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(2438op->getLoc(), initialComplex, adaptor.getReal(), 0);24392440auto complex = rewriter.create<mlir::LLVM::InsertValueOp>(2441op->getLoc(), realComplex, adaptor.getImag(), 1);24422443rewriter.replaceOp(op, complex);2444return mlir::success();2445}24462447mlir::LogicalResult CIRToLLVMComplexRealOpLowering::matchAndRewrite(2448cir::ComplexRealOp op, OpAdaptor adaptor,2449mlir::ConversionPatternRewriter &rewriter) const {2450mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());2451rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(2452op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{0});2453return mlir::success();2454}24552456mlir::LogicalResult CIRToLLVMComplexSubOpLowering::matchAndRewrite(2457cir::ComplexSubOp op, OpAdaptor adaptor,2458mlir::ConversionPatternRewriter &rewriter) const {2459mlir::Value lhs = adaptor.getLhs();2460mlir::Value rhs = adaptor.getRhs();2461mlir::Location loc = op.getLoc();24622463auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());2464mlir::Type complexElemTy =2465getTypeConverter()->convertType(complexType.getElementType());2466auto lhsReal =2467rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);2468auto lhsImag =2469rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);2470auto rhsReal =2471rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);2472auto rhsImag =2473rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);24742475mlir::Value newReal;2476mlir::Value newImag;2477if (complexElemTy.isInteger()) {2478newReal = rewriter.create<mlir::LLVM::SubOp>(loc, complexElemTy, lhsReal,2479rhsReal);2480newImag = rewriter.create<mlir::LLVM::SubOp>(loc, complexElemTy, lhsImag,2481rhsImag);2482} else {2483assert(!cir::MissingFeatures::fastMathFlags());2484assert(!cir::MissingFeatures::fpConstraints());2485newReal = rewriter.create<mlir::LLVM::FSubOp>(loc, complexElemTy, lhsReal,2486rhsReal);2487newImag = rewriter.create<mlir::LLVM::FSubOp>(loc, complexElemTy, lhsImag,2488rhsImag);2489}24902491mlir::Type complexLLVMTy =2492getTypeConverter()->convertType(op.getResult().getType());2493auto initialComplex =2494rewriter.create<mlir::LLVM::PoisonOp>(op->getLoc(), complexLLVMTy);24952496auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(2497op->getLoc(), initialComplex, newReal, 0);24982499rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(op, realComplex,2500newImag, 1);25012502return mlir::success();2503}25042505mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(2506cir::ComplexImagOp op, OpAdaptor adaptor,2507mlir::ConversionPatternRewriter &rewriter) const {2508mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());2509rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(2510op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{1});2511return mlir::success();2512}25132514mlir::IntegerType computeBitfieldIntType(mlir::Type storageType,2515mlir::MLIRContext *context,2516unsigned &storageSize) {2517return TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)2518.Case<cir::ArrayType>([&](cir::ArrayType atTy) {2519storageSize = atTy.getSize() * 8;2520return mlir::IntegerType::get(context, storageSize);2521})2522.Case<cir::IntType>([&](cir::IntType intTy) {2523storageSize = intTy.getWidth();2524return mlir::IntegerType::get(context, storageSize);2525})2526.Default([](mlir::Type) -> mlir::IntegerType {2527llvm_unreachable(2528"Either ArrayType or IntType expected for bitfields storage");2529});2530}25312532mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite(2533cir::SetBitfieldOp op, OpAdaptor adaptor,2534mlir::ConversionPatternRewriter &rewriter) const {2535mlir::OpBuilder::InsertionGuard guard(rewriter);2536rewriter.setInsertionPoint(op);25372538cir::BitfieldInfoAttr info = op.getBitfieldInfo();2539uint64_t size = info.getSize();2540uint64_t offset = info.getOffset();2541mlir::Type storageType = info.getStorageType();2542mlir::MLIRContext *context = storageType.getContext();25432544unsigned storageSize = 0;25452546mlir::IntegerType intType =2547computeBitfieldIntType(storageType, context, storageSize);25482549mlir::Value srcVal = createIntCast(rewriter, adaptor.getSrc(), intType);2550unsigned srcWidth = storageSize;2551mlir::Value resultVal = srcVal;25522553if (storageSize != size) {2554assert(storageSize > size && "Invalid bitfield size.");25552556mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(2557op.getLoc(), intType, adaptor.getAddr(), /* alignment */ 0,2558op.getIsVolatile());25592560srcVal =2561createAnd(rewriter, srcVal, llvm::APInt::getLowBitsSet(srcWidth, size));2562resultVal = srcVal;2563srcVal = createShL(rewriter, srcVal, offset);25642565// Mask out the original value.2566val = createAnd(rewriter, val,2567~llvm::APInt::getBitsSet(srcWidth, offset, offset + size));25682569// Or together the unchanged values and the source value.2570srcVal = rewriter.create<mlir::LLVM::OrOp>(op.getLoc(), val, srcVal);2571}25722573rewriter.create<mlir::LLVM::StoreOp>(op.getLoc(), srcVal, adaptor.getAddr(),2574/* alignment */ 0, op.getIsVolatile());25752576mlir::Type resultTy = getTypeConverter()->convertType(op.getType());25772578if (info.getIsSigned()) {2579assert(size <= storageSize);2580unsigned highBits = storageSize - size;25812582if (highBits) {2583resultVal = createShL(rewriter, resultVal, highBits);2584resultVal = createAShR(rewriter, resultVal, highBits);2585}2586}25872588resultVal = createIntCast(rewriter, resultVal,2589mlir::cast<mlir::IntegerType>(resultTy),2590info.getIsSigned());25912592rewriter.replaceOp(op, resultVal);2593return mlir::success();2594}25952596mlir::LogicalResult CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite(2597cir::ComplexImagPtrOp op, OpAdaptor adaptor,2598mlir::ConversionPatternRewriter &rewriter) const {2599cir::PointerType operandTy = op.getOperand().getType();2600mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());2601mlir::Type elementLLVMTy =2602getTypeConverter()->convertType(operandTy.getPointee());26032604mlir::LLVM::GEPArg gepIndices[2] = {{0}, {1}};2605mlir::LLVM::GEPNoWrapFlags inboundsNuw =2606mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;2607rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(2608op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,2609inboundsNuw);2610return mlir::success();2611}26122613mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite(2614cir::ComplexRealPtrOp op, OpAdaptor adaptor,2615mlir::ConversionPatternRewriter &rewriter) const {2616cir::PointerType operandTy = op.getOperand().getType();2617mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());2618mlir::Type elementLLVMTy =2619getTypeConverter()->convertType(operandTy.getPointee());26202621mlir::LLVM::GEPArg gepIndices[2] = {0, 0};2622mlir::LLVM::GEPNoWrapFlags inboundsNuw =2623mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;2624rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(2625op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,2626inboundsNuw);2627return mlir::success();2628}26292630mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(2631cir::GetBitfieldOp op, OpAdaptor adaptor,2632mlir::ConversionPatternRewriter &rewriter) const {26332634mlir::OpBuilder::InsertionGuard guard(rewriter);2635rewriter.setInsertionPoint(op);26362637cir::BitfieldInfoAttr info = op.getBitfieldInfo();2638uint64_t size = info.getSize();2639uint64_t offset = info.getOffset();2640mlir::Type storageType = info.getStorageType();2641mlir::MLIRContext *context = storageType.getContext();2642unsigned storageSize = 0;26432644mlir::IntegerType intType =2645computeBitfieldIntType(storageType, context, storageSize);26462647mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(2648op.getLoc(), intType, adaptor.getAddr(), 0, op.getIsVolatile());2649val = rewriter.create<mlir::LLVM::BitcastOp>(op.getLoc(), intType, val);26502651if (info.getIsSigned()) {2652assert(static_cast<unsigned>(offset + size) <= storageSize);2653unsigned highBits = storageSize - offset - size;2654val = createShL(rewriter, val, highBits);2655val = createAShR(rewriter, val, offset + highBits);2656} else {2657val = createLShR(rewriter, val, offset);26582659if (static_cast<unsigned>(offset) + size < storageSize)2660val = createAnd(rewriter, val,2661llvm::APInt::getLowBitsSet(storageSize, size));2662}26632664mlir::Type resTy = getTypeConverter()->convertType(op.getType());2665mlir::Value newOp = createIntCast(2666rewriter, val, mlir::cast<mlir::IntegerType>(resTy), info.getIsSigned());2667rewriter.replaceOp(op, newOp);2668return mlir::success();2669}26702671std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {2672return std::make_unique<ConvertCIRToLLVMPass>();2673}26742675void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {2676mlir::populateCIRPreLoweringPasses(pm);2677pm.addPass(createConvertCIRToLLVMPass());2678}26792680std::unique_ptr<llvm::Module>2681lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) {2682llvm::TimeTraceScope scope("lower from CIR to LLVM directly");26832684mlir::MLIRContext *mlirCtx = mlirModule.getContext();26852686mlir::PassManager pm(mlirCtx);2687populateCIRToLLVMPasses(pm);26882689(void)mlir::applyPassManagerCLOptions(pm);26902691if (mlir::failed(pm.run(mlirModule))) {2692// FIXME: Handle any errors where they occurs and return a nullptr here.2693report_fatal_error(2694"The pass manager failed to lower CIR to LLVMIR dialect!");2695}26962697mlir::registerBuiltinDialectTranslation(*mlirCtx);2698mlir::registerLLVMDialectTranslation(*mlirCtx);2699mlir::registerCIRDialectTranslation(*mlirCtx);27002701llvm::TimeTraceScope translateScope("translateModuleToLLVMIR");27022703StringRef moduleName = mlirModule.getName().value_or("CIRToLLVMModule");2704std::unique_ptr<llvm::Module> llvmModule =2705mlir::translateModuleToLLVMIR(mlirModule, llvmCtx, moduleName);27062707if (!llvmModule) {2708// FIXME: Handle any errors where they occurs and return a nullptr here.2709report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!");2710}27112712return llvmModule;2713}2714} // namespace direct2715} // namespace cir271627172718