xref: /freebsd/contrib/llvm-project/clang/lib/CIR/Lowering/DirectToLLVM/LowerToLLVM.cpp (revision 700637cbb5e582861067a11aaca4d053546871d2)
1*700637cbSDimitry Andric //====- LowerToLLVM.cpp - Lowering from CIR to LLVMIR ---------------------===//
2*700637cbSDimitry Andric //
3*700637cbSDimitry Andric // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4*700637cbSDimitry Andric // See https://llvm.org/LICENSE.txt for license information.
5*700637cbSDimitry Andric // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6*700637cbSDimitry Andric //
7*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
8*700637cbSDimitry Andric //
9*700637cbSDimitry Andric // This file implements lowering of CIR operations to LLVMIR.
10*700637cbSDimitry Andric //
11*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
12*700637cbSDimitry Andric 
13*700637cbSDimitry Andric #include "LowerToLLVM.h"
14*700637cbSDimitry Andric 
15*700637cbSDimitry Andric #include <deque>
16*700637cbSDimitry Andric #include <optional>
17*700637cbSDimitry Andric 
18*700637cbSDimitry Andric #include "mlir/Conversion/LLVMCommon/TypeConverter.h"
19*700637cbSDimitry Andric #include "mlir/Dialect/DLTI/DLTI.h"
20*700637cbSDimitry Andric #include "mlir/Dialect/Func/IR/FuncOps.h"
21*700637cbSDimitry Andric #include "mlir/Dialect/LLVMIR/LLVMDialect.h"
22*700637cbSDimitry Andric #include "mlir/Dialect/LLVMIR/LLVMTypes.h"
23*700637cbSDimitry Andric #include "mlir/IR/BuiltinAttributes.h"
24*700637cbSDimitry Andric #include "mlir/IR/BuiltinDialect.h"
25*700637cbSDimitry Andric #include "mlir/IR/BuiltinOps.h"
26*700637cbSDimitry Andric #include "mlir/IR/Types.h"
27*700637cbSDimitry Andric #include "mlir/Pass/Pass.h"
28*700637cbSDimitry Andric #include "mlir/Pass/PassManager.h"
29*700637cbSDimitry Andric #include "mlir/Target/LLVMIR/Dialect/Builtin/BuiltinToLLVMIRTranslation.h"
30*700637cbSDimitry Andric #include "mlir/Target/LLVMIR/Dialect/LLVMIR/LLVMToLLVMIRTranslation.h"
31*700637cbSDimitry Andric #include "mlir/Target/LLVMIR/Export.h"
32*700637cbSDimitry Andric #include "mlir/Transforms/DialectConversion.h"
33*700637cbSDimitry Andric #include "clang/CIR/Dialect/IR/CIRAttrs.h"
34*700637cbSDimitry Andric #include "clang/CIR/Dialect/IR/CIRDialect.h"
35*700637cbSDimitry Andric #include "clang/CIR/Dialect/Passes.h"
36*700637cbSDimitry Andric #include "clang/CIR/LoweringHelpers.h"
37*700637cbSDimitry Andric #include "clang/CIR/MissingFeatures.h"
38*700637cbSDimitry Andric #include "clang/CIR/Passes.h"
39*700637cbSDimitry Andric #include "llvm/ADT/TypeSwitch.h"
40*700637cbSDimitry Andric #include "llvm/IR/Module.h"
41*700637cbSDimitry Andric #include "llvm/Support/ErrorHandling.h"
42*700637cbSDimitry Andric #include "llvm/Support/TimeProfiler.h"
43*700637cbSDimitry Andric 
44*700637cbSDimitry Andric using namespace cir;
45*700637cbSDimitry Andric using namespace llvm;
46*700637cbSDimitry Andric 
47*700637cbSDimitry Andric namespace cir {
48*700637cbSDimitry Andric namespace direct {
49*700637cbSDimitry Andric 
50*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
51*700637cbSDimitry Andric // Helper Methods
52*700637cbSDimitry Andric //===----------------------------------------------------------------------===//
53*700637cbSDimitry Andric 
54*700637cbSDimitry Andric namespace {
55*700637cbSDimitry Andric /// If the given type is a vector type, return the vector's element type.
56*700637cbSDimitry Andric /// Otherwise return the given type unchanged.
elementTypeIfVector(mlir::Type type)57*700637cbSDimitry Andric mlir::Type elementTypeIfVector(mlir::Type type) {
58*700637cbSDimitry Andric   return llvm::TypeSwitch<mlir::Type, mlir::Type>(type)
59*700637cbSDimitry Andric       .Case<cir::VectorType, mlir::VectorType>(
60*700637cbSDimitry Andric           [](auto p) { return p.getElementType(); })
61*700637cbSDimitry Andric       .Default([](mlir::Type p) { return p; });
62*700637cbSDimitry Andric }
63*700637cbSDimitry Andric } // namespace
64*700637cbSDimitry Andric 
65*700637cbSDimitry Andric /// Given a type convertor and a data layout, convert the given type to a type
66*700637cbSDimitry Andric /// that is suitable for memory operations. For example, this can be used to
67*700637cbSDimitry Andric /// lower cir.bool accesses to i8.
convertTypeForMemory(const mlir::TypeConverter & converter,mlir::DataLayout const & dataLayout,mlir::Type type)68*700637cbSDimitry Andric static mlir::Type convertTypeForMemory(const mlir::TypeConverter &converter,
69*700637cbSDimitry Andric                                        mlir::DataLayout const &dataLayout,
70*700637cbSDimitry Andric                                        mlir::Type type) {
71*700637cbSDimitry Andric   // TODO(cir): Handle other types similarly to clang's codegen
72*700637cbSDimitry Andric   // convertTypeForMemory
73*700637cbSDimitry Andric   if (isa<cir::BoolType>(type)) {
74*700637cbSDimitry Andric     return mlir::IntegerType::get(type.getContext(),
75*700637cbSDimitry Andric                                   dataLayout.getTypeSizeInBits(type));
76*700637cbSDimitry Andric   }
77*700637cbSDimitry Andric 
78*700637cbSDimitry Andric   return converter.convertType(type);
79*700637cbSDimitry Andric }
80*700637cbSDimitry Andric 
createIntCast(mlir::OpBuilder & bld,mlir::Value src,mlir::IntegerType dstTy,bool isSigned=false)81*700637cbSDimitry Andric static mlir::Value createIntCast(mlir::OpBuilder &bld, mlir::Value src,
82*700637cbSDimitry Andric                                  mlir::IntegerType dstTy,
83*700637cbSDimitry Andric                                  bool isSigned = false) {
84*700637cbSDimitry Andric   mlir::Type srcTy = src.getType();
85*700637cbSDimitry Andric   assert(mlir::isa<mlir::IntegerType>(srcTy));
86*700637cbSDimitry Andric 
87*700637cbSDimitry Andric   unsigned srcWidth = mlir::cast<mlir::IntegerType>(srcTy).getWidth();
88*700637cbSDimitry Andric   unsigned dstWidth = mlir::cast<mlir::IntegerType>(dstTy).getWidth();
89*700637cbSDimitry Andric   mlir::Location loc = src.getLoc();
90*700637cbSDimitry Andric 
91*700637cbSDimitry Andric   if (dstWidth > srcWidth && isSigned)
92*700637cbSDimitry Andric     return bld.create<mlir::LLVM::SExtOp>(loc, dstTy, src);
93*700637cbSDimitry Andric   if (dstWidth > srcWidth)
94*700637cbSDimitry Andric     return bld.create<mlir::LLVM::ZExtOp>(loc, dstTy, src);
95*700637cbSDimitry Andric   if (dstWidth < srcWidth)
96*700637cbSDimitry Andric     return bld.create<mlir::LLVM::TruncOp>(loc, dstTy, src);
97*700637cbSDimitry Andric   return bld.create<mlir::LLVM::BitcastOp>(loc, dstTy, src);
98*700637cbSDimitry Andric }
99*700637cbSDimitry Andric 
100*700637cbSDimitry Andric static mlir::LLVM::Visibility
lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind)101*700637cbSDimitry Andric lowerCIRVisibilityToLLVMVisibility(cir::VisibilityKind visibilityKind) {
102*700637cbSDimitry Andric   switch (visibilityKind) {
103*700637cbSDimitry Andric   case cir::VisibilityKind::Default:
104*700637cbSDimitry Andric     return ::mlir::LLVM::Visibility::Default;
105*700637cbSDimitry Andric   case cir::VisibilityKind::Hidden:
106*700637cbSDimitry Andric     return ::mlir::LLVM::Visibility::Hidden;
107*700637cbSDimitry Andric   case cir::VisibilityKind::Protected:
108*700637cbSDimitry Andric     return ::mlir::LLVM::Visibility::Protected;
109*700637cbSDimitry Andric   }
110*700637cbSDimitry Andric }
111*700637cbSDimitry Andric 
112*700637cbSDimitry Andric /// Emits the value from memory as expected by its users. Should be called when
113*700637cbSDimitry Andric /// the memory represetnation of a CIR type is not equal to its scalar
114*700637cbSDimitry Andric /// representation.
emitFromMemory(mlir::ConversionPatternRewriter & rewriter,mlir::DataLayout const & dataLayout,cir::LoadOp op,mlir::Value value)115*700637cbSDimitry Andric static mlir::Value emitFromMemory(mlir::ConversionPatternRewriter &rewriter,
116*700637cbSDimitry Andric                                   mlir::DataLayout const &dataLayout,
117*700637cbSDimitry Andric                                   cir::LoadOp op, mlir::Value value) {
118*700637cbSDimitry Andric 
119*700637cbSDimitry Andric   // TODO(cir): Handle other types similarly to clang's codegen EmitFromMemory
120*700637cbSDimitry Andric   if (auto boolTy = mlir::dyn_cast<cir::BoolType>(op.getType())) {
121*700637cbSDimitry Andric     // Create a cast value from specified size in datalayout to i1
122*700637cbSDimitry Andric     assert(value.getType().isInteger(dataLayout.getTypeSizeInBits(boolTy)));
123*700637cbSDimitry Andric     return createIntCast(rewriter, value, rewriter.getI1Type());
124*700637cbSDimitry Andric   }
125*700637cbSDimitry Andric 
126*700637cbSDimitry Andric   return value;
127*700637cbSDimitry Andric }
128*700637cbSDimitry Andric 
129*700637cbSDimitry Andric /// Emits a value to memory with the expected scalar type. Should be called when
130*700637cbSDimitry Andric /// the memory represetnation of a CIR type is not equal to its scalar
131*700637cbSDimitry Andric /// representation.
emitToMemory(mlir::ConversionPatternRewriter & rewriter,mlir::DataLayout const & dataLayout,mlir::Type origType,mlir::Value value)132*700637cbSDimitry Andric static mlir::Value emitToMemory(mlir::ConversionPatternRewriter &rewriter,
133*700637cbSDimitry Andric                                 mlir::DataLayout const &dataLayout,
134*700637cbSDimitry Andric                                 mlir::Type origType, mlir::Value value) {
135*700637cbSDimitry Andric 
136*700637cbSDimitry Andric   // TODO(cir): Handle other types similarly to clang's codegen EmitToMemory
137*700637cbSDimitry Andric   if (auto boolTy = mlir::dyn_cast<cir::BoolType>(origType)) {
138*700637cbSDimitry Andric     // Create zext of value from i1 to i8
139*700637cbSDimitry Andric     mlir::IntegerType memType =
140*700637cbSDimitry Andric         rewriter.getIntegerType(dataLayout.getTypeSizeInBits(boolTy));
141*700637cbSDimitry Andric     return createIntCast(rewriter, value, memType);
142*700637cbSDimitry Andric   }
143*700637cbSDimitry Andric 
144*700637cbSDimitry Andric   return value;
145*700637cbSDimitry Andric }
146*700637cbSDimitry Andric 
convertLinkage(cir::GlobalLinkageKind linkage)147*700637cbSDimitry Andric mlir::LLVM::Linkage convertLinkage(cir::GlobalLinkageKind linkage) {
148*700637cbSDimitry Andric   using CIR = cir::GlobalLinkageKind;
149*700637cbSDimitry Andric   using LLVM = mlir::LLVM::Linkage;
150*700637cbSDimitry Andric 
151*700637cbSDimitry Andric   switch (linkage) {
152*700637cbSDimitry Andric   case CIR::AvailableExternallyLinkage:
153*700637cbSDimitry Andric     return LLVM::AvailableExternally;
154*700637cbSDimitry Andric   case CIR::CommonLinkage:
155*700637cbSDimitry Andric     return LLVM::Common;
156*700637cbSDimitry Andric   case CIR::ExternalLinkage:
157*700637cbSDimitry Andric     return LLVM::External;
158*700637cbSDimitry Andric   case CIR::ExternalWeakLinkage:
159*700637cbSDimitry Andric     return LLVM::ExternWeak;
160*700637cbSDimitry Andric   case CIR::InternalLinkage:
161*700637cbSDimitry Andric     return LLVM::Internal;
162*700637cbSDimitry Andric   case CIR::LinkOnceAnyLinkage:
163*700637cbSDimitry Andric     return LLVM::Linkonce;
164*700637cbSDimitry Andric   case CIR::LinkOnceODRLinkage:
165*700637cbSDimitry Andric     return LLVM::LinkonceODR;
166*700637cbSDimitry Andric   case CIR::PrivateLinkage:
167*700637cbSDimitry Andric     return LLVM::Private;
168*700637cbSDimitry Andric   case CIR::WeakAnyLinkage:
169*700637cbSDimitry Andric     return LLVM::Weak;
170*700637cbSDimitry Andric   case CIR::WeakODRLinkage:
171*700637cbSDimitry Andric     return LLVM::WeakODR;
172*700637cbSDimitry Andric   };
173*700637cbSDimitry Andric   llvm_unreachable("Unknown CIR linkage type");
174*700637cbSDimitry Andric }
175*700637cbSDimitry Andric 
getLLVMIntCast(mlir::ConversionPatternRewriter & rewriter,mlir::Value llvmSrc,mlir::Type llvmDstIntTy,bool isUnsigned,uint64_t cirSrcWidth,uint64_t cirDstIntWidth)176*700637cbSDimitry Andric static mlir::Value getLLVMIntCast(mlir::ConversionPatternRewriter &rewriter,
177*700637cbSDimitry Andric                                   mlir::Value llvmSrc, mlir::Type llvmDstIntTy,
178*700637cbSDimitry Andric                                   bool isUnsigned, uint64_t cirSrcWidth,
179*700637cbSDimitry Andric                                   uint64_t cirDstIntWidth) {
180*700637cbSDimitry Andric   if (cirSrcWidth == cirDstIntWidth)
181*700637cbSDimitry Andric     return llvmSrc;
182*700637cbSDimitry Andric 
183*700637cbSDimitry Andric   auto loc = llvmSrc.getLoc();
184*700637cbSDimitry Andric   if (cirSrcWidth < cirDstIntWidth) {
185*700637cbSDimitry Andric     if (isUnsigned)
186*700637cbSDimitry Andric       return rewriter.create<mlir::LLVM::ZExtOp>(loc, llvmDstIntTy, llvmSrc);
187*700637cbSDimitry Andric     return rewriter.create<mlir::LLVM::SExtOp>(loc, llvmDstIntTy, llvmSrc);
188*700637cbSDimitry Andric   }
189*700637cbSDimitry Andric 
190*700637cbSDimitry Andric   // Otherwise truncate
191*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::TruncOp>(loc, llvmDstIntTy, llvmSrc);
192*700637cbSDimitry Andric }
193*700637cbSDimitry Andric 
194*700637cbSDimitry Andric class CIRAttrToValue {
195*700637cbSDimitry Andric public:
CIRAttrToValue(mlir::Operation * parentOp,mlir::ConversionPatternRewriter & rewriter,const mlir::TypeConverter * converter)196*700637cbSDimitry Andric   CIRAttrToValue(mlir::Operation *parentOp,
197*700637cbSDimitry Andric                  mlir::ConversionPatternRewriter &rewriter,
198*700637cbSDimitry Andric                  const mlir::TypeConverter *converter)
199*700637cbSDimitry Andric       : parentOp(parentOp), rewriter(rewriter), converter(converter) {}
200*700637cbSDimitry Andric 
visit(mlir::Attribute attr)201*700637cbSDimitry Andric   mlir::Value visit(mlir::Attribute attr) {
202*700637cbSDimitry Andric     return llvm::TypeSwitch<mlir::Attribute, mlir::Value>(attr)
203*700637cbSDimitry Andric         .Case<cir::IntAttr, cir::FPAttr, cir::ConstComplexAttr,
204*700637cbSDimitry Andric               cir::ConstArrayAttr, cir::ConstVectorAttr, cir::ConstPtrAttr,
205*700637cbSDimitry Andric               cir::ZeroAttr>([&](auto attrT) { return visitCirAttr(attrT); })
206*700637cbSDimitry Andric         .Default([&](auto attrT) { return mlir::Value(); });
207*700637cbSDimitry Andric   }
208*700637cbSDimitry Andric 
209*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::IntAttr intAttr);
210*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::FPAttr fltAttr);
211*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::ConstComplexAttr complexAttr);
212*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::ConstPtrAttr ptrAttr);
213*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::ConstArrayAttr attr);
214*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::ConstVectorAttr attr);
215*700637cbSDimitry Andric   mlir::Value visitCirAttr(cir::ZeroAttr attr);
216*700637cbSDimitry Andric 
217*700637cbSDimitry Andric private:
218*700637cbSDimitry Andric   mlir::Operation *parentOp;
219*700637cbSDimitry Andric   mlir::ConversionPatternRewriter &rewriter;
220*700637cbSDimitry Andric   const mlir::TypeConverter *converter;
221*700637cbSDimitry Andric };
222*700637cbSDimitry Andric 
223*700637cbSDimitry Andric /// Switches on the type of attribute and calls the appropriate conversion.
lowerCirAttrAsValue(mlir::Operation * parentOp,const mlir::Attribute attr,mlir::ConversionPatternRewriter & rewriter,const mlir::TypeConverter * converter)224*700637cbSDimitry Andric mlir::Value lowerCirAttrAsValue(mlir::Operation *parentOp,
225*700637cbSDimitry Andric                                 const mlir::Attribute attr,
226*700637cbSDimitry Andric                                 mlir::ConversionPatternRewriter &rewriter,
227*700637cbSDimitry Andric                                 const mlir::TypeConverter *converter) {
228*700637cbSDimitry Andric   CIRAttrToValue valueConverter(parentOp, rewriter, converter);
229*700637cbSDimitry Andric   mlir::Value value = valueConverter.visit(attr);
230*700637cbSDimitry Andric   if (!value)
231*700637cbSDimitry Andric     llvm_unreachable("unhandled attribute type");
232*700637cbSDimitry Andric   return value;
233*700637cbSDimitry Andric }
234*700637cbSDimitry Andric 
convertSideEffectForCall(mlir::Operation * callOp,bool isNothrow,cir::SideEffect sideEffect,mlir::LLVM::MemoryEffectsAttr & memoryEffect,bool & noUnwind,bool & willReturn)235*700637cbSDimitry Andric void convertSideEffectForCall(mlir::Operation *callOp, bool isNothrow,
236*700637cbSDimitry Andric                               cir::SideEffect sideEffect,
237*700637cbSDimitry Andric                               mlir::LLVM::MemoryEffectsAttr &memoryEffect,
238*700637cbSDimitry Andric                               bool &noUnwind, bool &willReturn) {
239*700637cbSDimitry Andric   using mlir::LLVM::ModRefInfo;
240*700637cbSDimitry Andric 
241*700637cbSDimitry Andric   switch (sideEffect) {
242*700637cbSDimitry Andric   case cir::SideEffect::All:
243*700637cbSDimitry Andric     memoryEffect = {};
244*700637cbSDimitry Andric     noUnwind = isNothrow;
245*700637cbSDimitry Andric     willReturn = false;
246*700637cbSDimitry Andric     break;
247*700637cbSDimitry Andric 
248*700637cbSDimitry Andric   case cir::SideEffect::Pure:
249*700637cbSDimitry Andric     memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
250*700637cbSDimitry Andric         callOp->getContext(), /*other=*/ModRefInfo::Ref,
251*700637cbSDimitry Andric         /*argMem=*/ModRefInfo::Ref,
252*700637cbSDimitry Andric         /*inaccessibleMem=*/ModRefInfo::Ref);
253*700637cbSDimitry Andric     noUnwind = true;
254*700637cbSDimitry Andric     willReturn = true;
255*700637cbSDimitry Andric     break;
256*700637cbSDimitry Andric 
257*700637cbSDimitry Andric   case cir::SideEffect::Const:
258*700637cbSDimitry Andric     memoryEffect = mlir::LLVM::MemoryEffectsAttr::get(
259*700637cbSDimitry Andric         callOp->getContext(), /*other=*/ModRefInfo::NoModRef,
260*700637cbSDimitry Andric         /*argMem=*/ModRefInfo::NoModRef,
261*700637cbSDimitry Andric         /*inaccessibleMem=*/ModRefInfo::NoModRef);
262*700637cbSDimitry Andric     noUnwind = true;
263*700637cbSDimitry Andric     willReturn = true;
264*700637cbSDimitry Andric     break;
265*700637cbSDimitry Andric   }
266*700637cbSDimitry Andric }
267*700637cbSDimitry Andric 
268*700637cbSDimitry Andric /// IntAttr visitor.
visitCirAttr(cir::IntAttr intAttr)269*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::IntAttr intAttr) {
270*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
271*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::ConstantOp>(
272*700637cbSDimitry Andric       loc, converter->convertType(intAttr.getType()), intAttr.getValue());
273*700637cbSDimitry Andric }
274*700637cbSDimitry Andric 
275*700637cbSDimitry Andric /// FPAttr visitor.
visitCirAttr(cir::FPAttr fltAttr)276*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::FPAttr fltAttr) {
277*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
278*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::ConstantOp>(
279*700637cbSDimitry Andric       loc, converter->convertType(fltAttr.getType()), fltAttr.getValue());
280*700637cbSDimitry Andric }
281*700637cbSDimitry Andric 
282*700637cbSDimitry Andric /// ConstComplexAttr visitor.
visitCirAttr(cir::ConstComplexAttr complexAttr)283*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstComplexAttr complexAttr) {
284*700637cbSDimitry Andric   auto complexType = mlir::cast<cir::ComplexType>(complexAttr.getType());
285*700637cbSDimitry Andric   mlir::Type complexElemTy = complexType.getElementType();
286*700637cbSDimitry Andric   mlir::Type complexElemLLVMTy = converter->convertType(complexElemTy);
287*700637cbSDimitry Andric 
288*700637cbSDimitry Andric   mlir::Attribute components[2];
289*700637cbSDimitry Andric   if (const auto intType = mlir::dyn_cast<cir::IntType>(complexElemTy)) {
290*700637cbSDimitry Andric     components[0] = rewriter.getIntegerAttr(
291*700637cbSDimitry Andric         complexElemLLVMTy,
292*700637cbSDimitry Andric         mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());
293*700637cbSDimitry Andric     components[1] = rewriter.getIntegerAttr(
294*700637cbSDimitry Andric         complexElemLLVMTy,
295*700637cbSDimitry Andric         mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());
296*700637cbSDimitry Andric   } else {
297*700637cbSDimitry Andric     components[0] = rewriter.getFloatAttr(
298*700637cbSDimitry Andric         complexElemLLVMTy,
299*700637cbSDimitry Andric         mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());
300*700637cbSDimitry Andric     components[1] = rewriter.getFloatAttr(
301*700637cbSDimitry Andric         complexElemLLVMTy,
302*700637cbSDimitry Andric         mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());
303*700637cbSDimitry Andric   }
304*700637cbSDimitry Andric 
305*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
306*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::ConstantOp>(
307*700637cbSDimitry Andric       loc, converter->convertType(complexAttr.getType()),
308*700637cbSDimitry Andric       rewriter.getArrayAttr(components));
309*700637cbSDimitry Andric }
310*700637cbSDimitry Andric 
311*700637cbSDimitry Andric /// ConstPtrAttr visitor.
visitCirAttr(cir::ConstPtrAttr ptrAttr)312*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstPtrAttr ptrAttr) {
313*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
314*700637cbSDimitry Andric   if (ptrAttr.isNullValue()) {
315*700637cbSDimitry Andric     return rewriter.create<mlir::LLVM::ZeroOp>(
316*700637cbSDimitry Andric         loc, converter->convertType(ptrAttr.getType()));
317*700637cbSDimitry Andric   }
318*700637cbSDimitry Andric   mlir::DataLayout layout(parentOp->getParentOfType<mlir::ModuleOp>());
319*700637cbSDimitry Andric   mlir::Value ptrVal = rewriter.create<mlir::LLVM::ConstantOp>(
320*700637cbSDimitry Andric       loc, rewriter.getIntegerType(layout.getTypeSizeInBits(ptrAttr.getType())),
321*700637cbSDimitry Andric       ptrAttr.getValue().getInt());
322*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::IntToPtrOp>(
323*700637cbSDimitry Andric       loc, converter->convertType(ptrAttr.getType()), ptrVal);
324*700637cbSDimitry Andric }
325*700637cbSDimitry Andric 
326*700637cbSDimitry Andric // ConstArrayAttr visitor
visitCirAttr(cir::ConstArrayAttr attr)327*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstArrayAttr attr) {
328*700637cbSDimitry Andric   mlir::Type llvmTy = converter->convertType(attr.getType());
329*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
330*700637cbSDimitry Andric   mlir::Value result;
331*700637cbSDimitry Andric 
332*700637cbSDimitry Andric   if (attr.hasTrailingZeros()) {
333*700637cbSDimitry Andric     mlir::Type arrayTy = attr.getType();
334*700637cbSDimitry Andric     result = rewriter.create<mlir::LLVM::ZeroOp>(
335*700637cbSDimitry Andric         loc, converter->convertType(arrayTy));
336*700637cbSDimitry Andric   } else {
337*700637cbSDimitry Andric     result = rewriter.create<mlir::LLVM::UndefOp>(loc, llvmTy);
338*700637cbSDimitry Andric   }
339*700637cbSDimitry Andric 
340*700637cbSDimitry Andric   // Iteratively lower each constant element of the array.
341*700637cbSDimitry Andric   if (auto arrayAttr = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts())) {
342*700637cbSDimitry Andric     for (auto [idx, elt] : llvm::enumerate(arrayAttr)) {
343*700637cbSDimitry Andric       mlir::DataLayout dataLayout(parentOp->getParentOfType<mlir::ModuleOp>());
344*700637cbSDimitry Andric       mlir::Value init = visit(elt);
345*700637cbSDimitry Andric       result =
346*700637cbSDimitry Andric           rewriter.create<mlir::LLVM::InsertValueOp>(loc, result, init, idx);
347*700637cbSDimitry Andric     }
348*700637cbSDimitry Andric   } else if (auto strAttr = mlir::dyn_cast<mlir::StringAttr>(attr.getElts())) {
349*700637cbSDimitry Andric     // TODO(cir): this diverges from traditional lowering. Normally the string
350*700637cbSDimitry Andric     // would be a global constant that is memcopied.
351*700637cbSDimitry Andric     auto arrayTy = mlir::dyn_cast<cir::ArrayType>(strAttr.getType());
352*700637cbSDimitry Andric     assert(arrayTy && "String attribute must have an array type");
353*700637cbSDimitry Andric     mlir::Type eltTy = arrayTy.getElementType();
354*700637cbSDimitry Andric     for (auto [idx, elt] : llvm::enumerate(strAttr)) {
355*700637cbSDimitry Andric       auto init = rewriter.create<mlir::LLVM::ConstantOp>(
356*700637cbSDimitry Andric           loc, converter->convertType(eltTy), elt);
357*700637cbSDimitry Andric       result =
358*700637cbSDimitry Andric           rewriter.create<mlir::LLVM::InsertValueOp>(loc, result, init, idx);
359*700637cbSDimitry Andric     }
360*700637cbSDimitry Andric   } else {
361*700637cbSDimitry Andric     llvm_unreachable("unexpected ConstArrayAttr elements");
362*700637cbSDimitry Andric   }
363*700637cbSDimitry Andric 
364*700637cbSDimitry Andric   return result;
365*700637cbSDimitry Andric }
366*700637cbSDimitry Andric 
367*700637cbSDimitry Andric /// ConstVectorAttr visitor.
visitCirAttr(cir::ConstVectorAttr attr)368*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::ConstVectorAttr attr) {
369*700637cbSDimitry Andric   const mlir::Type llvmTy = converter->convertType(attr.getType());
370*700637cbSDimitry Andric   const mlir::Location loc = parentOp->getLoc();
371*700637cbSDimitry Andric 
372*700637cbSDimitry Andric   SmallVector<mlir::Attribute> mlirValues;
373*700637cbSDimitry Andric   for (const mlir::Attribute elementAttr : attr.getElts()) {
374*700637cbSDimitry Andric     mlir::Attribute mlirAttr;
375*700637cbSDimitry Andric     if (auto intAttr = mlir::dyn_cast<cir::IntAttr>(elementAttr)) {
376*700637cbSDimitry Andric       mlirAttr = rewriter.getIntegerAttr(
377*700637cbSDimitry Andric           converter->convertType(intAttr.getType()), intAttr.getValue());
378*700637cbSDimitry Andric     } else if (auto floatAttr = mlir::dyn_cast<cir::FPAttr>(elementAttr)) {
379*700637cbSDimitry Andric       mlirAttr = rewriter.getFloatAttr(
380*700637cbSDimitry Andric           converter->convertType(floatAttr.getType()), floatAttr.getValue());
381*700637cbSDimitry Andric     } else {
382*700637cbSDimitry Andric       llvm_unreachable(
383*700637cbSDimitry Andric           "vector constant with an element that is neither an int nor a float");
384*700637cbSDimitry Andric     }
385*700637cbSDimitry Andric     mlirValues.push_back(mlirAttr);
386*700637cbSDimitry Andric   }
387*700637cbSDimitry Andric 
388*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::ConstantOp>(
389*700637cbSDimitry Andric       loc, llvmTy,
390*700637cbSDimitry Andric       mlir::DenseElementsAttr::get(mlir::cast<mlir::ShapedType>(llvmTy),
391*700637cbSDimitry Andric                                    mlirValues));
392*700637cbSDimitry Andric }
393*700637cbSDimitry Andric 
394*700637cbSDimitry Andric /// ZeroAttr visitor.
visitCirAttr(cir::ZeroAttr attr)395*700637cbSDimitry Andric mlir::Value CIRAttrToValue::visitCirAttr(cir::ZeroAttr attr) {
396*700637cbSDimitry Andric   mlir::Location loc = parentOp->getLoc();
397*700637cbSDimitry Andric   return rewriter.create<mlir::LLVM::ZeroOp>(
398*700637cbSDimitry Andric       loc, converter->convertType(attr.getType()));
399*700637cbSDimitry Andric }
400*700637cbSDimitry Andric 
401*700637cbSDimitry Andric // This class handles rewriting initializer attributes for types that do not
402*700637cbSDimitry Andric // require region initialization.
403*700637cbSDimitry Andric class GlobalInitAttrRewriter {
404*700637cbSDimitry Andric public:
GlobalInitAttrRewriter(mlir::Type type,mlir::ConversionPatternRewriter & rewriter)405*700637cbSDimitry Andric   GlobalInitAttrRewriter(mlir::Type type,
406*700637cbSDimitry Andric                          mlir::ConversionPatternRewriter &rewriter)
407*700637cbSDimitry Andric       : llvmType(type), rewriter(rewriter) {}
408*700637cbSDimitry Andric 
visit(mlir::Attribute attr)409*700637cbSDimitry Andric   mlir::Attribute visit(mlir::Attribute attr) {
410*700637cbSDimitry Andric     return llvm::TypeSwitch<mlir::Attribute, mlir::Attribute>(attr)
411*700637cbSDimitry Andric         .Case<cir::IntAttr, cir::FPAttr, cir::BoolAttr>(
412*700637cbSDimitry Andric             [&](auto attrT) { return visitCirAttr(attrT); })
413*700637cbSDimitry Andric         .Default([&](auto attrT) { return mlir::Attribute(); });
414*700637cbSDimitry Andric   }
415*700637cbSDimitry Andric 
visitCirAttr(cir::IntAttr attr)416*700637cbSDimitry Andric   mlir::Attribute visitCirAttr(cir::IntAttr attr) {
417*700637cbSDimitry Andric     return rewriter.getIntegerAttr(llvmType, attr.getValue());
418*700637cbSDimitry Andric   }
419*700637cbSDimitry Andric 
visitCirAttr(cir::FPAttr attr)420*700637cbSDimitry Andric   mlir::Attribute visitCirAttr(cir::FPAttr attr) {
421*700637cbSDimitry Andric     return rewriter.getFloatAttr(llvmType, attr.getValue());
422*700637cbSDimitry Andric   }
423*700637cbSDimitry Andric 
visitCirAttr(cir::BoolAttr attr)424*700637cbSDimitry Andric   mlir::Attribute visitCirAttr(cir::BoolAttr attr) {
425*700637cbSDimitry Andric     return rewriter.getBoolAttr(attr.getValue());
426*700637cbSDimitry Andric   }
427*700637cbSDimitry Andric 
428*700637cbSDimitry Andric private:
429*700637cbSDimitry Andric   mlir::Type llvmType;
430*700637cbSDimitry Andric   mlir::ConversionPatternRewriter &rewriter;
431*700637cbSDimitry Andric };
432*700637cbSDimitry Andric 
433*700637cbSDimitry Andric // This pass requires the CIR to be in a "flat" state. All blocks in each
434*700637cbSDimitry Andric // function must belong to the parent region. Once scopes and control flow
435*700637cbSDimitry Andric // are implemented in CIR, a pass will be run before this one to flatten
436*700637cbSDimitry Andric // the CIR and get it into the state that this pass requires.
437*700637cbSDimitry Andric struct ConvertCIRToLLVMPass
438*700637cbSDimitry Andric     : public mlir::PassWrapper<ConvertCIRToLLVMPass,
439*700637cbSDimitry Andric                                mlir::OperationPass<mlir::ModuleOp>> {
getDependentDialectscir::direct::ConvertCIRToLLVMPass440*700637cbSDimitry Andric   void getDependentDialects(mlir::DialectRegistry &registry) const override {
441*700637cbSDimitry Andric     registry.insert<mlir::BuiltinDialect, mlir::DLTIDialect,
442*700637cbSDimitry Andric                     mlir::LLVM::LLVMDialect, mlir::func::FuncDialect>();
443*700637cbSDimitry Andric   }
444*700637cbSDimitry Andric   void runOnOperation() final;
445*700637cbSDimitry Andric 
446*700637cbSDimitry Andric   void processCIRAttrs(mlir::ModuleOp module);
447*700637cbSDimitry Andric 
getDescriptioncir::direct::ConvertCIRToLLVMPass448*700637cbSDimitry Andric   StringRef getDescription() const override {
449*700637cbSDimitry Andric     return "Convert the prepared CIR dialect module to LLVM dialect";
450*700637cbSDimitry Andric   }
451*700637cbSDimitry Andric 
getArgumentcir::direct::ConvertCIRToLLVMPass452*700637cbSDimitry Andric   StringRef getArgument() const override { return "cir-flat-to-llvm"; }
453*700637cbSDimitry Andric };
454*700637cbSDimitry Andric 
matchAndRewrite(cir::AssumeOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const455*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMAssumeOpLowering::matchAndRewrite(
456*700637cbSDimitry Andric     cir::AssumeOp op, OpAdaptor adaptor,
457*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
458*700637cbSDimitry Andric   auto cond = adaptor.getPredicate();
459*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::AssumeOp>(op, cond);
460*700637cbSDimitry Andric   return mlir::success();
461*700637cbSDimitry Andric }
462*700637cbSDimitry Andric 
matchAndRewrite(cir::BitClrsbOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const463*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitClrsbOpLowering::matchAndRewrite(
464*700637cbSDimitry Andric     cir::BitClrsbOp op, OpAdaptor adaptor,
465*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
466*700637cbSDimitry Andric   auto zero = rewriter.create<mlir::LLVM::ConstantOp>(
467*700637cbSDimitry Andric       op.getLoc(), adaptor.getInput().getType(), 0);
468*700637cbSDimitry Andric   auto isNeg = rewriter.create<mlir::LLVM::ICmpOp>(
469*700637cbSDimitry Andric       op.getLoc(),
470*700637cbSDimitry Andric       mlir::LLVM::ICmpPredicateAttr::get(rewriter.getContext(),
471*700637cbSDimitry Andric                                          mlir::LLVM::ICmpPredicate::slt),
472*700637cbSDimitry Andric       adaptor.getInput(), zero);
473*700637cbSDimitry Andric 
474*700637cbSDimitry Andric   auto negOne = rewriter.create<mlir::LLVM::ConstantOp>(
475*700637cbSDimitry Andric       op.getLoc(), adaptor.getInput().getType(), -1);
476*700637cbSDimitry Andric   auto flipped = rewriter.create<mlir::LLVM::XOrOp>(op.getLoc(),
477*700637cbSDimitry Andric                                                     adaptor.getInput(), negOne);
478*700637cbSDimitry Andric 
479*700637cbSDimitry Andric   auto select = rewriter.create<mlir::LLVM::SelectOp>(
480*700637cbSDimitry Andric       op.getLoc(), isNeg, flipped, adaptor.getInput());
481*700637cbSDimitry Andric 
482*700637cbSDimitry Andric   auto resTy = getTypeConverter()->convertType(op.getType());
483*700637cbSDimitry Andric   auto clz = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(
484*700637cbSDimitry Andric       op.getLoc(), resTy, select, /*is_zero_poison=*/false);
485*700637cbSDimitry Andric 
486*700637cbSDimitry Andric   auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);
487*700637cbSDimitry Andric   auto res = rewriter.create<mlir::LLVM::SubOp>(op.getLoc(), clz, one);
488*700637cbSDimitry Andric   rewriter.replaceOp(op, res);
489*700637cbSDimitry Andric 
490*700637cbSDimitry Andric   return mlir::LogicalResult::success();
491*700637cbSDimitry Andric }
492*700637cbSDimitry Andric 
matchAndRewrite(cir::BitClzOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const493*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitClzOpLowering::matchAndRewrite(
494*700637cbSDimitry Andric     cir::BitClzOp op, OpAdaptor adaptor,
495*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
496*700637cbSDimitry Andric   auto resTy = getTypeConverter()->convertType(op.getType());
497*700637cbSDimitry Andric   auto llvmOp = rewriter.create<mlir::LLVM::CountLeadingZerosOp>(
498*700637cbSDimitry Andric       op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());
499*700637cbSDimitry Andric   rewriter.replaceOp(op, llvmOp);
500*700637cbSDimitry Andric   return mlir::LogicalResult::success();
501*700637cbSDimitry Andric }
502*700637cbSDimitry Andric 
matchAndRewrite(cir::BitCtzOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const503*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitCtzOpLowering::matchAndRewrite(
504*700637cbSDimitry Andric     cir::BitCtzOp op, OpAdaptor adaptor,
505*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
506*700637cbSDimitry Andric   auto resTy = getTypeConverter()->convertType(op.getType());
507*700637cbSDimitry Andric   auto llvmOp = rewriter.create<mlir::LLVM::CountTrailingZerosOp>(
508*700637cbSDimitry Andric       op.getLoc(), resTy, adaptor.getInput(), op.getPoisonZero());
509*700637cbSDimitry Andric   rewriter.replaceOp(op, llvmOp);
510*700637cbSDimitry Andric   return mlir::LogicalResult::success();
511*700637cbSDimitry Andric }
512*700637cbSDimitry Andric 
matchAndRewrite(cir::BitParityOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const513*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitParityOpLowering::matchAndRewrite(
514*700637cbSDimitry Andric     cir::BitParityOp op, OpAdaptor adaptor,
515*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
516*700637cbSDimitry Andric   auto resTy = getTypeConverter()->convertType(op.getType());
517*700637cbSDimitry Andric   auto popcnt = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,
518*700637cbSDimitry Andric                                                      adaptor.getInput());
519*700637cbSDimitry Andric 
520*700637cbSDimitry Andric   auto one = rewriter.create<mlir::LLVM::ConstantOp>(op.getLoc(), resTy, 1);
521*700637cbSDimitry Andric   auto popcntMod2 =
522*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::AndOp>(op.getLoc(), popcnt, one);
523*700637cbSDimitry Andric   rewriter.replaceOp(op, popcntMod2);
524*700637cbSDimitry Andric 
525*700637cbSDimitry Andric   return mlir::LogicalResult::success();
526*700637cbSDimitry Andric }
527*700637cbSDimitry Andric 
matchAndRewrite(cir::BitPopcountOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const528*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitPopcountOpLowering::matchAndRewrite(
529*700637cbSDimitry Andric     cir::BitPopcountOp op, OpAdaptor adaptor,
530*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
531*700637cbSDimitry Andric   auto resTy = getTypeConverter()->convertType(op.getType());
532*700637cbSDimitry Andric   auto llvmOp = rewriter.create<mlir::LLVM::CtPopOp>(op.getLoc(), resTy,
533*700637cbSDimitry Andric                                                      adaptor.getInput());
534*700637cbSDimitry Andric   rewriter.replaceOp(op, llvmOp);
535*700637cbSDimitry Andric   return mlir::LogicalResult::success();
536*700637cbSDimitry Andric }
537*700637cbSDimitry Andric 
matchAndRewrite(cir::BitReverseOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const538*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBitReverseOpLowering::matchAndRewrite(
539*700637cbSDimitry Andric     cir::BitReverseOp op, OpAdaptor adaptor,
540*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
541*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::BitReverseOp>(op, adaptor.getInput());
542*700637cbSDimitry Andric   return mlir::success();
543*700637cbSDimitry Andric }
544*700637cbSDimitry Andric 
matchAndRewrite(cir::BrCondOp brOp,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const545*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBrCondOpLowering::matchAndRewrite(
546*700637cbSDimitry Andric     cir::BrCondOp brOp, OpAdaptor adaptor,
547*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
548*700637cbSDimitry Andric   // When ZExtOp is implemented, we'll need to check if the condition is a
549*700637cbSDimitry Andric   // ZExtOp and if so, delete it if it has a single use.
550*700637cbSDimitry Andric   assert(!cir::MissingFeatures::zextOp());
551*700637cbSDimitry Andric 
552*700637cbSDimitry Andric   mlir::Value i1Condition = adaptor.getCond();
553*700637cbSDimitry Andric 
554*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::CondBrOp>(
555*700637cbSDimitry Andric       brOp, i1Condition, brOp.getDestTrue(), adaptor.getDestOperandsTrue(),
556*700637cbSDimitry Andric       brOp.getDestFalse(), adaptor.getDestOperandsFalse());
557*700637cbSDimitry Andric 
558*700637cbSDimitry Andric   return mlir::success();
559*700637cbSDimitry Andric }
560*700637cbSDimitry Andric 
matchAndRewrite(cir::ByteSwapOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const561*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMByteSwapOpLowering::matchAndRewrite(
562*700637cbSDimitry Andric     cir::ByteSwapOp op, OpAdaptor adaptor,
563*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
564*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ByteSwapOp>(op, adaptor.getInput());
565*700637cbSDimitry Andric   return mlir::LogicalResult::success();
566*700637cbSDimitry Andric }
567*700637cbSDimitry Andric 
convertTy(mlir::Type ty) const568*700637cbSDimitry Andric mlir::Type CIRToLLVMCastOpLowering::convertTy(mlir::Type ty) const {
569*700637cbSDimitry Andric   return getTypeConverter()->convertType(ty);
570*700637cbSDimitry Andric }
571*700637cbSDimitry Andric 
matchAndRewrite(cir::CastOp castOp,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const572*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMCastOpLowering::matchAndRewrite(
573*700637cbSDimitry Andric     cir::CastOp castOp, OpAdaptor adaptor,
574*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
575*700637cbSDimitry Andric   // For arithmetic conversions, LLVM IR uses the same instruction to convert
576*700637cbSDimitry Andric   // both individual scalars and entire vectors. This lowering pass handles
577*700637cbSDimitry Andric   // both situations.
578*700637cbSDimitry Andric 
579*700637cbSDimitry Andric   switch (castOp.getKind()) {
580*700637cbSDimitry Andric   case cir::CastKind::array_to_ptrdecay: {
581*700637cbSDimitry Andric     const auto ptrTy = mlir::cast<cir::PointerType>(castOp.getType());
582*700637cbSDimitry Andric     mlir::Value sourceValue = adaptor.getSrc();
583*700637cbSDimitry Andric     mlir::Type targetType = convertTy(ptrTy);
584*700637cbSDimitry Andric     mlir::Type elementTy = convertTypeForMemory(*getTypeConverter(), dataLayout,
585*700637cbSDimitry Andric                                                 ptrTy.getPointee());
586*700637cbSDimitry Andric     llvm::SmallVector<mlir::LLVM::GEPArg> offset{0};
587*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
588*700637cbSDimitry Andric         castOp, targetType, elementTy, sourceValue, offset);
589*700637cbSDimitry Andric     break;
590*700637cbSDimitry Andric   }
591*700637cbSDimitry Andric   case cir::CastKind::int_to_bool: {
592*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
593*700637cbSDimitry Andric     mlir::Value zeroInt = rewriter.create<mlir::LLVM::ConstantOp>(
594*700637cbSDimitry Andric         castOp.getLoc(), llvmSrcVal.getType(), 0);
595*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
596*700637cbSDimitry Andric         castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroInt);
597*700637cbSDimitry Andric     break;
598*700637cbSDimitry Andric   }
599*700637cbSDimitry Andric   case cir::CastKind::integral: {
600*700637cbSDimitry Andric     mlir::Type srcType = castOp.getSrc().getType();
601*700637cbSDimitry Andric     mlir::Type dstType = castOp.getType();
602*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
603*700637cbSDimitry Andric     mlir::Type llvmDstType = getTypeConverter()->convertType(dstType);
604*700637cbSDimitry Andric     cir::IntType srcIntType =
605*700637cbSDimitry Andric         mlir::cast<cir::IntType>(elementTypeIfVector(srcType));
606*700637cbSDimitry Andric     cir::IntType dstIntType =
607*700637cbSDimitry Andric         mlir::cast<cir::IntType>(elementTypeIfVector(dstType));
608*700637cbSDimitry Andric     rewriter.replaceOp(castOp, getLLVMIntCast(rewriter, llvmSrcVal, llvmDstType,
609*700637cbSDimitry Andric                                               srcIntType.isUnsigned(),
610*700637cbSDimitry Andric                                               srcIntType.getWidth(),
611*700637cbSDimitry Andric                                               dstIntType.getWidth()));
612*700637cbSDimitry Andric     break;
613*700637cbSDimitry Andric   }
614*700637cbSDimitry Andric   case cir::CastKind::floating: {
615*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
616*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(castOp.getType());
617*700637cbSDimitry Andric 
618*700637cbSDimitry Andric     mlir::Type srcTy = elementTypeIfVector(castOp.getSrc().getType());
619*700637cbSDimitry Andric     mlir::Type dstTy = elementTypeIfVector(castOp.getType());
620*700637cbSDimitry Andric 
621*700637cbSDimitry Andric     if (!mlir::isa<cir::FPTypeInterface>(dstTy) ||
622*700637cbSDimitry Andric         !mlir::isa<cir::FPTypeInterface>(srcTy))
623*700637cbSDimitry Andric       return castOp.emitError() << "NYI cast from " << srcTy << " to " << dstTy;
624*700637cbSDimitry Andric 
625*700637cbSDimitry Andric     auto getFloatWidth = [](mlir::Type ty) -> unsigned {
626*700637cbSDimitry Andric       return mlir::cast<cir::FPTypeInterface>(ty).getWidth();
627*700637cbSDimitry Andric     };
628*700637cbSDimitry Andric 
629*700637cbSDimitry Andric     if (getFloatWidth(srcTy) > getFloatWidth(dstTy))
630*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FPTruncOp>(castOp, llvmDstTy,
631*700637cbSDimitry Andric                                                          llvmSrcVal);
632*700637cbSDimitry Andric     else
633*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FPExtOp>(castOp, llvmDstTy,
634*700637cbSDimitry Andric                                                        llvmSrcVal);
635*700637cbSDimitry Andric     return mlir::success();
636*700637cbSDimitry Andric   }
637*700637cbSDimitry Andric   case cir::CastKind::int_to_ptr: {
638*700637cbSDimitry Andric     auto dstTy = mlir::cast<cir::PointerType>(castOp.getType());
639*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
640*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
641*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(castOp, llvmDstTy,
642*700637cbSDimitry Andric                                                         llvmSrcVal);
643*700637cbSDimitry Andric     return mlir::success();
644*700637cbSDimitry Andric   }
645*700637cbSDimitry Andric   case cir::CastKind::ptr_to_int: {
646*700637cbSDimitry Andric     auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
647*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
648*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
649*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(castOp, llvmDstTy,
650*700637cbSDimitry Andric                                                         llvmSrcVal);
651*700637cbSDimitry Andric     return mlir::success();
652*700637cbSDimitry Andric   }
653*700637cbSDimitry Andric   case cir::CastKind::float_to_bool: {
654*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
655*700637cbSDimitry Andric     auto kind = mlir::LLVM::FCmpPredicate::une;
656*700637cbSDimitry Andric 
657*700637cbSDimitry Andric     // Check if float is not equal to zero.
658*700637cbSDimitry Andric     auto zeroFloat = rewriter.create<mlir::LLVM::ConstantOp>(
659*700637cbSDimitry Andric         castOp.getLoc(), llvmSrcVal.getType(),
660*700637cbSDimitry Andric         mlir::FloatAttr::get(llvmSrcVal.getType(), 0.0));
661*700637cbSDimitry Andric 
662*700637cbSDimitry Andric     // Extend comparison result to either bool (C++) or int (C).
663*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(castOp, kind, llvmSrcVal,
664*700637cbSDimitry Andric                                                     zeroFloat);
665*700637cbSDimitry Andric 
666*700637cbSDimitry Andric     return mlir::success();
667*700637cbSDimitry Andric   }
668*700637cbSDimitry Andric   case cir::CastKind::bool_to_int: {
669*700637cbSDimitry Andric     auto dstTy = mlir::cast<cir::IntType>(castOp.getType());
670*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
671*700637cbSDimitry Andric     auto llvmSrcTy = mlir::cast<mlir::IntegerType>(llvmSrcVal.getType());
672*700637cbSDimitry Andric     auto llvmDstTy =
673*700637cbSDimitry Andric         mlir::cast<mlir::IntegerType>(getTypeConverter()->convertType(dstTy));
674*700637cbSDimitry Andric     if (llvmSrcTy.getWidth() == llvmDstTy.getWidth())
675*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,
676*700637cbSDimitry Andric                                                          llvmSrcVal);
677*700637cbSDimitry Andric     else
678*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::ZExtOp>(castOp, llvmDstTy,
679*700637cbSDimitry Andric                                                       llvmSrcVal);
680*700637cbSDimitry Andric     return mlir::success();
681*700637cbSDimitry Andric   }
682*700637cbSDimitry Andric   case cir::CastKind::bool_to_float: {
683*700637cbSDimitry Andric     mlir::Type dstTy = castOp.getType();
684*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
685*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
686*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,
687*700637cbSDimitry Andric                                                       llvmSrcVal);
688*700637cbSDimitry Andric     return mlir::success();
689*700637cbSDimitry Andric   }
690*700637cbSDimitry Andric   case cir::CastKind::int_to_float: {
691*700637cbSDimitry Andric     mlir::Type dstTy = castOp.getType();
692*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
693*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
694*700637cbSDimitry Andric     if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getSrc().getType()))
695*700637cbSDimitry Andric             .isSigned())
696*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(castOp, llvmDstTy,
697*700637cbSDimitry Andric                                                         llvmSrcVal);
698*700637cbSDimitry Andric     else
699*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::UIToFPOp>(castOp, llvmDstTy,
700*700637cbSDimitry Andric                                                         llvmSrcVal);
701*700637cbSDimitry Andric     return mlir::success();
702*700637cbSDimitry Andric   }
703*700637cbSDimitry Andric   case cir::CastKind::float_to_int: {
704*700637cbSDimitry Andric     mlir::Type dstTy = castOp.getType();
705*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
706*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
707*700637cbSDimitry Andric     if (mlir::cast<cir::IntType>(elementTypeIfVector(castOp.getType()))
708*700637cbSDimitry Andric             .isSigned())
709*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(castOp, llvmDstTy,
710*700637cbSDimitry Andric                                                         llvmSrcVal);
711*700637cbSDimitry Andric     else
712*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FPToUIOp>(castOp, llvmDstTy,
713*700637cbSDimitry Andric                                                         llvmSrcVal);
714*700637cbSDimitry Andric     return mlir::success();
715*700637cbSDimitry Andric   }
716*700637cbSDimitry Andric   case cir::CastKind::bitcast: {
717*700637cbSDimitry Andric     mlir::Type dstTy = castOp.getType();
718*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
719*700637cbSDimitry Andric 
720*700637cbSDimitry Andric     assert(!MissingFeatures::cxxABI());
721*700637cbSDimitry Andric     assert(!MissingFeatures::dataMemberType());
722*700637cbSDimitry Andric 
723*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
724*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(castOp, llvmDstTy,
725*700637cbSDimitry Andric                                                        llvmSrcVal);
726*700637cbSDimitry Andric     return mlir::success();
727*700637cbSDimitry Andric   }
728*700637cbSDimitry Andric   case cir::CastKind::ptr_to_bool: {
729*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
730*700637cbSDimitry Andric     mlir::Value zeroPtr = rewriter.create<mlir::LLVM::ZeroOp>(
731*700637cbSDimitry Andric         castOp.getLoc(), llvmSrcVal.getType());
732*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
733*700637cbSDimitry Andric         castOp, mlir::LLVM::ICmpPredicate::ne, llvmSrcVal, zeroPtr);
734*700637cbSDimitry Andric     break;
735*700637cbSDimitry Andric   }
736*700637cbSDimitry Andric   case cir::CastKind::address_space: {
737*700637cbSDimitry Andric     mlir::Type dstTy = castOp.getType();
738*700637cbSDimitry Andric     mlir::Value llvmSrcVal = adaptor.getSrc();
739*700637cbSDimitry Andric     mlir::Type llvmDstTy = getTypeConverter()->convertType(dstTy);
740*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::AddrSpaceCastOp>(castOp, llvmDstTy,
741*700637cbSDimitry Andric                                                              llvmSrcVal);
742*700637cbSDimitry Andric     break;
743*700637cbSDimitry Andric   }
744*700637cbSDimitry Andric   case cir::CastKind::member_ptr_to_bool:
745*700637cbSDimitry Andric     assert(!MissingFeatures::cxxABI());
746*700637cbSDimitry Andric     assert(!MissingFeatures::methodType());
747*700637cbSDimitry Andric     break;
748*700637cbSDimitry Andric   default: {
749*700637cbSDimitry Andric     return castOp.emitError("Unhandled cast kind: ")
750*700637cbSDimitry Andric            << castOp.getKindAttrName();
751*700637cbSDimitry Andric   }
752*700637cbSDimitry Andric   }
753*700637cbSDimitry Andric 
754*700637cbSDimitry Andric   return mlir::success();
755*700637cbSDimitry Andric }
756*700637cbSDimitry Andric 
matchAndRewrite(cir::PtrStrideOp ptrStrideOp,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const757*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMPtrStrideOpLowering::matchAndRewrite(
758*700637cbSDimitry Andric     cir::PtrStrideOp ptrStrideOp, OpAdaptor adaptor,
759*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
760*700637cbSDimitry Andric 
761*700637cbSDimitry Andric   const mlir::TypeConverter *tc = getTypeConverter();
762*700637cbSDimitry Andric   const mlir::Type resultTy = tc->convertType(ptrStrideOp.getType());
763*700637cbSDimitry Andric 
764*700637cbSDimitry Andric   mlir::Type elementTy =
765*700637cbSDimitry Andric       convertTypeForMemory(*tc, dataLayout, ptrStrideOp.getElementTy());
766*700637cbSDimitry Andric   mlir::MLIRContext *ctx = elementTy.getContext();
767*700637cbSDimitry Andric 
768*700637cbSDimitry Andric   // void and function types doesn't really have a layout to use in GEPs,
769*700637cbSDimitry Andric   // make it i8 instead.
770*700637cbSDimitry Andric   if (mlir::isa<mlir::LLVM::LLVMVoidType>(elementTy) ||
771*700637cbSDimitry Andric       mlir::isa<mlir::LLVM::LLVMFunctionType>(elementTy))
772*700637cbSDimitry Andric     elementTy = mlir::IntegerType::get(elementTy.getContext(), 8,
773*700637cbSDimitry Andric                                        mlir::IntegerType::Signless);
774*700637cbSDimitry Andric   // Zero-extend, sign-extend or trunc the pointer value.
775*700637cbSDimitry Andric   mlir::Value index = adaptor.getStride();
776*700637cbSDimitry Andric   const unsigned width =
777*700637cbSDimitry Andric       mlir::cast<mlir::IntegerType>(index.getType()).getWidth();
778*700637cbSDimitry Andric   const std::optional<std::uint64_t> layoutWidth =
779*700637cbSDimitry Andric       dataLayout.getTypeIndexBitwidth(adaptor.getBase().getType());
780*700637cbSDimitry Andric 
781*700637cbSDimitry Andric   mlir::Operation *indexOp = index.getDefiningOp();
782*700637cbSDimitry Andric   if (indexOp && layoutWidth && width != *layoutWidth) {
783*700637cbSDimitry Andric     // If the index comes from a subtraction, make sure the extension happens
784*700637cbSDimitry Andric     // before it. To achieve that, look at unary minus, which already got
785*700637cbSDimitry Andric     // lowered to "sub 0, x".
786*700637cbSDimitry Andric     const auto sub = dyn_cast<mlir::LLVM::SubOp>(indexOp);
787*700637cbSDimitry Andric     auto unary = dyn_cast_if_present<cir::UnaryOp>(
788*700637cbSDimitry Andric         ptrStrideOp.getStride().getDefiningOp());
789*700637cbSDimitry Andric     bool rewriteSub =
790*700637cbSDimitry Andric         unary && unary.getKind() == cir::UnaryOpKind::Minus && sub;
791*700637cbSDimitry Andric     if (rewriteSub)
792*700637cbSDimitry Andric       index = indexOp->getOperand(1);
793*700637cbSDimitry Andric 
794*700637cbSDimitry Andric     // Handle the cast
795*700637cbSDimitry Andric     const auto llvmDstType = mlir::IntegerType::get(ctx, *layoutWidth);
796*700637cbSDimitry Andric     index = getLLVMIntCast(rewriter, index, llvmDstType,
797*700637cbSDimitry Andric                            ptrStrideOp.getStride().getType().isUnsigned(),
798*700637cbSDimitry Andric                            width, *layoutWidth);
799*700637cbSDimitry Andric 
800*700637cbSDimitry Andric     // Rewrite the sub in front of extensions/trunc
801*700637cbSDimitry Andric     if (rewriteSub) {
802*700637cbSDimitry Andric       index = rewriter.create<mlir::LLVM::SubOp>(
803*700637cbSDimitry Andric           index.getLoc(), index.getType(),
804*700637cbSDimitry Andric           rewriter.create<mlir::LLVM::ConstantOp>(index.getLoc(),
805*700637cbSDimitry Andric                                                   index.getType(), 0),
806*700637cbSDimitry Andric           index);
807*700637cbSDimitry Andric       rewriter.eraseOp(sub);
808*700637cbSDimitry Andric     }
809*700637cbSDimitry Andric   }
810*700637cbSDimitry Andric 
811*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
812*700637cbSDimitry Andric       ptrStrideOp, resultTy, elementTy, adaptor.getBase(), index);
813*700637cbSDimitry Andric   return mlir::success();
814*700637cbSDimitry Andric }
815*700637cbSDimitry Andric 
matchAndRewrite(cir::BaseClassAddrOp baseClassOp,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const816*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBaseClassAddrOpLowering::matchAndRewrite(
817*700637cbSDimitry Andric     cir::BaseClassAddrOp baseClassOp, OpAdaptor adaptor,
818*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
819*700637cbSDimitry Andric   const mlir::Type resultType =
820*700637cbSDimitry Andric       getTypeConverter()->convertType(baseClassOp.getType());
821*700637cbSDimitry Andric   mlir::Value derivedAddr = adaptor.getDerivedAddr();
822*700637cbSDimitry Andric   llvm::SmallVector<mlir::LLVM::GEPArg, 1> offset = {
823*700637cbSDimitry Andric       adaptor.getOffset().getZExtValue()};
824*700637cbSDimitry Andric   mlir::Type byteType = mlir::IntegerType::get(resultType.getContext(), 8,
825*700637cbSDimitry Andric                                                mlir::IntegerType::Signless);
826*700637cbSDimitry Andric   if (adaptor.getOffset().getZExtValue() == 0) {
827*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(
828*700637cbSDimitry Andric         baseClassOp, resultType, adaptor.getDerivedAddr());
829*700637cbSDimitry Andric     return mlir::success();
830*700637cbSDimitry Andric   }
831*700637cbSDimitry Andric 
832*700637cbSDimitry Andric   if (baseClassOp.getAssumeNotNull()) {
833*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
834*700637cbSDimitry Andric         baseClassOp, resultType, byteType, derivedAddr, offset);
835*700637cbSDimitry Andric   } else {
836*700637cbSDimitry Andric     auto loc = baseClassOp.getLoc();
837*700637cbSDimitry Andric     mlir::Value isNull = rewriter.create<mlir::LLVM::ICmpOp>(
838*700637cbSDimitry Andric         loc, mlir::LLVM::ICmpPredicate::eq, derivedAddr,
839*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ZeroOp>(loc, derivedAddr.getType()));
840*700637cbSDimitry Andric     mlir::Value adjusted = rewriter.create<mlir::LLVM::GEPOp>(
841*700637cbSDimitry Andric         loc, resultType, byteType, derivedAddr, offset);
842*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(baseClassOp, isNull,
843*700637cbSDimitry Andric                                                       derivedAddr, adjusted);
844*700637cbSDimitry Andric   }
845*700637cbSDimitry Andric   return mlir::success();
846*700637cbSDimitry Andric }
847*700637cbSDimitry Andric 
matchAndRewrite(cir::AllocaOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const848*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMAllocaOpLowering::matchAndRewrite(
849*700637cbSDimitry Andric     cir::AllocaOp op, OpAdaptor adaptor,
850*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
851*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opAllocaDynAllocSize());
852*700637cbSDimitry Andric   mlir::Value size = rewriter.create<mlir::LLVM::ConstantOp>(
853*700637cbSDimitry Andric       op.getLoc(), typeConverter->convertType(rewriter.getIndexType()), 1);
854*700637cbSDimitry Andric   mlir::Type elementTy =
855*700637cbSDimitry Andric       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getAllocaType());
856*700637cbSDimitry Andric   mlir::Type resultTy =
857*700637cbSDimitry Andric       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
858*700637cbSDimitry Andric 
859*700637cbSDimitry Andric   assert(!cir::MissingFeatures::addressSpace());
860*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opAllocaAnnotations());
861*700637cbSDimitry Andric 
862*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(
863*700637cbSDimitry Andric       op, resultTy, elementTy, size, op.getAlignmentAttr().getInt());
864*700637cbSDimitry Andric 
865*700637cbSDimitry Andric   return mlir::success();
866*700637cbSDimitry Andric }
867*700637cbSDimitry Andric 
matchAndRewrite(cir::ReturnOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const868*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMReturnOpLowering::matchAndRewrite(
869*700637cbSDimitry Andric     cir::ReturnOp op, OpAdaptor adaptor,
870*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
871*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ReturnOp>(op, adaptor.getOperands());
872*700637cbSDimitry Andric   return mlir::LogicalResult::success();
873*700637cbSDimitry Andric }
874*700637cbSDimitry Andric 
875*700637cbSDimitry Andric static mlir::LogicalResult
rewriteCallOrInvoke(mlir::Operation * op,mlir::ValueRange callOperands,mlir::ConversionPatternRewriter & rewriter,const mlir::TypeConverter * converter,mlir::FlatSymbolRefAttr calleeAttr)876*700637cbSDimitry Andric rewriteCallOrInvoke(mlir::Operation *op, mlir::ValueRange callOperands,
877*700637cbSDimitry Andric                     mlir::ConversionPatternRewriter &rewriter,
878*700637cbSDimitry Andric                     const mlir::TypeConverter *converter,
879*700637cbSDimitry Andric                     mlir::FlatSymbolRefAttr calleeAttr) {
880*700637cbSDimitry Andric   llvm::SmallVector<mlir::Type, 8> llvmResults;
881*700637cbSDimitry Andric   mlir::ValueTypeRange<mlir::ResultRange> cirResults = op->getResultTypes();
882*700637cbSDimitry Andric   auto call = cast<cir::CIRCallOpInterface>(op);
883*700637cbSDimitry Andric 
884*700637cbSDimitry Andric   if (converter->convertTypes(cirResults, llvmResults).failed())
885*700637cbSDimitry Andric     return mlir::failure();
886*700637cbSDimitry Andric 
887*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opCallCallConv());
888*700637cbSDimitry Andric 
889*700637cbSDimitry Andric   mlir::LLVM::MemoryEffectsAttr memoryEffects;
890*700637cbSDimitry Andric   bool noUnwind = false;
891*700637cbSDimitry Andric   bool willReturn = false;
892*700637cbSDimitry Andric   convertSideEffectForCall(op, call.getNothrow(), call.getSideEffect(),
893*700637cbSDimitry Andric                            memoryEffects, noUnwind, willReturn);
894*700637cbSDimitry Andric 
895*700637cbSDimitry Andric   mlir::LLVM::LLVMFunctionType llvmFnTy;
896*700637cbSDimitry Andric   if (calleeAttr) { // direct call
897*700637cbSDimitry Andric     mlir::FunctionOpInterface fn =
898*700637cbSDimitry Andric         mlir::SymbolTable::lookupNearestSymbolFrom<mlir::FunctionOpInterface>(
899*700637cbSDimitry Andric             op, calleeAttr);
900*700637cbSDimitry Andric     assert(fn && "Did not find function for call");
901*700637cbSDimitry Andric     llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
902*700637cbSDimitry Andric         converter->convertType(fn.getFunctionType()));
903*700637cbSDimitry Andric   } else { // indirect call
904*700637cbSDimitry Andric     assert(!op->getOperands().empty() &&
905*700637cbSDimitry Andric            "operands list must no be empty for the indirect call");
906*700637cbSDimitry Andric     auto calleeTy = op->getOperands().front().getType();
907*700637cbSDimitry Andric     auto calleePtrTy = cast<cir::PointerType>(calleeTy);
908*700637cbSDimitry Andric     auto calleeFuncTy = cast<cir::FuncType>(calleePtrTy.getPointee());
909*700637cbSDimitry Andric     calleeFuncTy.dump();
910*700637cbSDimitry Andric     converter->convertType(calleeFuncTy).dump();
911*700637cbSDimitry Andric     llvmFnTy = cast<mlir::LLVM::LLVMFunctionType>(
912*700637cbSDimitry Andric         converter->convertType(calleeFuncTy));
913*700637cbSDimitry Andric   }
914*700637cbSDimitry Andric 
915*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opCallLandingPad());
916*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opCallContinueBlock());
917*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opCallCallConv());
918*700637cbSDimitry Andric 
919*700637cbSDimitry Andric   auto newOp = rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
920*700637cbSDimitry Andric       op, llvmFnTy, calleeAttr, callOperands);
921*700637cbSDimitry Andric   if (memoryEffects)
922*700637cbSDimitry Andric     newOp.setMemoryEffectsAttr(memoryEffects);
923*700637cbSDimitry Andric   newOp.setNoUnwind(noUnwind);
924*700637cbSDimitry Andric   newOp.setWillReturn(willReturn);
925*700637cbSDimitry Andric 
926*700637cbSDimitry Andric   return mlir::success();
927*700637cbSDimitry Andric }
928*700637cbSDimitry Andric 
matchAndRewrite(cir::CallOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const929*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMCallOpLowering::matchAndRewrite(
930*700637cbSDimitry Andric     cir::CallOp op, OpAdaptor adaptor,
931*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
932*700637cbSDimitry Andric   return rewriteCallOrInvoke(op.getOperation(), adaptor.getOperands(), rewriter,
933*700637cbSDimitry Andric                              getTypeConverter(), op.getCalleeAttr());
934*700637cbSDimitry Andric }
935*700637cbSDimitry Andric 
matchAndRewrite(cir::LoadOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const936*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMLoadOpLowering::matchAndRewrite(
937*700637cbSDimitry Andric     cir::LoadOp op, OpAdaptor adaptor,
938*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
939*700637cbSDimitry Andric   const mlir::Type llvmTy =
940*700637cbSDimitry Andric       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getType());
941*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreMemOrder());
942*700637cbSDimitry Andric   std::optional<size_t> opAlign = op.getAlignment();
943*700637cbSDimitry Andric   unsigned alignment =
944*700637cbSDimitry Andric       (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));
945*700637cbSDimitry Andric 
946*700637cbSDimitry Andric   assert(!cir::MissingFeatures::lowerModeOptLevel());
947*700637cbSDimitry Andric 
948*700637cbSDimitry Andric   // TODO: nontemporal, syncscope.
949*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreVolatile());
950*700637cbSDimitry Andric   mlir::LLVM::LoadOp newLoad = rewriter.create<mlir::LLVM::LoadOp>(
951*700637cbSDimitry Andric       op->getLoc(), llvmTy, adaptor.getAddr(), alignment,
952*700637cbSDimitry Andric       /*volatile=*/false, /*nontemporal=*/false,
953*700637cbSDimitry Andric       /*invariant=*/false, /*invariantGroup=*/false,
954*700637cbSDimitry Andric       mlir::LLVM::AtomicOrdering::not_atomic);
955*700637cbSDimitry Andric 
956*700637cbSDimitry Andric   // Convert adapted result to its original type if needed.
957*700637cbSDimitry Andric   mlir::Value result =
958*700637cbSDimitry Andric       emitFromMemory(rewriter, dataLayout, op, newLoad.getResult());
959*700637cbSDimitry Andric   rewriter.replaceOp(op, result);
960*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreTbaa());
961*700637cbSDimitry Andric   return mlir::LogicalResult::success();
962*700637cbSDimitry Andric }
963*700637cbSDimitry Andric 
matchAndRewrite(cir::StoreOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const964*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMStoreOpLowering::matchAndRewrite(
965*700637cbSDimitry Andric     cir::StoreOp op, OpAdaptor adaptor,
966*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
967*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreMemOrder());
968*700637cbSDimitry Andric   const mlir::Type llvmTy =
969*700637cbSDimitry Andric       getTypeConverter()->convertType(op.getValue().getType());
970*700637cbSDimitry Andric   std::optional<size_t> opAlign = op.getAlignment();
971*700637cbSDimitry Andric   unsigned alignment =
972*700637cbSDimitry Andric       (unsigned)opAlign.value_or(dataLayout.getTypeABIAlignment(llvmTy));
973*700637cbSDimitry Andric 
974*700637cbSDimitry Andric   assert(!cir::MissingFeatures::lowerModeOptLevel());
975*700637cbSDimitry Andric 
976*700637cbSDimitry Andric   // Convert adapted value to its memory type if needed.
977*700637cbSDimitry Andric   mlir::Value value = emitToMemory(rewriter, dataLayout,
978*700637cbSDimitry Andric                                    op.getValue().getType(), adaptor.getValue());
979*700637cbSDimitry Andric   // TODO: nontemporal, syncscope.
980*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreVolatile());
981*700637cbSDimitry Andric   mlir::LLVM::StoreOp storeOp = rewriter.create<mlir::LLVM::StoreOp>(
982*700637cbSDimitry Andric       op->getLoc(), value, adaptor.getAddr(), alignment, /*volatile=*/false,
983*700637cbSDimitry Andric       /*nontemporal=*/false, /*invariantGroup=*/false,
984*700637cbSDimitry Andric       mlir::LLVM::AtomicOrdering::not_atomic);
985*700637cbSDimitry Andric   rewriter.replaceOp(op, storeOp);
986*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opLoadStoreTbaa());
987*700637cbSDimitry Andric   return mlir::LogicalResult::success();
988*700637cbSDimitry Andric }
989*700637cbSDimitry Andric 
hasTrailingZeros(cir::ConstArrayAttr attr)990*700637cbSDimitry Andric bool hasTrailingZeros(cir::ConstArrayAttr attr) {
991*700637cbSDimitry Andric   auto array = mlir::dyn_cast<mlir::ArrayAttr>(attr.getElts());
992*700637cbSDimitry Andric   return attr.hasTrailingZeros() ||
993*700637cbSDimitry Andric          (array && std::count_if(array.begin(), array.end(), [](auto elt) {
994*700637cbSDimitry Andric             auto ar = dyn_cast<cir::ConstArrayAttr>(elt);
995*700637cbSDimitry Andric             return ar && hasTrailingZeros(ar);
996*700637cbSDimitry Andric           }));
997*700637cbSDimitry Andric }
998*700637cbSDimitry Andric 
matchAndRewrite(cir::ConstantOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const999*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMConstantOpLowering::matchAndRewrite(
1000*700637cbSDimitry Andric     cir::ConstantOp op, OpAdaptor adaptor,
1001*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1002*700637cbSDimitry Andric   mlir::Attribute attr = op.getValue();
1003*700637cbSDimitry Andric 
1004*700637cbSDimitry Andric   if (mlir::isa<mlir::IntegerType>(op.getType())) {
1005*700637cbSDimitry Andric     // Verified cir.const operations cannot actually be of these types, but the
1006*700637cbSDimitry Andric     // lowering pass may generate temporary cir.const operations with these
1007*700637cbSDimitry Andric     // types. This is OK since MLIR allows unverified operations to be alive
1008*700637cbSDimitry Andric     // during a pass as long as they don't live past the end of the pass.
1009*700637cbSDimitry Andric     attr = op.getValue();
1010*700637cbSDimitry Andric   } else if (mlir::isa<cir::BoolType>(op.getType())) {
1011*700637cbSDimitry Andric     int value = mlir::cast<cir::BoolAttr>(op.getValue()).getValue();
1012*700637cbSDimitry Andric     attr = rewriter.getIntegerAttr(typeConverter->convertType(op.getType()),
1013*700637cbSDimitry Andric                                    value);
1014*700637cbSDimitry Andric   } else if (mlir::isa<cir::IntType>(op.getType())) {
1015*700637cbSDimitry Andric     assert(!cir::MissingFeatures::opGlobalViewAttr());
1016*700637cbSDimitry Andric 
1017*700637cbSDimitry Andric     attr = rewriter.getIntegerAttr(
1018*700637cbSDimitry Andric         typeConverter->convertType(op.getType()),
1019*700637cbSDimitry Andric         mlir::cast<cir::IntAttr>(op.getValue()).getValue());
1020*700637cbSDimitry Andric   } else if (mlir::isa<cir::FPTypeInterface>(op.getType())) {
1021*700637cbSDimitry Andric     attr = rewriter.getFloatAttr(
1022*700637cbSDimitry Andric         typeConverter->convertType(op.getType()),
1023*700637cbSDimitry Andric         mlir::cast<cir::FPAttr>(op.getValue()).getValue());
1024*700637cbSDimitry Andric   } else if (mlir::isa<cir::PointerType>(op.getType())) {
1025*700637cbSDimitry Andric     // Optimize with dedicated LLVM op for null pointers.
1026*700637cbSDimitry Andric     if (mlir::isa<cir::ConstPtrAttr>(op.getValue())) {
1027*700637cbSDimitry Andric       if (mlir::cast<cir::ConstPtrAttr>(op.getValue()).isNullValue()) {
1028*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::ZeroOp>(
1029*700637cbSDimitry Andric             op, typeConverter->convertType(op.getType()));
1030*700637cbSDimitry Andric         return mlir::success();
1031*700637cbSDimitry Andric       }
1032*700637cbSDimitry Andric     }
1033*700637cbSDimitry Andric     assert(!cir::MissingFeatures::opGlobalViewAttr());
1034*700637cbSDimitry Andric     attr = op.getValue();
1035*700637cbSDimitry Andric   } else if (const auto arrTy = mlir::dyn_cast<cir::ArrayType>(op.getType())) {
1036*700637cbSDimitry Andric     const auto constArr = mlir::dyn_cast<cir::ConstArrayAttr>(op.getValue());
1037*700637cbSDimitry Andric     if (!constArr && !isa<cir::ZeroAttr, cir::UndefAttr>(op.getValue()))
1038*700637cbSDimitry Andric       return op.emitError() << "array does not have a constant initializer";
1039*700637cbSDimitry Andric 
1040*700637cbSDimitry Andric     std::optional<mlir::Attribute> denseAttr;
1041*700637cbSDimitry Andric     if (constArr && hasTrailingZeros(constArr)) {
1042*700637cbSDimitry Andric       const mlir::Value newOp =
1043*700637cbSDimitry Andric           lowerCirAttrAsValue(op, constArr, rewriter, getTypeConverter());
1044*700637cbSDimitry Andric       rewriter.replaceOp(op, newOp);
1045*700637cbSDimitry Andric       return mlir::success();
1046*700637cbSDimitry Andric     } else if (constArr &&
1047*700637cbSDimitry Andric                (denseAttr = lowerConstArrayAttr(constArr, typeConverter))) {
1048*700637cbSDimitry Andric       attr = denseAttr.value();
1049*700637cbSDimitry Andric     } else {
1050*700637cbSDimitry Andric       const mlir::Value initVal =
1051*700637cbSDimitry Andric           lowerCirAttrAsValue(op, op.getValue(), rewriter, typeConverter);
1052*700637cbSDimitry Andric       rewriter.replaceAllUsesWith(op, initVal);
1053*700637cbSDimitry Andric       rewriter.eraseOp(op);
1054*700637cbSDimitry Andric       return mlir::success();
1055*700637cbSDimitry Andric     }
1056*700637cbSDimitry Andric   } else if (const auto vecTy = mlir::dyn_cast<cir::VectorType>(op.getType())) {
1057*700637cbSDimitry Andric     rewriter.replaceOp(op, lowerCirAttrAsValue(op, op.getValue(), rewriter,
1058*700637cbSDimitry Andric                                                getTypeConverter()));
1059*700637cbSDimitry Andric     return mlir::success();
1060*700637cbSDimitry Andric   } else if (auto complexTy = mlir::dyn_cast<cir::ComplexType>(op.getType())) {
1061*700637cbSDimitry Andric     mlir::Type complexElemTy = complexTy.getElementType();
1062*700637cbSDimitry Andric     mlir::Type complexElemLLVMTy = typeConverter->convertType(complexElemTy);
1063*700637cbSDimitry Andric 
1064*700637cbSDimitry Andric     if (auto zeroInitAttr = mlir::dyn_cast<cir::ZeroAttr>(op.getValue())) {
1065*700637cbSDimitry Andric       mlir::TypedAttr zeroAttr = rewriter.getZeroAttr(complexElemLLVMTy);
1066*700637cbSDimitry Andric       mlir::ArrayAttr array = rewriter.getArrayAttr({zeroAttr, zeroAttr});
1067*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1068*700637cbSDimitry Andric           op, getTypeConverter()->convertType(op.getType()), array);
1069*700637cbSDimitry Andric       return mlir::success();
1070*700637cbSDimitry Andric     }
1071*700637cbSDimitry Andric 
1072*700637cbSDimitry Andric     auto complexAttr = mlir::cast<cir::ConstComplexAttr>(op.getValue());
1073*700637cbSDimitry Andric 
1074*700637cbSDimitry Andric     mlir::Attribute components[2];
1075*700637cbSDimitry Andric     if (mlir::isa<cir::IntType>(complexElemTy)) {
1076*700637cbSDimitry Andric       components[0] = rewriter.getIntegerAttr(
1077*700637cbSDimitry Andric           complexElemLLVMTy,
1078*700637cbSDimitry Andric           mlir::cast<cir::IntAttr>(complexAttr.getReal()).getValue());
1079*700637cbSDimitry Andric       components[1] = rewriter.getIntegerAttr(
1080*700637cbSDimitry Andric           complexElemLLVMTy,
1081*700637cbSDimitry Andric           mlir::cast<cir::IntAttr>(complexAttr.getImag()).getValue());
1082*700637cbSDimitry Andric     } else {
1083*700637cbSDimitry Andric       components[0] = rewriter.getFloatAttr(
1084*700637cbSDimitry Andric           complexElemLLVMTy,
1085*700637cbSDimitry Andric           mlir::cast<cir::FPAttr>(complexAttr.getReal()).getValue());
1086*700637cbSDimitry Andric       components[1] = rewriter.getFloatAttr(
1087*700637cbSDimitry Andric           complexElemLLVMTy,
1088*700637cbSDimitry Andric           mlir::cast<cir::FPAttr>(complexAttr.getImag()).getValue());
1089*700637cbSDimitry Andric     }
1090*700637cbSDimitry Andric 
1091*700637cbSDimitry Andric     attr = rewriter.getArrayAttr(components);
1092*700637cbSDimitry Andric   } else {
1093*700637cbSDimitry Andric     return op.emitError() << "unsupported constant type " << op.getType();
1094*700637cbSDimitry Andric   }
1095*700637cbSDimitry Andric 
1096*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
1097*700637cbSDimitry Andric       op, getTypeConverter()->convertType(op.getType()), attr);
1098*700637cbSDimitry Andric 
1099*700637cbSDimitry Andric   return mlir::success();
1100*700637cbSDimitry Andric }
1101*700637cbSDimitry Andric 
matchAndRewrite(cir::ExpectOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1102*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMExpectOpLowering::matchAndRewrite(
1103*700637cbSDimitry Andric     cir::ExpectOp op, OpAdaptor adaptor,
1104*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1105*700637cbSDimitry Andric   // TODO(cir): do not generate LLVM intrinsics under -O0
1106*700637cbSDimitry Andric   assert(!cir::MissingFeatures::optInfoAttr());
1107*700637cbSDimitry Andric 
1108*700637cbSDimitry Andric   std::optional<llvm::APFloat> prob = op.getProb();
1109*700637cbSDimitry Andric   if (prob)
1110*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectWithProbabilityOp>(
1111*700637cbSDimitry Andric         op, adaptor.getVal(), adaptor.getExpected(), prob.value());
1112*700637cbSDimitry Andric   else
1113*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ExpectOp>(op, adaptor.getVal(),
1114*700637cbSDimitry Andric                                                       adaptor.getExpected());
1115*700637cbSDimitry Andric   return mlir::success();
1116*700637cbSDimitry Andric }
1117*700637cbSDimitry Andric 
1118*700637cbSDimitry Andric /// Convert the `cir.func` attributes to `llvm.func` attributes.
1119*700637cbSDimitry Andric /// Only retain those attributes that are not constructed by
1120*700637cbSDimitry Andric /// `LLVMFuncOp::build`. If `filterArgAttrs` is set, also filter out
1121*700637cbSDimitry Andric /// argument attributes.
lowerFuncAttributes(cir::FuncOp func,bool filterArgAndResAttrs,SmallVectorImpl<mlir::NamedAttribute> & result) const1122*700637cbSDimitry Andric void CIRToLLVMFuncOpLowering::lowerFuncAttributes(
1123*700637cbSDimitry Andric     cir::FuncOp func, bool filterArgAndResAttrs,
1124*700637cbSDimitry Andric     SmallVectorImpl<mlir::NamedAttribute> &result) const {
1125*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opFuncCallingConv());
1126*700637cbSDimitry Andric   for (mlir::NamedAttribute attr : func->getAttrs()) {
1127*700637cbSDimitry Andric     assert(!cir::MissingFeatures::opFuncCallingConv());
1128*700637cbSDimitry Andric     if (attr.getName() == mlir::SymbolTable::getSymbolAttrName() ||
1129*700637cbSDimitry Andric         attr.getName() == func.getFunctionTypeAttrName() ||
1130*700637cbSDimitry Andric         attr.getName() == getLinkageAttrNameString() ||
1131*700637cbSDimitry Andric         attr.getName() == func.getGlobalVisibilityAttrName() ||
1132*700637cbSDimitry Andric         attr.getName() == func.getDsoLocalAttrName() ||
1133*700637cbSDimitry Andric         (filterArgAndResAttrs &&
1134*700637cbSDimitry Andric          (attr.getName() == func.getArgAttrsAttrName() ||
1135*700637cbSDimitry Andric           attr.getName() == func.getResAttrsAttrName())))
1136*700637cbSDimitry Andric       continue;
1137*700637cbSDimitry Andric 
1138*700637cbSDimitry Andric     assert(!cir::MissingFeatures::opFuncExtraAttrs());
1139*700637cbSDimitry Andric     result.push_back(attr);
1140*700637cbSDimitry Andric   }
1141*700637cbSDimitry Andric }
1142*700637cbSDimitry Andric 
matchAndRewrite(cir::FuncOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1143*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMFuncOpLowering::matchAndRewrite(
1144*700637cbSDimitry Andric     cir::FuncOp op, OpAdaptor adaptor,
1145*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1146*700637cbSDimitry Andric 
1147*700637cbSDimitry Andric   cir::FuncType fnType = op.getFunctionType();
1148*700637cbSDimitry Andric   bool isDsoLocal = op.getDsoLocal();
1149*700637cbSDimitry Andric   mlir::TypeConverter::SignatureConversion signatureConversion(
1150*700637cbSDimitry Andric       fnType.getNumInputs());
1151*700637cbSDimitry Andric 
1152*700637cbSDimitry Andric   for (const auto &argType : llvm::enumerate(fnType.getInputs())) {
1153*700637cbSDimitry Andric     mlir::Type convertedType = typeConverter->convertType(argType.value());
1154*700637cbSDimitry Andric     if (!convertedType)
1155*700637cbSDimitry Andric       return mlir::failure();
1156*700637cbSDimitry Andric     signatureConversion.addInputs(argType.index(), convertedType);
1157*700637cbSDimitry Andric   }
1158*700637cbSDimitry Andric 
1159*700637cbSDimitry Andric   mlir::Type resultType =
1160*700637cbSDimitry Andric       getTypeConverter()->convertType(fnType.getReturnType());
1161*700637cbSDimitry Andric 
1162*700637cbSDimitry Andric   // Create the LLVM function operation.
1163*700637cbSDimitry Andric   mlir::Type llvmFnTy = mlir::LLVM::LLVMFunctionType::get(
1164*700637cbSDimitry Andric       resultType ? resultType : mlir::LLVM::LLVMVoidType::get(getContext()),
1165*700637cbSDimitry Andric       signatureConversion.getConvertedTypes(),
1166*700637cbSDimitry Andric       /*isVarArg=*/fnType.isVarArg());
1167*700637cbSDimitry Andric   // LLVMFuncOp expects a single FileLine Location instead of a fused
1168*700637cbSDimitry Andric   // location.
1169*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
1170*700637cbSDimitry Andric   if (mlir::FusedLoc fusedLoc = mlir::dyn_cast<mlir::FusedLoc>(loc))
1171*700637cbSDimitry Andric     loc = fusedLoc.getLocations()[0];
1172*700637cbSDimitry Andric   assert((mlir::isa<mlir::FileLineColLoc>(loc) ||
1173*700637cbSDimitry Andric           mlir::isa<mlir::UnknownLoc>(loc)) &&
1174*700637cbSDimitry Andric          "expected single location or unknown location here");
1175*700637cbSDimitry Andric 
1176*700637cbSDimitry Andric   mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
1177*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opFuncCallingConv());
1178*700637cbSDimitry Andric   mlir::LLVM::CConv cconv = mlir::LLVM::CConv::C;
1179*700637cbSDimitry Andric   SmallVector<mlir::NamedAttribute, 4> attributes;
1180*700637cbSDimitry Andric   lowerFuncAttributes(op, /*filterArgAndResAttrs=*/false, attributes);
1181*700637cbSDimitry Andric 
1182*700637cbSDimitry Andric   mlir::LLVM::LLVMFuncOp fn = rewriter.create<mlir::LLVM::LLVMFuncOp>(
1183*700637cbSDimitry Andric       loc, op.getName(), llvmFnTy, linkage, isDsoLocal, cconv,
1184*700637cbSDimitry Andric       mlir::SymbolRefAttr(), attributes);
1185*700637cbSDimitry Andric 
1186*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opFuncMultipleReturnVals());
1187*700637cbSDimitry Andric 
1188*700637cbSDimitry Andric   fn.setVisibility_Attr(mlir::LLVM::VisibilityAttr::get(
1189*700637cbSDimitry Andric       getContext(), lowerCIRVisibilityToLLVMVisibility(
1190*700637cbSDimitry Andric                         op.getGlobalVisibilityAttr().getValue())));
1191*700637cbSDimitry Andric 
1192*700637cbSDimitry Andric   rewriter.inlineRegionBefore(op.getBody(), fn.getBody(), fn.end());
1193*700637cbSDimitry Andric   if (failed(rewriter.convertRegionTypes(&fn.getBody(), *typeConverter,
1194*700637cbSDimitry Andric                                          &signatureConversion)))
1195*700637cbSDimitry Andric     return mlir::failure();
1196*700637cbSDimitry Andric 
1197*700637cbSDimitry Andric   rewriter.eraseOp(op);
1198*700637cbSDimitry Andric 
1199*700637cbSDimitry Andric   return mlir::LogicalResult::success();
1200*700637cbSDimitry Andric }
1201*700637cbSDimitry Andric 
matchAndRewrite(cir::GetGlobalOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1202*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMGetGlobalOpLowering::matchAndRewrite(
1203*700637cbSDimitry Andric     cir::GetGlobalOp op, OpAdaptor adaptor,
1204*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1205*700637cbSDimitry Andric   // FIXME(cir): Premature DCE to avoid lowering stuff we're not using.
1206*700637cbSDimitry Andric   // CIRGen should mitigate this and not emit the get_global.
1207*700637cbSDimitry Andric   if (op->getUses().empty()) {
1208*700637cbSDimitry Andric     rewriter.eraseOp(op);
1209*700637cbSDimitry Andric     return mlir::success();
1210*700637cbSDimitry Andric   }
1211*700637cbSDimitry Andric 
1212*700637cbSDimitry Andric   mlir::Type type = getTypeConverter()->convertType(op.getType());
1213*700637cbSDimitry Andric   mlir::Operation *newop =
1214*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::AddressOfOp>(op.getLoc(), type, op.getName());
1215*700637cbSDimitry Andric 
1216*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalThreadLocal());
1217*700637cbSDimitry Andric 
1218*700637cbSDimitry Andric   rewriter.replaceOp(op, newop);
1219*700637cbSDimitry Andric   return mlir::success();
1220*700637cbSDimitry Andric }
1221*700637cbSDimitry Andric 
1222*700637cbSDimitry Andric /// Replace CIR global with a region initialized LLVM global and update
1223*700637cbSDimitry Andric /// insertion point to the end of the initializer block.
setupRegionInitializedLLVMGlobalOp(cir::GlobalOp op,mlir::ConversionPatternRewriter & rewriter) const1224*700637cbSDimitry Andric void CIRToLLVMGlobalOpLowering::setupRegionInitializedLLVMGlobalOp(
1225*700637cbSDimitry Andric     cir::GlobalOp op, mlir::ConversionPatternRewriter &rewriter) const {
1226*700637cbSDimitry Andric   const mlir::Type llvmType =
1227*700637cbSDimitry Andric       convertTypeForMemory(*getTypeConverter(), dataLayout, op.getSymType());
1228*700637cbSDimitry Andric 
1229*700637cbSDimitry Andric   // FIXME: These default values are placeholders until the the equivalent
1230*700637cbSDimitry Andric   //        attributes are available on cir.global ops. This duplicates code
1231*700637cbSDimitry Andric   //        in CIRToLLVMGlobalOpLowering::matchAndRewrite() but that will go
1232*700637cbSDimitry Andric   //        away when the placeholders are no longer needed.
1233*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalConstant());
1234*700637cbSDimitry Andric   const bool isConst = false;
1235*700637cbSDimitry Andric   assert(!cir::MissingFeatures::addressSpace());
1236*700637cbSDimitry Andric   const unsigned addrSpace = 0;
1237*700637cbSDimitry Andric   const bool isDsoLocal = op.getDsoLocal();
1238*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalThreadLocal());
1239*700637cbSDimitry Andric   const bool isThreadLocal = false;
1240*700637cbSDimitry Andric   const uint64_t alignment = op.getAlignment().value_or(0);
1241*700637cbSDimitry Andric   const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
1242*700637cbSDimitry Andric   const StringRef symbol = op.getSymName();
1243*700637cbSDimitry Andric   mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
1244*700637cbSDimitry Andric 
1245*700637cbSDimitry Andric   SmallVector<mlir::NamedAttribute> attributes;
1246*700637cbSDimitry Andric   mlir::LLVM::GlobalOp newGlobalOp =
1247*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
1248*700637cbSDimitry Andric           op, llvmType, isConst, linkage, symbol, nullptr, alignment, addrSpace,
1249*700637cbSDimitry Andric           isDsoLocal, isThreadLocal, comdatAttr, attributes);
1250*700637cbSDimitry Andric   newGlobalOp.getRegion().emplaceBlock();
1251*700637cbSDimitry Andric   rewriter.setInsertionPointToEnd(newGlobalOp.getInitializerBlock());
1252*700637cbSDimitry Andric }
1253*700637cbSDimitry Andric 
1254*700637cbSDimitry Andric mlir::LogicalResult
matchAndRewriteRegionInitializedGlobal(cir::GlobalOp op,mlir::Attribute init,mlir::ConversionPatternRewriter & rewriter) const1255*700637cbSDimitry Andric CIRToLLVMGlobalOpLowering::matchAndRewriteRegionInitializedGlobal(
1256*700637cbSDimitry Andric     cir::GlobalOp op, mlir::Attribute init,
1257*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1258*700637cbSDimitry Andric   // TODO: Generalize this handling when more types are needed here.
1259*700637cbSDimitry Andric   assert((isa<cir::ConstArrayAttr, cir::ConstVectorAttr, cir::ConstPtrAttr,
1260*700637cbSDimitry Andric               cir::ConstComplexAttr, cir::ZeroAttr>(init)));
1261*700637cbSDimitry Andric 
1262*700637cbSDimitry Andric   // TODO(cir): once LLVM's dialect has proper equivalent attributes this
1263*700637cbSDimitry Andric   // should be updated. For now, we use a custom op to initialize globals
1264*700637cbSDimitry Andric   // to the appropriate value.
1265*700637cbSDimitry Andric   const mlir::Location loc = op.getLoc();
1266*700637cbSDimitry Andric   setupRegionInitializedLLVMGlobalOp(op, rewriter);
1267*700637cbSDimitry Andric   CIRAttrToValue valueConverter(op, rewriter, typeConverter);
1268*700637cbSDimitry Andric   mlir::Value value = valueConverter.visit(init);
1269*700637cbSDimitry Andric   rewriter.create<mlir::LLVM::ReturnOp>(loc, value);
1270*700637cbSDimitry Andric   return mlir::success();
1271*700637cbSDimitry Andric }
1272*700637cbSDimitry Andric 
matchAndRewrite(cir::GlobalOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1273*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMGlobalOpLowering::matchAndRewrite(
1274*700637cbSDimitry Andric     cir::GlobalOp op, OpAdaptor adaptor,
1275*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1276*700637cbSDimitry Andric 
1277*700637cbSDimitry Andric   std::optional<mlir::Attribute> init = op.getInitialValue();
1278*700637cbSDimitry Andric 
1279*700637cbSDimitry Andric   // Fetch required values to create LLVM op.
1280*700637cbSDimitry Andric   const mlir::Type cirSymType = op.getSymType();
1281*700637cbSDimitry Andric 
1282*700637cbSDimitry Andric   // This is the LLVM dialect type.
1283*700637cbSDimitry Andric   const mlir::Type llvmType =
1284*700637cbSDimitry Andric       convertTypeForMemory(*getTypeConverter(), dataLayout, cirSymType);
1285*700637cbSDimitry Andric   // FIXME: These default values are placeholders until the the equivalent
1286*700637cbSDimitry Andric   //        attributes are available on cir.global ops.
1287*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalConstant());
1288*700637cbSDimitry Andric   const bool isConst = false;
1289*700637cbSDimitry Andric   assert(!cir::MissingFeatures::addressSpace());
1290*700637cbSDimitry Andric   const unsigned addrSpace = 0;
1291*700637cbSDimitry Andric   const bool isDsoLocal = op.getDsoLocal();
1292*700637cbSDimitry Andric   assert(!cir::MissingFeatures::opGlobalThreadLocal());
1293*700637cbSDimitry Andric   const bool isThreadLocal = false;
1294*700637cbSDimitry Andric   const uint64_t alignment = op.getAlignment().value_or(0);
1295*700637cbSDimitry Andric   const mlir::LLVM::Linkage linkage = convertLinkage(op.getLinkage());
1296*700637cbSDimitry Andric   const StringRef symbol = op.getSymName();
1297*700637cbSDimitry Andric   SmallVector<mlir::NamedAttribute> attributes;
1298*700637cbSDimitry Andric   mlir::SymbolRefAttr comdatAttr = getComdatAttr(op, rewriter);
1299*700637cbSDimitry Andric 
1300*700637cbSDimitry Andric   if (init.has_value()) {
1301*700637cbSDimitry Andric     if (mlir::isa<cir::FPAttr, cir::IntAttr, cir::BoolAttr>(init.value())) {
1302*700637cbSDimitry Andric       GlobalInitAttrRewriter initRewriter(llvmType, rewriter);
1303*700637cbSDimitry Andric       init = initRewriter.visit(init.value());
1304*700637cbSDimitry Andric       // If initRewriter returned a null attribute, init will have a value but
1305*700637cbSDimitry Andric       // the value will be null. If that happens, initRewriter didn't handle the
1306*700637cbSDimitry Andric       // attribute type. It probably needs to be added to
1307*700637cbSDimitry Andric       // GlobalInitAttrRewriter.
1308*700637cbSDimitry Andric       if (!init.value()) {
1309*700637cbSDimitry Andric         op.emitError() << "unsupported initializer '" << init.value() << "'";
1310*700637cbSDimitry Andric         return mlir::failure();
1311*700637cbSDimitry Andric       }
1312*700637cbSDimitry Andric     } else if (mlir::isa<cir::ConstArrayAttr, cir::ConstVectorAttr,
1313*700637cbSDimitry Andric                          cir::ConstPtrAttr, cir::ConstComplexAttr,
1314*700637cbSDimitry Andric                          cir::ZeroAttr>(init.value())) {
1315*700637cbSDimitry Andric       // TODO(cir): once LLVM's dialect has proper equivalent attributes this
1316*700637cbSDimitry Andric       // should be updated. For now, we use a custom op to initialize globals
1317*700637cbSDimitry Andric       // to the appropriate value.
1318*700637cbSDimitry Andric       return matchAndRewriteRegionInitializedGlobal(op, init.value(), rewriter);
1319*700637cbSDimitry Andric     } else {
1320*700637cbSDimitry Andric       // We will only get here if new initializer types are added and this
1321*700637cbSDimitry Andric       // code is not updated to handle them.
1322*700637cbSDimitry Andric       op.emitError() << "unsupported initializer '" << init.value() << "'";
1323*700637cbSDimitry Andric       return mlir::failure();
1324*700637cbSDimitry Andric     }
1325*700637cbSDimitry Andric   }
1326*700637cbSDimitry Andric 
1327*700637cbSDimitry Andric   // Rewrite op.
1328*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::GlobalOp>(
1329*700637cbSDimitry Andric       op, llvmType, isConst, linkage, symbol, init.value_or(mlir::Attribute()),
1330*700637cbSDimitry Andric       alignment, addrSpace, isDsoLocal, isThreadLocal, comdatAttr, attributes);
1331*700637cbSDimitry Andric   return mlir::success();
1332*700637cbSDimitry Andric }
1333*700637cbSDimitry Andric 
1334*700637cbSDimitry Andric mlir::SymbolRefAttr
getComdatAttr(cir::GlobalOp & op,mlir::OpBuilder & builder) const1335*700637cbSDimitry Andric CIRToLLVMGlobalOpLowering::getComdatAttr(cir::GlobalOp &op,
1336*700637cbSDimitry Andric                                          mlir::OpBuilder &builder) const {
1337*700637cbSDimitry Andric   if (!op.getComdat())
1338*700637cbSDimitry Andric     return mlir::SymbolRefAttr{};
1339*700637cbSDimitry Andric 
1340*700637cbSDimitry Andric   mlir::ModuleOp module = op->getParentOfType<mlir::ModuleOp>();
1341*700637cbSDimitry Andric   mlir::OpBuilder::InsertionGuard guard(builder);
1342*700637cbSDimitry Andric   StringRef comdatName("__llvm_comdat_globals");
1343*700637cbSDimitry Andric   if (!comdatOp) {
1344*700637cbSDimitry Andric     builder.setInsertionPointToStart(module.getBody());
1345*700637cbSDimitry Andric     comdatOp =
1346*700637cbSDimitry Andric         builder.create<mlir::LLVM::ComdatOp>(module.getLoc(), comdatName);
1347*700637cbSDimitry Andric   }
1348*700637cbSDimitry Andric 
1349*700637cbSDimitry Andric   builder.setInsertionPointToStart(&comdatOp.getBody().back());
1350*700637cbSDimitry Andric   auto selectorOp = builder.create<mlir::LLVM::ComdatSelectorOp>(
1351*700637cbSDimitry Andric       comdatOp.getLoc(), op.getSymName(), mlir::LLVM::comdat::Comdat::Any);
1352*700637cbSDimitry Andric   return mlir::SymbolRefAttr::get(
1353*700637cbSDimitry Andric       builder.getContext(), comdatName,
1354*700637cbSDimitry Andric       mlir::FlatSymbolRefAttr::get(selectorOp.getSymNameAttr()));
1355*700637cbSDimitry Andric }
1356*700637cbSDimitry Andric 
matchAndRewrite(cir::SwitchFlatOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1357*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMSwitchFlatOpLowering::matchAndRewrite(
1358*700637cbSDimitry Andric     cir::SwitchFlatOp op, OpAdaptor adaptor,
1359*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1360*700637cbSDimitry Andric 
1361*700637cbSDimitry Andric   llvm::SmallVector<mlir::APInt, 8> caseValues;
1362*700637cbSDimitry Andric   for (mlir::Attribute val : op.getCaseValues()) {
1363*700637cbSDimitry Andric     auto intAttr = cast<cir::IntAttr>(val);
1364*700637cbSDimitry Andric     caseValues.push_back(intAttr.getValue());
1365*700637cbSDimitry Andric   }
1366*700637cbSDimitry Andric 
1367*700637cbSDimitry Andric   llvm::SmallVector<mlir::Block *, 8> caseDestinations;
1368*700637cbSDimitry Andric   llvm::SmallVector<mlir::ValueRange, 8> caseOperands;
1369*700637cbSDimitry Andric 
1370*700637cbSDimitry Andric   for (mlir::Block *x : op.getCaseDestinations())
1371*700637cbSDimitry Andric     caseDestinations.push_back(x);
1372*700637cbSDimitry Andric 
1373*700637cbSDimitry Andric   for (mlir::OperandRange x : op.getCaseOperands())
1374*700637cbSDimitry Andric     caseOperands.push_back(x);
1375*700637cbSDimitry Andric 
1376*700637cbSDimitry Andric   // Set switch op to branch to the newly created blocks.
1377*700637cbSDimitry Andric   rewriter.setInsertionPoint(op);
1378*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
1379*700637cbSDimitry Andric       op, adaptor.getCondition(), op.getDefaultDestination(),
1380*700637cbSDimitry Andric       op.getDefaultOperands(), caseValues, caseDestinations, caseOperands);
1381*700637cbSDimitry Andric   return mlir::success();
1382*700637cbSDimitry Andric }
1383*700637cbSDimitry Andric 
matchAndRewrite(cir::UnaryOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1384*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMUnaryOpLowering::matchAndRewrite(
1385*700637cbSDimitry Andric     cir::UnaryOp op, OpAdaptor adaptor,
1386*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1387*700637cbSDimitry Andric   assert(op.getType() == op.getInput().getType() &&
1388*700637cbSDimitry Andric          "Unary operation's operand type and result type are different");
1389*700637cbSDimitry Andric   mlir::Type type = op.getType();
1390*700637cbSDimitry Andric   mlir::Type elementType = elementTypeIfVector(type);
1391*700637cbSDimitry Andric   bool isVector = mlir::isa<cir::VectorType>(type);
1392*700637cbSDimitry Andric   mlir::Type llvmType = getTypeConverter()->convertType(type);
1393*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
1394*700637cbSDimitry Andric 
1395*700637cbSDimitry Andric   // Integer unary operations: + - ~ ++ --
1396*700637cbSDimitry Andric   if (mlir::isa<cir::IntType>(elementType)) {
1397*700637cbSDimitry Andric     mlir::LLVM::IntegerOverflowFlags maybeNSW =
1398*700637cbSDimitry Andric         op.getNoSignedWrap() ? mlir::LLVM::IntegerOverflowFlags::nsw
1399*700637cbSDimitry Andric                              : mlir::LLVM::IntegerOverflowFlags::none;
1400*700637cbSDimitry Andric     switch (op.getKind()) {
1401*700637cbSDimitry Andric     case cir::UnaryOpKind::Inc: {
1402*700637cbSDimitry Andric       assert(!isVector && "++ not allowed on vector types");
1403*700637cbSDimitry Andric       auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);
1404*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(
1405*700637cbSDimitry Andric           op, llvmType, adaptor.getInput(), one, maybeNSW);
1406*700637cbSDimitry Andric       return mlir::success();
1407*700637cbSDimitry Andric     }
1408*700637cbSDimitry Andric     case cir::UnaryOpKind::Dec: {
1409*700637cbSDimitry Andric       assert(!isVector && "-- not allowed on vector types");
1410*700637cbSDimitry Andric       auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);
1411*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, adaptor.getInput(),
1412*700637cbSDimitry Andric                                                      one, maybeNSW);
1413*700637cbSDimitry Andric       return mlir::success();
1414*700637cbSDimitry Andric     }
1415*700637cbSDimitry Andric     case cir::UnaryOpKind::Plus:
1416*700637cbSDimitry Andric       rewriter.replaceOp(op, adaptor.getInput());
1417*700637cbSDimitry Andric       return mlir::success();
1418*700637cbSDimitry Andric     case cir::UnaryOpKind::Minus: {
1419*700637cbSDimitry Andric       mlir::Value zero;
1420*700637cbSDimitry Andric       if (isVector)
1421*700637cbSDimitry Andric         zero = rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmType);
1422*700637cbSDimitry Andric       else
1423*700637cbSDimitry Andric         zero = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 0);
1424*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(
1425*700637cbSDimitry Andric           op, zero, adaptor.getInput(), maybeNSW);
1426*700637cbSDimitry Andric       return mlir::success();
1427*700637cbSDimitry Andric     }
1428*700637cbSDimitry Andric     case cir::UnaryOpKind::Not: {
1429*700637cbSDimitry Andric       // bit-wise compliment operator, implemented as an XOR with -1.
1430*700637cbSDimitry Andric       mlir::Value minusOne;
1431*700637cbSDimitry Andric       if (isVector) {
1432*700637cbSDimitry Andric         const uint64_t numElements =
1433*700637cbSDimitry Andric             mlir::dyn_cast<cir::VectorType>(type).getSize();
1434*700637cbSDimitry Andric         std::vector<int32_t> values(numElements, -1);
1435*700637cbSDimitry Andric         mlir::DenseIntElementsAttr denseVec = rewriter.getI32VectorAttr(values);
1436*700637cbSDimitry Andric         minusOne =
1437*700637cbSDimitry Andric             rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, denseVec);
1438*700637cbSDimitry Andric       } else {
1439*700637cbSDimitry Andric         minusOne = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, -1);
1440*700637cbSDimitry Andric       }
1441*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),
1442*700637cbSDimitry Andric                                                      minusOne);
1443*700637cbSDimitry Andric       return mlir::success();
1444*700637cbSDimitry Andric     }
1445*700637cbSDimitry Andric     }
1446*700637cbSDimitry Andric     llvm_unreachable("Unexpected unary op for int");
1447*700637cbSDimitry Andric   }
1448*700637cbSDimitry Andric 
1449*700637cbSDimitry Andric   // Floating point unary operations: + - ++ --
1450*700637cbSDimitry Andric   if (mlir::isa<cir::FPTypeInterface>(elementType)) {
1451*700637cbSDimitry Andric     switch (op.getKind()) {
1452*700637cbSDimitry Andric     case cir::UnaryOpKind::Inc: {
1453*700637cbSDimitry Andric       assert(!isVector && "++ not allowed on vector types");
1454*700637cbSDimitry Andric       mlir::LLVM::ConstantOp one = rewriter.create<mlir::LLVM::ConstantOp>(
1455*700637cbSDimitry Andric           loc, llvmType, rewriter.getFloatAttr(llvmType, 1.0));
1456*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, one,
1457*700637cbSDimitry Andric                                                       adaptor.getInput());
1458*700637cbSDimitry Andric       return mlir::success();
1459*700637cbSDimitry Andric     }
1460*700637cbSDimitry Andric     case cir::UnaryOpKind::Dec: {
1461*700637cbSDimitry Andric       assert(!isVector && "-- not allowed on vector types");
1462*700637cbSDimitry Andric       mlir::LLVM::ConstantOp minusOne = rewriter.create<mlir::LLVM::ConstantOp>(
1463*700637cbSDimitry Andric           loc, llvmType, rewriter.getFloatAttr(llvmType, -1.0));
1464*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, llvmType, minusOne,
1465*700637cbSDimitry Andric                                                       adaptor.getInput());
1466*700637cbSDimitry Andric       return mlir::success();
1467*700637cbSDimitry Andric     }
1468*700637cbSDimitry Andric     case cir::UnaryOpKind::Plus:
1469*700637cbSDimitry Andric       rewriter.replaceOp(op, adaptor.getInput());
1470*700637cbSDimitry Andric       return mlir::success();
1471*700637cbSDimitry Andric     case cir::UnaryOpKind::Minus:
1472*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FNegOp>(op, llvmType,
1473*700637cbSDimitry Andric                                                       adaptor.getInput());
1474*700637cbSDimitry Andric       return mlir::success();
1475*700637cbSDimitry Andric     case cir::UnaryOpKind::Not:
1476*700637cbSDimitry Andric       return op.emitError() << "Unary not is invalid for floating-point types";
1477*700637cbSDimitry Andric     }
1478*700637cbSDimitry Andric     llvm_unreachable("Unexpected unary op for float");
1479*700637cbSDimitry Andric   }
1480*700637cbSDimitry Andric 
1481*700637cbSDimitry Andric   // Boolean unary operations: ! only. (For all others, the operand has
1482*700637cbSDimitry Andric   // already been promoted to int.)
1483*700637cbSDimitry Andric   if (mlir::isa<cir::BoolType>(elementType)) {
1484*700637cbSDimitry Andric     switch (op.getKind()) {
1485*700637cbSDimitry Andric     case cir::UnaryOpKind::Inc:
1486*700637cbSDimitry Andric     case cir::UnaryOpKind::Dec:
1487*700637cbSDimitry Andric     case cir::UnaryOpKind::Plus:
1488*700637cbSDimitry Andric     case cir::UnaryOpKind::Minus:
1489*700637cbSDimitry Andric       // Some of these are allowed in source code, but we shouldn't get here
1490*700637cbSDimitry Andric       // with a boolean type.
1491*700637cbSDimitry Andric       return op.emitError() << "Unsupported unary operation on boolean type";
1492*700637cbSDimitry Andric     case cir::UnaryOpKind::Not: {
1493*700637cbSDimitry Andric       assert(!isVector && "NYI: op! on vector mask");
1494*700637cbSDimitry Andric       auto one = rewriter.create<mlir::LLVM::ConstantOp>(loc, llvmType, 1);
1495*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, adaptor.getInput(),
1496*700637cbSDimitry Andric                                                      one);
1497*700637cbSDimitry Andric       return mlir::success();
1498*700637cbSDimitry Andric     }
1499*700637cbSDimitry Andric     }
1500*700637cbSDimitry Andric     llvm_unreachable("Unexpected unary op for bool");
1501*700637cbSDimitry Andric   }
1502*700637cbSDimitry Andric 
1503*700637cbSDimitry Andric   // Pointer unary operations: + only.  (++ and -- of pointers are implemented
1504*700637cbSDimitry Andric   // with cir.ptr_stride, not cir.unary.)
1505*700637cbSDimitry Andric   if (mlir::isa<cir::PointerType>(elementType)) {
1506*700637cbSDimitry Andric     return op.emitError()
1507*700637cbSDimitry Andric            << "Unary operation on pointer types is not yet implemented";
1508*700637cbSDimitry Andric   }
1509*700637cbSDimitry Andric 
1510*700637cbSDimitry Andric   return op.emitError() << "Unary operation has unsupported type: "
1511*700637cbSDimitry Andric                         << elementType;
1512*700637cbSDimitry Andric }
1513*700637cbSDimitry Andric 
1514*700637cbSDimitry Andric mlir::LLVM::IntegerOverflowFlags
getIntOverflowFlag(cir::BinOp op) const1515*700637cbSDimitry Andric CIRToLLVMBinOpLowering::getIntOverflowFlag(cir::BinOp op) const {
1516*700637cbSDimitry Andric   if (op.getNoUnsignedWrap())
1517*700637cbSDimitry Andric     return mlir::LLVM::IntegerOverflowFlags::nuw;
1518*700637cbSDimitry Andric 
1519*700637cbSDimitry Andric   if (op.getNoSignedWrap())
1520*700637cbSDimitry Andric     return mlir::LLVM::IntegerOverflowFlags::nsw;
1521*700637cbSDimitry Andric 
1522*700637cbSDimitry Andric   return mlir::LLVM::IntegerOverflowFlags::none;
1523*700637cbSDimitry Andric }
1524*700637cbSDimitry Andric 
isIntTypeUnsigned(mlir::Type type)1525*700637cbSDimitry Andric static bool isIntTypeUnsigned(mlir::Type type) {
1526*700637cbSDimitry Andric   // TODO: Ideally, we should only need to check cir::IntType here.
1527*700637cbSDimitry Andric   return mlir::isa<cir::IntType>(type)
1528*700637cbSDimitry Andric              ? mlir::cast<cir::IntType>(type).isUnsigned()
1529*700637cbSDimitry Andric              : mlir::cast<mlir::IntegerType>(type).isUnsigned();
1530*700637cbSDimitry Andric }
1531*700637cbSDimitry Andric 
matchAndRewrite(cir::BinOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1532*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBinOpLowering::matchAndRewrite(
1533*700637cbSDimitry Andric     cir::BinOp op, OpAdaptor adaptor,
1534*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1535*700637cbSDimitry Andric   if (adaptor.getLhs().getType() != adaptor.getRhs().getType())
1536*700637cbSDimitry Andric     return op.emitError() << "inconsistent operands' types not supported yet";
1537*700637cbSDimitry Andric 
1538*700637cbSDimitry Andric   mlir::Type type = op.getRhs().getType();
1539*700637cbSDimitry Andric   if (!mlir::isa<cir::IntType, cir::BoolType, cir::FPTypeInterface,
1540*700637cbSDimitry Andric                  mlir::IntegerType, cir::VectorType>(type))
1541*700637cbSDimitry Andric     return op.emitError() << "operand type not supported yet";
1542*700637cbSDimitry Andric 
1543*700637cbSDimitry Andric   const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());
1544*700637cbSDimitry Andric   const mlir::Type llvmEltTy = elementTypeIfVector(llvmTy);
1545*700637cbSDimitry Andric 
1546*700637cbSDimitry Andric   const mlir::Value rhs = adaptor.getRhs();
1547*700637cbSDimitry Andric   const mlir::Value lhs = adaptor.getLhs();
1548*700637cbSDimitry Andric   type = elementTypeIfVector(type);
1549*700637cbSDimitry Andric 
1550*700637cbSDimitry Andric   switch (op.getKind()) {
1551*700637cbSDimitry Andric   case cir::BinOpKind::Add:
1552*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {
1553*700637cbSDimitry Andric       if (op.getSaturated()) {
1554*700637cbSDimitry Andric         if (isIntTypeUnsigned(type)) {
1555*700637cbSDimitry Andric           rewriter.replaceOpWithNewOp<mlir::LLVM::UAddSat>(op, lhs, rhs);
1556*700637cbSDimitry Andric           break;
1557*700637cbSDimitry Andric         }
1558*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::SAddSat>(op, lhs, rhs);
1559*700637cbSDimitry Andric         break;
1560*700637cbSDimitry Andric       }
1561*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::AddOp>(op, llvmTy, lhs, rhs,
1562*700637cbSDimitry Andric                                                      getIntOverflowFlag(op));
1563*700637cbSDimitry Andric     } else {
1564*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FAddOp>(op, lhs, rhs);
1565*700637cbSDimitry Andric     }
1566*700637cbSDimitry Andric     break;
1567*700637cbSDimitry Andric   case cir::BinOpKind::Sub:
1568*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {
1569*700637cbSDimitry Andric       if (op.getSaturated()) {
1570*700637cbSDimitry Andric         if (isIntTypeUnsigned(type)) {
1571*700637cbSDimitry Andric           rewriter.replaceOpWithNewOp<mlir::LLVM::USubSat>(op, lhs, rhs);
1572*700637cbSDimitry Andric           break;
1573*700637cbSDimitry Andric         }
1574*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::SSubSat>(op, lhs, rhs);
1575*700637cbSDimitry Andric         break;
1576*700637cbSDimitry Andric       }
1577*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::SubOp>(op, llvmTy, lhs, rhs,
1578*700637cbSDimitry Andric                                                      getIntOverflowFlag(op));
1579*700637cbSDimitry Andric     } else {
1580*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FSubOp>(op, lhs, rhs);
1581*700637cbSDimitry Andric     }
1582*700637cbSDimitry Andric     break;
1583*700637cbSDimitry Andric   case cir::BinOpKind::Mul:
1584*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy))
1585*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::MulOp>(op, llvmTy, lhs, rhs,
1586*700637cbSDimitry Andric                                                      getIntOverflowFlag(op));
1587*700637cbSDimitry Andric     else
1588*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FMulOp>(op, lhs, rhs);
1589*700637cbSDimitry Andric     break;
1590*700637cbSDimitry Andric   case cir::BinOpKind::Div:
1591*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {
1592*700637cbSDimitry Andric       auto isUnsigned = isIntTypeUnsigned(type);
1593*700637cbSDimitry Andric       if (isUnsigned)
1594*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::UDivOp>(op, lhs, rhs);
1595*700637cbSDimitry Andric       else
1596*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::SDivOp>(op, lhs, rhs);
1597*700637cbSDimitry Andric     } else {
1598*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FDivOp>(op, lhs, rhs);
1599*700637cbSDimitry Andric     }
1600*700637cbSDimitry Andric     break;
1601*700637cbSDimitry Andric   case cir::BinOpKind::Rem:
1602*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {
1603*700637cbSDimitry Andric       auto isUnsigned = isIntTypeUnsigned(type);
1604*700637cbSDimitry Andric       if (isUnsigned)
1605*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::URemOp>(op, lhs, rhs);
1606*700637cbSDimitry Andric       else
1607*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::SRemOp>(op, lhs, rhs);
1608*700637cbSDimitry Andric     } else {
1609*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::FRemOp>(op, lhs, rhs);
1610*700637cbSDimitry Andric     }
1611*700637cbSDimitry Andric     break;
1612*700637cbSDimitry Andric   case cir::BinOpKind::And:
1613*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, lhs, rhs);
1614*700637cbSDimitry Andric     break;
1615*700637cbSDimitry Andric   case cir::BinOpKind::Or:
1616*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, lhs, rhs);
1617*700637cbSDimitry Andric     break;
1618*700637cbSDimitry Andric   case cir::BinOpKind::Xor:
1619*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::XOrOp>(op, lhs, rhs);
1620*700637cbSDimitry Andric     break;
1621*700637cbSDimitry Andric   case cir::BinOpKind::Max:
1622*700637cbSDimitry Andric     if (mlir::isa<mlir::IntegerType>(llvmEltTy)) {
1623*700637cbSDimitry Andric       auto isUnsigned = isIntTypeUnsigned(type);
1624*700637cbSDimitry Andric       if (isUnsigned)
1625*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::UMaxOp>(op, llvmTy, lhs, rhs);
1626*700637cbSDimitry Andric       else
1627*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::SMaxOp>(op, llvmTy, lhs, rhs);
1628*700637cbSDimitry Andric     }
1629*700637cbSDimitry Andric     break;
1630*700637cbSDimitry Andric   }
1631*700637cbSDimitry Andric   return mlir::LogicalResult::success();
1632*700637cbSDimitry Andric }
1633*700637cbSDimitry Andric 
1634*700637cbSDimitry Andric /// Convert from a CIR comparison kind to an LLVM IR integral comparison kind.
1635*700637cbSDimitry Andric static mlir::LLVM::ICmpPredicate
convertCmpKindToICmpPredicate(cir::CmpOpKind kind,bool isSigned)1636*700637cbSDimitry Andric convertCmpKindToICmpPredicate(cir::CmpOpKind kind, bool isSigned) {
1637*700637cbSDimitry Andric   using CIR = cir::CmpOpKind;
1638*700637cbSDimitry Andric   using LLVMICmp = mlir::LLVM::ICmpPredicate;
1639*700637cbSDimitry Andric   switch (kind) {
1640*700637cbSDimitry Andric   case CIR::eq:
1641*700637cbSDimitry Andric     return LLVMICmp::eq;
1642*700637cbSDimitry Andric   case CIR::ne:
1643*700637cbSDimitry Andric     return LLVMICmp::ne;
1644*700637cbSDimitry Andric   case CIR::lt:
1645*700637cbSDimitry Andric     return (isSigned ? LLVMICmp::slt : LLVMICmp::ult);
1646*700637cbSDimitry Andric   case CIR::le:
1647*700637cbSDimitry Andric     return (isSigned ? LLVMICmp::sle : LLVMICmp::ule);
1648*700637cbSDimitry Andric   case CIR::gt:
1649*700637cbSDimitry Andric     return (isSigned ? LLVMICmp::sgt : LLVMICmp::ugt);
1650*700637cbSDimitry Andric   case CIR::ge:
1651*700637cbSDimitry Andric     return (isSigned ? LLVMICmp::sge : LLVMICmp::uge);
1652*700637cbSDimitry Andric   }
1653*700637cbSDimitry Andric   llvm_unreachable("Unknown CmpOpKind");
1654*700637cbSDimitry Andric }
1655*700637cbSDimitry Andric 
1656*700637cbSDimitry Andric /// Convert from a CIR comparison kind to an LLVM IR floating-point comparison
1657*700637cbSDimitry Andric /// kind.
1658*700637cbSDimitry Andric static mlir::LLVM::FCmpPredicate
convertCmpKindToFCmpPredicate(cir::CmpOpKind kind)1659*700637cbSDimitry Andric convertCmpKindToFCmpPredicate(cir::CmpOpKind kind) {
1660*700637cbSDimitry Andric   using CIR = cir::CmpOpKind;
1661*700637cbSDimitry Andric   using LLVMFCmp = mlir::LLVM::FCmpPredicate;
1662*700637cbSDimitry Andric   switch (kind) {
1663*700637cbSDimitry Andric   case CIR::eq:
1664*700637cbSDimitry Andric     return LLVMFCmp::oeq;
1665*700637cbSDimitry Andric   case CIR::ne:
1666*700637cbSDimitry Andric     return LLVMFCmp::une;
1667*700637cbSDimitry Andric   case CIR::lt:
1668*700637cbSDimitry Andric     return LLVMFCmp::olt;
1669*700637cbSDimitry Andric   case CIR::le:
1670*700637cbSDimitry Andric     return LLVMFCmp::ole;
1671*700637cbSDimitry Andric   case CIR::gt:
1672*700637cbSDimitry Andric     return LLVMFCmp::ogt;
1673*700637cbSDimitry Andric   case CIR::ge:
1674*700637cbSDimitry Andric     return LLVMFCmp::oge;
1675*700637cbSDimitry Andric   }
1676*700637cbSDimitry Andric   llvm_unreachable("Unknown CmpOpKind");
1677*700637cbSDimitry Andric }
1678*700637cbSDimitry Andric 
matchAndRewrite(cir::CmpOp cmpOp,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1679*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMCmpOpLowering::matchAndRewrite(
1680*700637cbSDimitry Andric     cir::CmpOp cmpOp, OpAdaptor adaptor,
1681*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1682*700637cbSDimitry Andric   mlir::Type type = cmpOp.getLhs().getType();
1683*700637cbSDimitry Andric 
1684*700637cbSDimitry Andric   assert(!cir::MissingFeatures::dataMemberType());
1685*700637cbSDimitry Andric   assert(!cir::MissingFeatures::methodType());
1686*700637cbSDimitry Andric 
1687*700637cbSDimitry Andric   if (mlir::isa<cir::IntType, mlir::IntegerType>(type)) {
1688*700637cbSDimitry Andric     bool isSigned = mlir::isa<cir::IntType>(type)
1689*700637cbSDimitry Andric                         ? mlir::cast<cir::IntType>(type).isSigned()
1690*700637cbSDimitry Andric                         : mlir::cast<mlir::IntegerType>(type).isSigned();
1691*700637cbSDimitry Andric     mlir::LLVM::ICmpPredicate kind =
1692*700637cbSDimitry Andric         convertCmpKindToICmpPredicate(cmpOp.getKind(), isSigned);
1693*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1694*700637cbSDimitry Andric         cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
1695*700637cbSDimitry Andric     return mlir::success();
1696*700637cbSDimitry Andric   }
1697*700637cbSDimitry Andric 
1698*700637cbSDimitry Andric   if (auto ptrTy = mlir::dyn_cast<cir::PointerType>(type)) {
1699*700637cbSDimitry Andric     mlir::LLVM::ICmpPredicate kind =
1700*700637cbSDimitry Andric         convertCmpKindToICmpPredicate(cmpOp.getKind(),
1701*700637cbSDimitry Andric                                       /* isSigned=*/false);
1702*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
1703*700637cbSDimitry Andric         cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
1704*700637cbSDimitry Andric     return mlir::success();
1705*700637cbSDimitry Andric   }
1706*700637cbSDimitry Andric 
1707*700637cbSDimitry Andric   if (mlir::isa<cir::FPTypeInterface>(type)) {
1708*700637cbSDimitry Andric     mlir::LLVM::FCmpPredicate kind =
1709*700637cbSDimitry Andric         convertCmpKindToFCmpPredicate(cmpOp.getKind());
1710*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::FCmpOp>(
1711*700637cbSDimitry Andric         cmpOp, kind, adaptor.getLhs(), adaptor.getRhs());
1712*700637cbSDimitry Andric     return mlir::success();
1713*700637cbSDimitry Andric   }
1714*700637cbSDimitry Andric 
1715*700637cbSDimitry Andric   if (mlir::isa<cir::ComplexType>(type)) {
1716*700637cbSDimitry Andric     mlir::Value lhs = adaptor.getLhs();
1717*700637cbSDimitry Andric     mlir::Value rhs = adaptor.getRhs();
1718*700637cbSDimitry Andric     mlir::Location loc = cmpOp.getLoc();
1719*700637cbSDimitry Andric 
1720*700637cbSDimitry Andric     auto complexType = mlir::cast<cir::ComplexType>(cmpOp.getLhs().getType());
1721*700637cbSDimitry Andric     mlir::Type complexElemTy =
1722*700637cbSDimitry Andric         getTypeConverter()->convertType(complexType.getElementType());
1723*700637cbSDimitry Andric 
1724*700637cbSDimitry Andric     auto lhsReal =
1725*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
1726*700637cbSDimitry Andric     auto lhsImag =
1727*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
1728*700637cbSDimitry Andric     auto rhsReal =
1729*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
1730*700637cbSDimitry Andric     auto rhsImag =
1731*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
1732*700637cbSDimitry Andric 
1733*700637cbSDimitry Andric     if (cmpOp.getKind() == cir::CmpOpKind::eq) {
1734*700637cbSDimitry Andric       if (complexElemTy.isInteger()) {
1735*700637cbSDimitry Andric         auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
1736*700637cbSDimitry Andric             loc, mlir::LLVM::ICmpPredicate::eq, lhsReal, rhsReal);
1737*700637cbSDimitry Andric         auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
1738*700637cbSDimitry Andric             loc, mlir::LLVM::ICmpPredicate::eq, lhsImag, rhsImag);
1739*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);
1740*700637cbSDimitry Andric         return mlir::success();
1741*700637cbSDimitry Andric       }
1742*700637cbSDimitry Andric 
1743*700637cbSDimitry Andric       auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
1744*700637cbSDimitry Andric           loc, mlir::LLVM::FCmpPredicate::oeq, lhsReal, rhsReal);
1745*700637cbSDimitry Andric       auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
1746*700637cbSDimitry Andric           loc, mlir::LLVM::FCmpPredicate::oeq, lhsImag, rhsImag);
1747*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(cmpOp, realCmp, imagCmp);
1748*700637cbSDimitry Andric       return mlir::success();
1749*700637cbSDimitry Andric     }
1750*700637cbSDimitry Andric 
1751*700637cbSDimitry Andric     if (cmpOp.getKind() == cir::CmpOpKind::ne) {
1752*700637cbSDimitry Andric       if (complexElemTy.isInteger()) {
1753*700637cbSDimitry Andric         auto realCmp = rewriter.create<mlir::LLVM::ICmpOp>(
1754*700637cbSDimitry Andric             loc, mlir::LLVM::ICmpPredicate::ne, lhsReal, rhsReal);
1755*700637cbSDimitry Andric         auto imagCmp = rewriter.create<mlir::LLVM::ICmpOp>(
1756*700637cbSDimitry Andric             loc, mlir::LLVM::ICmpPredicate::ne, lhsImag, rhsImag);
1757*700637cbSDimitry Andric         rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);
1758*700637cbSDimitry Andric         return mlir::success();
1759*700637cbSDimitry Andric       }
1760*700637cbSDimitry Andric 
1761*700637cbSDimitry Andric       auto realCmp = rewriter.create<mlir::LLVM::FCmpOp>(
1762*700637cbSDimitry Andric           loc, mlir::LLVM::FCmpPredicate::une, lhsReal, rhsReal);
1763*700637cbSDimitry Andric       auto imagCmp = rewriter.create<mlir::LLVM::FCmpOp>(
1764*700637cbSDimitry Andric           loc, mlir::LLVM::FCmpPredicate::une, lhsImag, rhsImag);
1765*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(cmpOp, realCmp, imagCmp);
1766*700637cbSDimitry Andric       return mlir::success();
1767*700637cbSDimitry Andric     }
1768*700637cbSDimitry Andric   }
1769*700637cbSDimitry Andric 
1770*700637cbSDimitry Andric   return cmpOp.emitError() << "unsupported type for CmpOp: " << type;
1771*700637cbSDimitry Andric }
1772*700637cbSDimitry Andric 
matchAndRewrite(cir::ShiftOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1773*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMShiftOpLowering::matchAndRewrite(
1774*700637cbSDimitry Andric     cir::ShiftOp op, OpAdaptor adaptor,
1775*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1776*700637cbSDimitry Andric   assert((op.getValue().getType() == op.getType()) &&
1777*700637cbSDimitry Andric          "inconsistent operands' types NYI");
1778*700637cbSDimitry Andric 
1779*700637cbSDimitry Andric   const mlir::Type llvmTy = getTypeConverter()->convertType(op.getType());
1780*700637cbSDimitry Andric   mlir::Value amt = adaptor.getAmount();
1781*700637cbSDimitry Andric   mlir::Value val = adaptor.getValue();
1782*700637cbSDimitry Andric 
1783*700637cbSDimitry Andric   auto cirAmtTy = mlir::dyn_cast<cir::IntType>(op.getAmount().getType());
1784*700637cbSDimitry Andric   bool isUnsigned;
1785*700637cbSDimitry Andric   if (cirAmtTy) {
1786*700637cbSDimitry Andric     auto cirValTy = mlir::cast<cir::IntType>(op.getValue().getType());
1787*700637cbSDimitry Andric     isUnsigned = cirValTy.isUnsigned();
1788*700637cbSDimitry Andric 
1789*700637cbSDimitry Andric     // Ensure shift amount is the same type as the value. Some undefined
1790*700637cbSDimitry Andric     // behavior might occur in the casts below as per [C99 6.5.7.3].
1791*700637cbSDimitry Andric     // Vector type shift amount needs no cast as type consistency is expected to
1792*700637cbSDimitry Andric     // be already be enforced at CIRGen.
1793*700637cbSDimitry Andric     if (cirAmtTy)
1794*700637cbSDimitry Andric       amt = getLLVMIntCast(rewriter, amt, llvmTy, true, cirAmtTy.getWidth(),
1795*700637cbSDimitry Andric                            cirValTy.getWidth());
1796*700637cbSDimitry Andric   } else {
1797*700637cbSDimitry Andric     auto cirValVTy = mlir::cast<cir::VectorType>(op.getValue().getType());
1798*700637cbSDimitry Andric     isUnsigned =
1799*700637cbSDimitry Andric         mlir::cast<cir::IntType>(cirValVTy.getElementType()).isUnsigned();
1800*700637cbSDimitry Andric   }
1801*700637cbSDimitry Andric 
1802*700637cbSDimitry Andric   // Lower to the proper LLVM shift operation.
1803*700637cbSDimitry Andric   if (op.getIsShiftleft()) {
1804*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::ShlOp>(op, llvmTy, val, amt);
1805*700637cbSDimitry Andric     return mlir::success();
1806*700637cbSDimitry Andric   }
1807*700637cbSDimitry Andric 
1808*700637cbSDimitry Andric   if (isUnsigned)
1809*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::LShrOp>(op, llvmTy, val, amt);
1810*700637cbSDimitry Andric   else
1811*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::AShrOp>(op, llvmTy, val, amt);
1812*700637cbSDimitry Andric   return mlir::success();
1813*700637cbSDimitry Andric }
1814*700637cbSDimitry Andric 
matchAndRewrite(cir::SelectOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const1815*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMSelectOpLowering::matchAndRewrite(
1816*700637cbSDimitry Andric     cir::SelectOp op, OpAdaptor adaptor,
1817*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
1818*700637cbSDimitry Andric   auto getConstantBool = [](mlir::Value value) -> cir::BoolAttr {
1819*700637cbSDimitry Andric     auto definingOp =
1820*700637cbSDimitry Andric         mlir::dyn_cast_if_present<cir::ConstantOp>(value.getDefiningOp());
1821*700637cbSDimitry Andric     if (!definingOp)
1822*700637cbSDimitry Andric       return {};
1823*700637cbSDimitry Andric 
1824*700637cbSDimitry Andric     auto constValue = mlir::dyn_cast<cir::BoolAttr>(definingOp.getValue());
1825*700637cbSDimitry Andric     if (!constValue)
1826*700637cbSDimitry Andric       return {};
1827*700637cbSDimitry Andric 
1828*700637cbSDimitry Andric     return constValue;
1829*700637cbSDimitry Andric   };
1830*700637cbSDimitry Andric 
1831*700637cbSDimitry Andric   // Two special cases in the LLVMIR codegen of select op:
1832*700637cbSDimitry Andric   // - select %0, %1, false => and %0, %1
1833*700637cbSDimitry Andric   // - select %0, true, %1 => or %0, %1
1834*700637cbSDimitry Andric   if (mlir::isa<cir::BoolType>(op.getTrueValue().getType())) {
1835*700637cbSDimitry Andric     cir::BoolAttr trueValue = getConstantBool(op.getTrueValue());
1836*700637cbSDimitry Andric     cir::BoolAttr falseValue = getConstantBool(op.getFalseValue());
1837*700637cbSDimitry Andric     if (falseValue && !falseValue.getValue()) {
1838*700637cbSDimitry Andric       // select %0, %1, false => and %0, %1
1839*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::AndOp>(op, adaptor.getCondition(),
1840*700637cbSDimitry Andric                                                      adaptor.getTrueValue());
1841*700637cbSDimitry Andric       return mlir::success();
1842*700637cbSDimitry Andric     }
1843*700637cbSDimitry Andric     if (trueValue && trueValue.getValue()) {
1844*700637cbSDimitry Andric       // select %0, true, %1 => or %0, %1
1845*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::OrOp>(op, adaptor.getCondition(),
1846*700637cbSDimitry Andric                                                     adaptor.getFalseValue());
1847*700637cbSDimitry Andric       return mlir::success();
1848*700637cbSDimitry Andric     }
1849*700637cbSDimitry Andric   }
1850*700637cbSDimitry Andric 
1851*700637cbSDimitry Andric   mlir::Value llvmCondition = adaptor.getCondition();
1852*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(
1853*700637cbSDimitry Andric       op, llvmCondition, adaptor.getTrueValue(), adaptor.getFalseValue());
1854*700637cbSDimitry Andric 
1855*700637cbSDimitry Andric   return mlir::success();
1856*700637cbSDimitry Andric }
1857*700637cbSDimitry Andric 
prepareTypeConverter(mlir::LLVMTypeConverter & converter,mlir::DataLayout & dataLayout)1858*700637cbSDimitry Andric static void prepareTypeConverter(mlir::LLVMTypeConverter &converter,
1859*700637cbSDimitry Andric                                  mlir::DataLayout &dataLayout) {
1860*700637cbSDimitry Andric   converter.addConversion([&](cir::PointerType type) -> mlir::Type {
1861*700637cbSDimitry Andric     // Drop pointee type since LLVM dialect only allows opaque pointers.
1862*700637cbSDimitry Andric     assert(!cir::MissingFeatures::addressSpace());
1863*700637cbSDimitry Andric     unsigned targetAS = 0;
1864*700637cbSDimitry Andric 
1865*700637cbSDimitry Andric     return mlir::LLVM::LLVMPointerType::get(type.getContext(), targetAS);
1866*700637cbSDimitry Andric   });
1867*700637cbSDimitry Andric   converter.addConversion([&](cir::ArrayType type) -> mlir::Type {
1868*700637cbSDimitry Andric     mlir::Type ty =
1869*700637cbSDimitry Andric         convertTypeForMemory(converter, dataLayout, type.getElementType());
1870*700637cbSDimitry Andric     return mlir::LLVM::LLVMArrayType::get(ty, type.getSize());
1871*700637cbSDimitry Andric   });
1872*700637cbSDimitry Andric   converter.addConversion([&](cir::VectorType type) -> mlir::Type {
1873*700637cbSDimitry Andric     const mlir::Type ty = converter.convertType(type.getElementType());
1874*700637cbSDimitry Andric     return mlir::VectorType::get(type.getSize(), ty);
1875*700637cbSDimitry Andric   });
1876*700637cbSDimitry Andric   converter.addConversion([&](cir::BoolType type) -> mlir::Type {
1877*700637cbSDimitry Andric     return mlir::IntegerType::get(type.getContext(), 1,
1878*700637cbSDimitry Andric                                   mlir::IntegerType::Signless);
1879*700637cbSDimitry Andric   });
1880*700637cbSDimitry Andric   converter.addConversion([&](cir::IntType type) -> mlir::Type {
1881*700637cbSDimitry Andric     // LLVM doesn't work with signed types, so we drop the CIR signs here.
1882*700637cbSDimitry Andric     return mlir::IntegerType::get(type.getContext(), type.getWidth());
1883*700637cbSDimitry Andric   });
1884*700637cbSDimitry Andric   converter.addConversion([&](cir::SingleType type) -> mlir::Type {
1885*700637cbSDimitry Andric     return mlir::Float32Type::get(type.getContext());
1886*700637cbSDimitry Andric   });
1887*700637cbSDimitry Andric   converter.addConversion([&](cir::DoubleType type) -> mlir::Type {
1888*700637cbSDimitry Andric     return mlir::Float64Type::get(type.getContext());
1889*700637cbSDimitry Andric   });
1890*700637cbSDimitry Andric   converter.addConversion([&](cir::FP80Type type) -> mlir::Type {
1891*700637cbSDimitry Andric     return mlir::Float80Type::get(type.getContext());
1892*700637cbSDimitry Andric   });
1893*700637cbSDimitry Andric   converter.addConversion([&](cir::FP128Type type) -> mlir::Type {
1894*700637cbSDimitry Andric     return mlir::Float128Type::get(type.getContext());
1895*700637cbSDimitry Andric   });
1896*700637cbSDimitry Andric   converter.addConversion([&](cir::LongDoubleType type) -> mlir::Type {
1897*700637cbSDimitry Andric     return converter.convertType(type.getUnderlying());
1898*700637cbSDimitry Andric   });
1899*700637cbSDimitry Andric   converter.addConversion([&](cir::FP16Type type) -> mlir::Type {
1900*700637cbSDimitry Andric     return mlir::Float16Type::get(type.getContext());
1901*700637cbSDimitry Andric   });
1902*700637cbSDimitry Andric   converter.addConversion([&](cir::BF16Type type) -> mlir::Type {
1903*700637cbSDimitry Andric     return mlir::BFloat16Type::get(type.getContext());
1904*700637cbSDimitry Andric   });
1905*700637cbSDimitry Andric   converter.addConversion([&](cir::ComplexType type) -> mlir::Type {
1906*700637cbSDimitry Andric     // A complex type is lowered to an LLVM struct that contains the real and
1907*700637cbSDimitry Andric     // imaginary part as data fields.
1908*700637cbSDimitry Andric     mlir::Type elementTy = converter.convertType(type.getElementType());
1909*700637cbSDimitry Andric     mlir::Type structFields[2] = {elementTy, elementTy};
1910*700637cbSDimitry Andric     return mlir::LLVM::LLVMStructType::getLiteral(type.getContext(),
1911*700637cbSDimitry Andric                                                   structFields);
1912*700637cbSDimitry Andric   });
1913*700637cbSDimitry Andric   converter.addConversion([&](cir::FuncType type) -> std::optional<mlir::Type> {
1914*700637cbSDimitry Andric     auto result = converter.convertType(type.getReturnType());
1915*700637cbSDimitry Andric     llvm::SmallVector<mlir::Type> arguments;
1916*700637cbSDimitry Andric     arguments.reserve(type.getNumInputs());
1917*700637cbSDimitry Andric     if (converter.convertTypes(type.getInputs(), arguments).failed())
1918*700637cbSDimitry Andric       return std::nullopt;
1919*700637cbSDimitry Andric     auto varArg = type.isVarArg();
1920*700637cbSDimitry Andric     return mlir::LLVM::LLVMFunctionType::get(result, arguments, varArg);
1921*700637cbSDimitry Andric   });
1922*700637cbSDimitry Andric   converter.addConversion([&](cir::RecordType type) -> mlir::Type {
1923*700637cbSDimitry Andric     // Convert struct members.
1924*700637cbSDimitry Andric     llvm::SmallVector<mlir::Type> llvmMembers;
1925*700637cbSDimitry Andric     switch (type.getKind()) {
1926*700637cbSDimitry Andric     case cir::RecordType::Class:
1927*700637cbSDimitry Andric     case cir::RecordType::Struct:
1928*700637cbSDimitry Andric       for (mlir::Type ty : type.getMembers())
1929*700637cbSDimitry Andric         llvmMembers.push_back(convertTypeForMemory(converter, dataLayout, ty));
1930*700637cbSDimitry Andric       break;
1931*700637cbSDimitry Andric     // Unions are lowered as only the largest member.
1932*700637cbSDimitry Andric     case cir::RecordType::Union:
1933*700637cbSDimitry Andric       if (auto largestMember = type.getLargestMember(dataLayout))
1934*700637cbSDimitry Andric         llvmMembers.push_back(
1935*700637cbSDimitry Andric             convertTypeForMemory(converter, dataLayout, largestMember));
1936*700637cbSDimitry Andric       if (type.getPadded()) {
1937*700637cbSDimitry Andric         auto last = *type.getMembers().rbegin();
1938*700637cbSDimitry Andric         llvmMembers.push_back(
1939*700637cbSDimitry Andric             convertTypeForMemory(converter, dataLayout, last));
1940*700637cbSDimitry Andric       }
1941*700637cbSDimitry Andric       break;
1942*700637cbSDimitry Andric     }
1943*700637cbSDimitry Andric 
1944*700637cbSDimitry Andric     // Record has a name: lower as an identified record.
1945*700637cbSDimitry Andric     mlir::LLVM::LLVMStructType llvmStruct;
1946*700637cbSDimitry Andric     if (type.getName()) {
1947*700637cbSDimitry Andric       llvmStruct = mlir::LLVM::LLVMStructType::getIdentified(
1948*700637cbSDimitry Andric           type.getContext(), type.getPrefixedName());
1949*700637cbSDimitry Andric       if (llvmStruct.setBody(llvmMembers, type.getPacked()).failed())
1950*700637cbSDimitry Andric         llvm_unreachable("Failed to set body of record");
1951*700637cbSDimitry Andric     } else { // Record has no name: lower as literal record.
1952*700637cbSDimitry Andric       llvmStruct = mlir::LLVM::LLVMStructType::getLiteral(
1953*700637cbSDimitry Andric           type.getContext(), llvmMembers, type.getPacked());
1954*700637cbSDimitry Andric     }
1955*700637cbSDimitry Andric 
1956*700637cbSDimitry Andric     return llvmStruct;
1957*700637cbSDimitry Andric   });
1958*700637cbSDimitry Andric }
1959*700637cbSDimitry Andric 
1960*700637cbSDimitry Andric // The applyPartialConversion function traverses blocks in the dominance order,
1961*700637cbSDimitry Andric // so it does not lower and operations that are not reachachable from the
1962*700637cbSDimitry Andric // operations passed in as arguments. Since we do need to lower such code in
1963*700637cbSDimitry Andric // order to avoid verification errors occur, we cannot just pass the module op
1964*700637cbSDimitry Andric // to applyPartialConversion. We must build a set of unreachable ops and
1965*700637cbSDimitry Andric // explicitly add them, along with the module, to the vector we pass to
1966*700637cbSDimitry Andric // applyPartialConversion.
1967*700637cbSDimitry Andric //
1968*700637cbSDimitry Andric // For instance, this CIR code:
1969*700637cbSDimitry Andric //
1970*700637cbSDimitry Andric //    cir.func @foo(%arg0: !s32i) -> !s32i {
1971*700637cbSDimitry Andric //      %4 = cir.cast(int_to_bool, %arg0 : !s32i), !cir.bool
1972*700637cbSDimitry Andric //      cir.if %4 {
1973*700637cbSDimitry Andric //        %5 = cir.const #cir.int<1> : !s32i
1974*700637cbSDimitry Andric //        cir.return %5 : !s32i
1975*700637cbSDimitry Andric //      } else {
1976*700637cbSDimitry Andric //        %5 = cir.const #cir.int<0> : !s32i
1977*700637cbSDimitry Andric //       cir.return %5 : !s32i
1978*700637cbSDimitry Andric //      }
1979*700637cbSDimitry Andric //      cir.return %arg0 : !s32i
1980*700637cbSDimitry Andric //    }
1981*700637cbSDimitry Andric //
1982*700637cbSDimitry Andric // contains an unreachable return operation (the last one). After the flattening
1983*700637cbSDimitry Andric // pass it will be placed into the unreachable block. The possible error
1984*700637cbSDimitry Andric // after the lowering pass is: error: 'cir.return' op expects parent op to be
1985*700637cbSDimitry Andric // one of 'cir.func, cir.scope, cir.if ... The reason that this operation was
1986*700637cbSDimitry Andric // not lowered and the new parent is llvm.func.
1987*700637cbSDimitry Andric //
1988*700637cbSDimitry Andric // In the future we may want to get rid of this function and use a DCE pass or
1989*700637cbSDimitry Andric // something similar. But for now we need to guarantee the absence of the
1990*700637cbSDimitry Andric // dialect verification errors.
collectUnreachable(mlir::Operation * parent,llvm::SmallVector<mlir::Operation * > & ops)1991*700637cbSDimitry Andric static void collectUnreachable(mlir::Operation *parent,
1992*700637cbSDimitry Andric                                llvm::SmallVector<mlir::Operation *> &ops) {
1993*700637cbSDimitry Andric 
1994*700637cbSDimitry Andric   llvm::SmallVector<mlir::Block *> unreachableBlocks;
1995*700637cbSDimitry Andric   parent->walk([&](mlir::Block *blk) { // check
1996*700637cbSDimitry Andric     if (blk->hasNoPredecessors() && !blk->isEntryBlock())
1997*700637cbSDimitry Andric       unreachableBlocks.push_back(blk);
1998*700637cbSDimitry Andric   });
1999*700637cbSDimitry Andric 
2000*700637cbSDimitry Andric   std::set<mlir::Block *> visited;
2001*700637cbSDimitry Andric   for (mlir::Block *root : unreachableBlocks) {
2002*700637cbSDimitry Andric     // We create a work list for each unreachable block.
2003*700637cbSDimitry Andric     // Thus we traverse operations in some order.
2004*700637cbSDimitry Andric     std::deque<mlir::Block *> workList;
2005*700637cbSDimitry Andric     workList.push_back(root);
2006*700637cbSDimitry Andric 
2007*700637cbSDimitry Andric     while (!workList.empty()) {
2008*700637cbSDimitry Andric       mlir::Block *blk = workList.back();
2009*700637cbSDimitry Andric       workList.pop_back();
2010*700637cbSDimitry Andric       if (visited.count(blk))
2011*700637cbSDimitry Andric         continue;
2012*700637cbSDimitry Andric       visited.emplace(blk);
2013*700637cbSDimitry Andric 
2014*700637cbSDimitry Andric       for (mlir::Operation &op : *blk)
2015*700637cbSDimitry Andric         ops.push_back(&op);
2016*700637cbSDimitry Andric 
2017*700637cbSDimitry Andric       for (mlir::Block *succ : blk->getSuccessors())
2018*700637cbSDimitry Andric         workList.push_back(succ);
2019*700637cbSDimitry Andric     }
2020*700637cbSDimitry Andric   }
2021*700637cbSDimitry Andric }
2022*700637cbSDimitry Andric 
processCIRAttrs(mlir::ModuleOp module)2023*700637cbSDimitry Andric void ConvertCIRToLLVMPass::processCIRAttrs(mlir::ModuleOp module) {
2024*700637cbSDimitry Andric   // Lower the module attributes to LLVM equivalents.
2025*700637cbSDimitry Andric   if (mlir::Attribute tripleAttr =
2026*700637cbSDimitry Andric           module->getAttr(cir::CIRDialect::getTripleAttrName()))
2027*700637cbSDimitry Andric     module->setAttr(mlir::LLVM::LLVMDialect::getTargetTripleAttrName(),
2028*700637cbSDimitry Andric                     tripleAttr);
2029*700637cbSDimitry Andric }
2030*700637cbSDimitry Andric 
runOnOperation()2031*700637cbSDimitry Andric void ConvertCIRToLLVMPass::runOnOperation() {
2032*700637cbSDimitry Andric   llvm::TimeTraceScope scope("Convert CIR to LLVM Pass");
2033*700637cbSDimitry Andric 
2034*700637cbSDimitry Andric   mlir::ModuleOp module = getOperation();
2035*700637cbSDimitry Andric   mlir::DataLayout dl(module);
2036*700637cbSDimitry Andric   mlir::LLVMTypeConverter converter(&getContext());
2037*700637cbSDimitry Andric   prepareTypeConverter(converter, dl);
2038*700637cbSDimitry Andric 
2039*700637cbSDimitry Andric   mlir::RewritePatternSet patterns(&getContext());
2040*700637cbSDimitry Andric 
2041*700637cbSDimitry Andric   patterns.add<CIRToLLVMReturnOpLowering>(patterns.getContext());
2042*700637cbSDimitry Andric   // This could currently be merged with the group below, but it will get more
2043*700637cbSDimitry Andric   // arguments later, so we'll keep it separate for now.
2044*700637cbSDimitry Andric   patterns.add<CIRToLLVMAllocaOpLowering>(converter, patterns.getContext(), dl);
2045*700637cbSDimitry Andric   patterns.add<CIRToLLVMLoadOpLowering>(converter, patterns.getContext(), dl);
2046*700637cbSDimitry Andric   patterns.add<CIRToLLVMStoreOpLowering>(converter, patterns.getContext(), dl);
2047*700637cbSDimitry Andric   patterns.add<CIRToLLVMGlobalOpLowering>(converter, patterns.getContext(), dl);
2048*700637cbSDimitry Andric   patterns.add<CIRToLLVMCastOpLowering>(converter, patterns.getContext(), dl);
2049*700637cbSDimitry Andric   patterns.add<CIRToLLVMPtrStrideOpLowering>(converter, patterns.getContext(),
2050*700637cbSDimitry Andric                                              dl);
2051*700637cbSDimitry Andric   patterns.add<
2052*700637cbSDimitry Andric       // clang-format off
2053*700637cbSDimitry Andric                CIRToLLVMAssumeOpLowering,
2054*700637cbSDimitry Andric                CIRToLLVMBaseClassAddrOpLowering,
2055*700637cbSDimitry Andric                CIRToLLVMBinOpLowering,
2056*700637cbSDimitry Andric                CIRToLLVMBitClrsbOpLowering,
2057*700637cbSDimitry Andric                CIRToLLVMBitClzOpLowering,
2058*700637cbSDimitry Andric                CIRToLLVMBitCtzOpLowering,
2059*700637cbSDimitry Andric                CIRToLLVMBitParityOpLowering,
2060*700637cbSDimitry Andric                CIRToLLVMBitPopcountOpLowering,
2061*700637cbSDimitry Andric                CIRToLLVMBitReverseOpLowering,
2062*700637cbSDimitry Andric                CIRToLLVMBrCondOpLowering,
2063*700637cbSDimitry Andric                CIRToLLVMBrOpLowering,
2064*700637cbSDimitry Andric                CIRToLLVMByteSwapOpLowering,
2065*700637cbSDimitry Andric                CIRToLLVMCallOpLowering,
2066*700637cbSDimitry Andric                CIRToLLVMCmpOpLowering,
2067*700637cbSDimitry Andric                CIRToLLVMComplexAddOpLowering,
2068*700637cbSDimitry Andric                CIRToLLVMComplexCreateOpLowering,
2069*700637cbSDimitry Andric                CIRToLLVMComplexImagOpLowering,
2070*700637cbSDimitry Andric                CIRToLLVMComplexImagPtrOpLowering,
2071*700637cbSDimitry Andric                CIRToLLVMComplexRealOpLowering,
2072*700637cbSDimitry Andric                CIRToLLVMComplexRealPtrOpLowering,
2073*700637cbSDimitry Andric                CIRToLLVMComplexSubOpLowering,
2074*700637cbSDimitry Andric                CIRToLLVMConstantOpLowering,
2075*700637cbSDimitry Andric                CIRToLLVMExpectOpLowering,
2076*700637cbSDimitry Andric                CIRToLLVMFuncOpLowering,
2077*700637cbSDimitry Andric                CIRToLLVMGetBitfieldOpLowering,
2078*700637cbSDimitry Andric                CIRToLLVMGetGlobalOpLowering,
2079*700637cbSDimitry Andric                CIRToLLVMGetMemberOpLowering,
2080*700637cbSDimitry Andric                CIRToLLVMSelectOpLowering,
2081*700637cbSDimitry Andric                CIRToLLVMSetBitfieldOpLowering,
2082*700637cbSDimitry Andric                CIRToLLVMShiftOpLowering,
2083*700637cbSDimitry Andric                CIRToLLVMStackRestoreOpLowering,
2084*700637cbSDimitry Andric                CIRToLLVMStackSaveOpLowering,
2085*700637cbSDimitry Andric                CIRToLLVMSwitchFlatOpLowering,
2086*700637cbSDimitry Andric                CIRToLLVMTrapOpLowering,
2087*700637cbSDimitry Andric                CIRToLLVMUnaryOpLowering,
2088*700637cbSDimitry Andric                CIRToLLVMVecCmpOpLowering,
2089*700637cbSDimitry Andric                CIRToLLVMVecCreateOpLowering,
2090*700637cbSDimitry Andric                CIRToLLVMVecExtractOpLowering,
2091*700637cbSDimitry Andric                CIRToLLVMVecInsertOpLowering,
2092*700637cbSDimitry Andric                CIRToLLVMVecShuffleDynamicOpLowering,
2093*700637cbSDimitry Andric                CIRToLLVMVecShuffleOpLowering,
2094*700637cbSDimitry Andric                CIRToLLVMVecSplatOpLowering,
2095*700637cbSDimitry Andric                CIRToLLVMVecTernaryOpLowering
2096*700637cbSDimitry Andric       // clang-format on
2097*700637cbSDimitry Andric       >(converter, patterns.getContext());
2098*700637cbSDimitry Andric 
2099*700637cbSDimitry Andric   processCIRAttrs(module);
2100*700637cbSDimitry Andric 
2101*700637cbSDimitry Andric   mlir::ConversionTarget target(getContext());
2102*700637cbSDimitry Andric   target.addLegalOp<mlir::ModuleOp>();
2103*700637cbSDimitry Andric   target.addLegalDialect<mlir::LLVM::LLVMDialect>();
2104*700637cbSDimitry Andric   target.addIllegalDialect<mlir::BuiltinDialect, cir::CIRDialect,
2105*700637cbSDimitry Andric                            mlir::func::FuncDialect>();
2106*700637cbSDimitry Andric 
2107*700637cbSDimitry Andric   llvm::SmallVector<mlir::Operation *> ops;
2108*700637cbSDimitry Andric   ops.push_back(module);
2109*700637cbSDimitry Andric   collectUnreachable(module, ops);
2110*700637cbSDimitry Andric 
2111*700637cbSDimitry Andric   if (failed(applyPartialConversion(ops, target, std::move(patterns))))
2112*700637cbSDimitry Andric     signalPassFailure();
2113*700637cbSDimitry Andric }
2114*700637cbSDimitry Andric 
matchAndRewrite(cir::BrOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2115*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMBrOpLowering::matchAndRewrite(
2116*700637cbSDimitry Andric     cir::BrOp op, OpAdaptor adaptor,
2117*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2118*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(op, adaptor.getOperands(),
2119*700637cbSDimitry Andric                                                 op.getDest());
2120*700637cbSDimitry Andric   return mlir::LogicalResult::success();
2121*700637cbSDimitry Andric }
2122*700637cbSDimitry Andric 
matchAndRewrite(cir::GetMemberOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2123*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMGetMemberOpLowering::matchAndRewrite(
2124*700637cbSDimitry Andric     cir::GetMemberOp op, OpAdaptor adaptor,
2125*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2126*700637cbSDimitry Andric   mlir::Type llResTy = getTypeConverter()->convertType(op.getType());
2127*700637cbSDimitry Andric   const auto recordTy =
2128*700637cbSDimitry Andric       mlir::cast<cir::RecordType>(op.getAddrTy().getPointee());
2129*700637cbSDimitry Andric   assert(recordTy && "expected record type");
2130*700637cbSDimitry Andric 
2131*700637cbSDimitry Andric   switch (recordTy.getKind()) {
2132*700637cbSDimitry Andric   case cir::RecordType::Class:
2133*700637cbSDimitry Andric   case cir::RecordType::Struct: {
2134*700637cbSDimitry Andric     // Since the base address is a pointer to an aggregate, the first offset
2135*700637cbSDimitry Andric     // is always zero. The second offset tell us which member it will access.
2136*700637cbSDimitry Andric     llvm::SmallVector<mlir::LLVM::GEPArg, 2> offset{0, op.getIndex()};
2137*700637cbSDimitry Andric     const mlir::Type elementTy = getTypeConverter()->convertType(recordTy);
2138*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(op, llResTy, elementTy,
2139*700637cbSDimitry Andric                                                    adaptor.getAddr(), offset);
2140*700637cbSDimitry Andric     return mlir::success();
2141*700637cbSDimitry Andric   }
2142*700637cbSDimitry Andric   case cir::RecordType::Union:
2143*700637cbSDimitry Andric     // Union members share the address space, so we just need a bitcast to
2144*700637cbSDimitry Andric     // conform to type-checking.
2145*700637cbSDimitry Andric     rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(op, llResTy,
2146*700637cbSDimitry Andric                                                        adaptor.getAddr());
2147*700637cbSDimitry Andric     return mlir::success();
2148*700637cbSDimitry Andric   }
2149*700637cbSDimitry Andric }
2150*700637cbSDimitry Andric 
matchAndRewrite(cir::TrapOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2151*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMTrapOpLowering::matchAndRewrite(
2152*700637cbSDimitry Andric     cir::TrapOp op, OpAdaptor adaptor,
2153*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2154*700637cbSDimitry Andric   mlir::Location loc = op->getLoc();
2155*700637cbSDimitry Andric   rewriter.eraseOp(op);
2156*700637cbSDimitry Andric 
2157*700637cbSDimitry Andric   rewriter.create<mlir::LLVM::Trap>(loc);
2158*700637cbSDimitry Andric 
2159*700637cbSDimitry Andric   // Note that the call to llvm.trap is not a terminator in LLVM dialect.
2160*700637cbSDimitry Andric   // So we must emit an additional llvm.unreachable to terminate the current
2161*700637cbSDimitry Andric   // block.
2162*700637cbSDimitry Andric   rewriter.create<mlir::LLVM::UnreachableOp>(loc);
2163*700637cbSDimitry Andric 
2164*700637cbSDimitry Andric   return mlir::success();
2165*700637cbSDimitry Andric }
2166*700637cbSDimitry Andric 
matchAndRewrite(cir::StackSaveOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2167*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMStackSaveOpLowering::matchAndRewrite(
2168*700637cbSDimitry Andric     cir::StackSaveOp op, OpAdaptor adaptor,
2169*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2170*700637cbSDimitry Andric   const mlir::Type ptrTy = getTypeConverter()->convertType(op.getType());
2171*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::StackSaveOp>(op, ptrTy);
2172*700637cbSDimitry Andric   return mlir::success();
2173*700637cbSDimitry Andric }
2174*700637cbSDimitry Andric 
matchAndRewrite(cir::StackRestoreOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2175*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMStackRestoreOpLowering::matchAndRewrite(
2176*700637cbSDimitry Andric     cir::StackRestoreOp op, OpAdaptor adaptor,
2177*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2178*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::StackRestoreOp>(op, adaptor.getPtr());
2179*700637cbSDimitry Andric   return mlir::success();
2180*700637cbSDimitry Andric }
2181*700637cbSDimitry Andric 
matchAndRewrite(cir::VecCreateOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2182*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecCreateOpLowering::matchAndRewrite(
2183*700637cbSDimitry Andric     cir::VecCreateOp op, OpAdaptor adaptor,
2184*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2185*700637cbSDimitry Andric   // Start with an 'undef' value for the vector.  Then 'insertelement' for
2186*700637cbSDimitry Andric   // each of the vector elements.
2187*700637cbSDimitry Andric   const auto vecTy = mlir::cast<cir::VectorType>(op.getType());
2188*700637cbSDimitry Andric   const mlir::Type llvmTy = typeConverter->convertType(vecTy);
2189*700637cbSDimitry Andric   const mlir::Location loc = op.getLoc();
2190*700637cbSDimitry Andric   mlir::Value result = rewriter.create<mlir::LLVM::PoisonOp>(loc, llvmTy);
2191*700637cbSDimitry Andric   assert(vecTy.getSize() == op.getElements().size() &&
2192*700637cbSDimitry Andric          "cir.vec.create op count doesn't match vector type elements count");
2193*700637cbSDimitry Andric 
2194*700637cbSDimitry Andric   for (uint64_t i = 0; i < vecTy.getSize(); ++i) {
2195*700637cbSDimitry Andric     const mlir::Value indexValue =
2196*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);
2197*700637cbSDimitry Andric     result = rewriter.create<mlir::LLVM::InsertElementOp>(
2198*700637cbSDimitry Andric         loc, result, adaptor.getElements()[i], indexValue);
2199*700637cbSDimitry Andric   }
2200*700637cbSDimitry Andric 
2201*700637cbSDimitry Andric   rewriter.replaceOp(op, result);
2202*700637cbSDimitry Andric   return mlir::success();
2203*700637cbSDimitry Andric }
2204*700637cbSDimitry Andric 
matchAndRewrite(cir::VecExtractOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2205*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecExtractOpLowering::matchAndRewrite(
2206*700637cbSDimitry Andric     cir::VecExtractOp op, OpAdaptor adaptor,
2207*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2208*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractElementOp>(
2209*700637cbSDimitry Andric       op, adaptor.getVec(), adaptor.getIndex());
2210*700637cbSDimitry Andric   return mlir::success();
2211*700637cbSDimitry Andric }
2212*700637cbSDimitry Andric 
matchAndRewrite(cir::VecInsertOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2213*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecInsertOpLowering::matchAndRewrite(
2214*700637cbSDimitry Andric     cir::VecInsertOp op, OpAdaptor adaptor,
2215*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2216*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::InsertElementOp>(
2217*700637cbSDimitry Andric       op, adaptor.getVec(), adaptor.getValue(), adaptor.getIndex());
2218*700637cbSDimitry Andric   return mlir::success();
2219*700637cbSDimitry Andric }
2220*700637cbSDimitry Andric 
matchAndRewrite(cir::VecCmpOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2221*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecCmpOpLowering::matchAndRewrite(
2222*700637cbSDimitry Andric     cir::VecCmpOp op, OpAdaptor adaptor,
2223*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2224*700637cbSDimitry Andric   mlir::Type elementType = elementTypeIfVector(op.getLhs().getType());
2225*700637cbSDimitry Andric   mlir::Value bitResult;
2226*700637cbSDimitry Andric   if (auto intType = mlir::dyn_cast<cir::IntType>(elementType)) {
2227*700637cbSDimitry Andric     bitResult = rewriter.create<mlir::LLVM::ICmpOp>(
2228*700637cbSDimitry Andric         op.getLoc(),
2229*700637cbSDimitry Andric         convertCmpKindToICmpPredicate(op.getKind(), intType.isSigned()),
2230*700637cbSDimitry Andric         adaptor.getLhs(), adaptor.getRhs());
2231*700637cbSDimitry Andric   } else if (mlir::isa<cir::FPTypeInterface>(elementType)) {
2232*700637cbSDimitry Andric     bitResult = rewriter.create<mlir::LLVM::FCmpOp>(
2233*700637cbSDimitry Andric         op.getLoc(), convertCmpKindToFCmpPredicate(op.getKind()),
2234*700637cbSDimitry Andric         adaptor.getLhs(), adaptor.getRhs());
2235*700637cbSDimitry Andric   } else {
2236*700637cbSDimitry Andric     return op.emitError() << "unsupported type for VecCmpOp: " << elementType;
2237*700637cbSDimitry Andric   }
2238*700637cbSDimitry Andric 
2239*700637cbSDimitry Andric   // LLVM IR vector comparison returns a vector of i1. This one-bit vector
2240*700637cbSDimitry Andric   // must be sign-extended to the correct result type.
2241*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(
2242*700637cbSDimitry Andric       op, typeConverter->convertType(op.getType()), bitResult);
2243*700637cbSDimitry Andric   return mlir::success();
2244*700637cbSDimitry Andric }
2245*700637cbSDimitry Andric 
matchAndRewrite(cir::VecSplatOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2246*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecSplatOpLowering::matchAndRewrite(
2247*700637cbSDimitry Andric     cir::VecSplatOp op, OpAdaptor adaptor,
2248*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2249*700637cbSDimitry Andric   // Vector splat can be implemented with an `insertelement` and a
2250*700637cbSDimitry Andric   // `shufflevector`, which is better than an `insertelement` for each
2251*700637cbSDimitry Andric   // element in the vector. Start with an undef vector. Insert the value into
2252*700637cbSDimitry Andric   // the first element. Then use a `shufflevector` with a mask of all 0 to
2253*700637cbSDimitry Andric   // fill out the entire vector with that value.
2254*700637cbSDimitry Andric   cir::VectorType vecTy = op.getType();
2255*700637cbSDimitry Andric   mlir::Type llvmTy = typeConverter->convertType(vecTy);
2256*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
2257*700637cbSDimitry Andric   mlir::Value poison = rewriter.create<mlir::LLVM::PoisonOp>(loc, llvmTy);
2258*700637cbSDimitry Andric 
2259*700637cbSDimitry Andric   mlir::Value elementValue = adaptor.getValue();
2260*700637cbSDimitry Andric   if (mlir::isa<mlir::LLVM::PoisonOp>(elementValue.getDefiningOp())) {
2261*700637cbSDimitry Andric     // If the splat value is poison, then we can just use poison value
2262*700637cbSDimitry Andric     // for the entire vector.
2263*700637cbSDimitry Andric     rewriter.replaceOp(op, poison);
2264*700637cbSDimitry Andric     return mlir::success();
2265*700637cbSDimitry Andric   }
2266*700637cbSDimitry Andric 
2267*700637cbSDimitry Andric   if (auto constValue =
2268*700637cbSDimitry Andric           dyn_cast<mlir::LLVM::ConstantOp>(elementValue.getDefiningOp())) {
2269*700637cbSDimitry Andric     if (auto intAttr = dyn_cast<mlir::IntegerAttr>(constValue.getValue())) {
2270*700637cbSDimitry Andric       mlir::DenseIntElementsAttr denseVec = mlir::DenseIntElementsAttr::get(
2271*700637cbSDimitry Andric           mlir::cast<mlir::ShapedType>(llvmTy), intAttr.getValue());
2272*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
2273*700637cbSDimitry Andric           op, denseVec.getType(), denseVec);
2274*700637cbSDimitry Andric       return mlir::success();
2275*700637cbSDimitry Andric     }
2276*700637cbSDimitry Andric 
2277*700637cbSDimitry Andric     if (auto fpAttr = dyn_cast<mlir::FloatAttr>(constValue.getValue())) {
2278*700637cbSDimitry Andric       mlir::DenseFPElementsAttr denseVec = mlir::DenseFPElementsAttr::get(
2279*700637cbSDimitry Andric           mlir::cast<mlir::ShapedType>(llvmTy), fpAttr.getValue());
2280*700637cbSDimitry Andric       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
2281*700637cbSDimitry Andric           op, denseVec.getType(), denseVec);
2282*700637cbSDimitry Andric       return mlir::success();
2283*700637cbSDimitry Andric     }
2284*700637cbSDimitry Andric   }
2285*700637cbSDimitry Andric 
2286*700637cbSDimitry Andric   mlir::Value indexValue =
2287*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), 0);
2288*700637cbSDimitry Andric   mlir::Value oneElement = rewriter.create<mlir::LLVM::InsertElementOp>(
2289*700637cbSDimitry Andric       loc, poison, elementValue, indexValue);
2290*700637cbSDimitry Andric   SmallVector<int32_t> zeroValues(vecTy.getSize(), 0);
2291*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(op, oneElement,
2292*700637cbSDimitry Andric                                                            poison, zeroValues);
2293*700637cbSDimitry Andric   return mlir::success();
2294*700637cbSDimitry Andric }
2295*700637cbSDimitry Andric 
matchAndRewrite(cir::VecShuffleOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2296*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecShuffleOpLowering::matchAndRewrite(
2297*700637cbSDimitry Andric     cir::VecShuffleOp op, OpAdaptor adaptor,
2298*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2299*700637cbSDimitry Andric   // LLVM::ShuffleVectorOp takes an ArrayRef of int for the list of indices.
2300*700637cbSDimitry Andric   // Convert the ClangIR ArrayAttr of IntAttr constants into a
2301*700637cbSDimitry Andric   // SmallVector<int>.
2302*700637cbSDimitry Andric   SmallVector<int, 8> indices;
2303*700637cbSDimitry Andric   std::transform(
2304*700637cbSDimitry Andric       op.getIndices().begin(), op.getIndices().end(),
2305*700637cbSDimitry Andric       std::back_inserter(indices), [](mlir::Attribute intAttr) {
2306*700637cbSDimitry Andric         return mlir::cast<cir::IntAttr>(intAttr).getValue().getSExtValue();
2307*700637cbSDimitry Andric       });
2308*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ShuffleVectorOp>(
2309*700637cbSDimitry Andric       op, adaptor.getVec1(), adaptor.getVec2(), indices);
2310*700637cbSDimitry Andric   return mlir::success();
2311*700637cbSDimitry Andric }
2312*700637cbSDimitry Andric 
matchAndRewrite(cir::VecShuffleDynamicOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2313*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecShuffleDynamicOpLowering::matchAndRewrite(
2314*700637cbSDimitry Andric     cir::VecShuffleDynamicOp op, OpAdaptor adaptor,
2315*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2316*700637cbSDimitry Andric   // LLVM IR does not have an operation that corresponds to this form of
2317*700637cbSDimitry Andric   // the built-in.
2318*700637cbSDimitry Andric   //     __builtin_shufflevector(V, I)
2319*700637cbSDimitry Andric   // is implemented as this pseudocode, where the for loop is unrolled
2320*700637cbSDimitry Andric   // and N is the number of elements:
2321*700637cbSDimitry Andric   //
2322*700637cbSDimitry Andric   // result = undef
2323*700637cbSDimitry Andric   // maskbits = NextPowerOf2(N - 1)
2324*700637cbSDimitry Andric   // masked = I & maskbits
2325*700637cbSDimitry Andric   // for (i in 0 <= i < N)
2326*700637cbSDimitry Andric   //    result[i] = V[masked[i]]
2327*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
2328*700637cbSDimitry Andric   mlir::Value input = adaptor.getVec();
2329*700637cbSDimitry Andric   mlir::Type llvmIndexVecType =
2330*700637cbSDimitry Andric       getTypeConverter()->convertType(op.getIndices().getType());
2331*700637cbSDimitry Andric   mlir::Type llvmIndexType = getTypeConverter()->convertType(
2332*700637cbSDimitry Andric       elementTypeIfVector(op.getIndices().getType()));
2333*700637cbSDimitry Andric   uint64_t numElements =
2334*700637cbSDimitry Andric       mlir::cast<cir::VectorType>(op.getVec().getType()).getSize();
2335*700637cbSDimitry Andric 
2336*700637cbSDimitry Andric   uint64_t maskBits = llvm::NextPowerOf2(numElements - 1) - 1;
2337*700637cbSDimitry Andric   mlir::Value maskValue = rewriter.create<mlir::LLVM::ConstantOp>(
2338*700637cbSDimitry Andric       loc, llvmIndexType, rewriter.getIntegerAttr(llvmIndexType, maskBits));
2339*700637cbSDimitry Andric   mlir::Value maskVector =
2340*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::UndefOp>(loc, llvmIndexVecType);
2341*700637cbSDimitry Andric 
2342*700637cbSDimitry Andric   for (uint64_t i = 0; i < numElements; ++i) {
2343*700637cbSDimitry Andric     mlir::Value idxValue =
2344*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);
2345*700637cbSDimitry Andric     maskVector = rewriter.create<mlir::LLVM::InsertElementOp>(
2346*700637cbSDimitry Andric         loc, maskVector, maskValue, idxValue);
2347*700637cbSDimitry Andric   }
2348*700637cbSDimitry Andric 
2349*700637cbSDimitry Andric   mlir::Value maskedIndices = rewriter.create<mlir::LLVM::AndOp>(
2350*700637cbSDimitry Andric       loc, llvmIndexVecType, adaptor.getIndices(), maskVector);
2351*700637cbSDimitry Andric   mlir::Value result = rewriter.create<mlir::LLVM::UndefOp>(
2352*700637cbSDimitry Andric       loc, getTypeConverter()->convertType(op.getVec().getType()));
2353*700637cbSDimitry Andric   for (uint64_t i = 0; i < numElements; ++i) {
2354*700637cbSDimitry Andric     mlir::Value iValue =
2355*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ConstantOp>(loc, rewriter.getI64Type(), i);
2356*700637cbSDimitry Andric     mlir::Value indexValue = rewriter.create<mlir::LLVM::ExtractElementOp>(
2357*700637cbSDimitry Andric         loc, maskedIndices, iValue);
2358*700637cbSDimitry Andric     mlir::Value valueAtIndex =
2359*700637cbSDimitry Andric         rewriter.create<mlir::LLVM::ExtractElementOp>(loc, input, indexValue);
2360*700637cbSDimitry Andric     result = rewriter.create<mlir::LLVM::InsertElementOp>(loc, result,
2361*700637cbSDimitry Andric                                                           valueAtIndex, iValue);
2362*700637cbSDimitry Andric   }
2363*700637cbSDimitry Andric   rewriter.replaceOp(op, result);
2364*700637cbSDimitry Andric   return mlir::success();
2365*700637cbSDimitry Andric }
2366*700637cbSDimitry Andric 
matchAndRewrite(cir::VecTernaryOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2367*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMVecTernaryOpLowering::matchAndRewrite(
2368*700637cbSDimitry Andric     cir::VecTernaryOp op, OpAdaptor adaptor,
2369*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2370*700637cbSDimitry Andric   // Convert `cond` into a vector of i1, then use that in a `select` op.
2371*700637cbSDimitry Andric   mlir::Value bitVec = rewriter.create<mlir::LLVM::ICmpOp>(
2372*700637cbSDimitry Andric       op.getLoc(), mlir::LLVM::ICmpPredicate::ne, adaptor.getCond(),
2373*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ZeroOp>(
2374*700637cbSDimitry Andric           op.getCond().getLoc(),
2375*700637cbSDimitry Andric           typeConverter->convertType(op.getCond().getType())));
2376*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::SelectOp>(
2377*700637cbSDimitry Andric       op, bitVec, adaptor.getLhs(), adaptor.getRhs());
2378*700637cbSDimitry Andric   return mlir::success();
2379*700637cbSDimitry Andric }
2380*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexAddOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2381*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexAddOpLowering::matchAndRewrite(
2382*700637cbSDimitry Andric     cir::ComplexAddOp op, OpAdaptor adaptor,
2383*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2384*700637cbSDimitry Andric   mlir::Value lhs = adaptor.getLhs();
2385*700637cbSDimitry Andric   mlir::Value rhs = adaptor.getRhs();
2386*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
2387*700637cbSDimitry Andric 
2388*700637cbSDimitry Andric   auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());
2389*700637cbSDimitry Andric   mlir::Type complexElemTy =
2390*700637cbSDimitry Andric       getTypeConverter()->convertType(complexType.getElementType());
2391*700637cbSDimitry Andric   auto lhsReal =
2392*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
2393*700637cbSDimitry Andric   auto lhsImag =
2394*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
2395*700637cbSDimitry Andric   auto rhsReal =
2396*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
2397*700637cbSDimitry Andric   auto rhsImag =
2398*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
2399*700637cbSDimitry Andric 
2400*700637cbSDimitry Andric   mlir::Value newReal;
2401*700637cbSDimitry Andric   mlir::Value newImag;
2402*700637cbSDimitry Andric   if (complexElemTy.isInteger()) {
2403*700637cbSDimitry Andric     newReal = rewriter.create<mlir::LLVM::AddOp>(loc, complexElemTy, lhsReal,
2404*700637cbSDimitry Andric                                                  rhsReal);
2405*700637cbSDimitry Andric     newImag = rewriter.create<mlir::LLVM::AddOp>(loc, complexElemTy, lhsImag,
2406*700637cbSDimitry Andric                                                  rhsImag);
2407*700637cbSDimitry Andric   } else {
2408*700637cbSDimitry Andric     assert(!cir::MissingFeatures::fastMathFlags());
2409*700637cbSDimitry Andric     assert(!cir::MissingFeatures::fpConstraints());
2410*700637cbSDimitry Andric     newReal = rewriter.create<mlir::LLVM::FAddOp>(loc, complexElemTy, lhsReal,
2411*700637cbSDimitry Andric                                                   rhsReal);
2412*700637cbSDimitry Andric     newImag = rewriter.create<mlir::LLVM::FAddOp>(loc, complexElemTy, lhsImag,
2413*700637cbSDimitry Andric                                                   rhsImag);
2414*700637cbSDimitry Andric   }
2415*700637cbSDimitry Andric 
2416*700637cbSDimitry Andric   mlir::Type complexLLVMTy =
2417*700637cbSDimitry Andric       getTypeConverter()->convertType(op.getResult().getType());
2418*700637cbSDimitry Andric   auto initialComplex =
2419*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::PoisonOp>(op->getLoc(), complexLLVMTy);
2420*700637cbSDimitry Andric 
2421*700637cbSDimitry Andric   auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(
2422*700637cbSDimitry Andric       op->getLoc(), initialComplex, newReal, 0);
2423*700637cbSDimitry Andric 
2424*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(op, realComplex,
2425*700637cbSDimitry Andric                                                          newImag, 1);
2426*700637cbSDimitry Andric 
2427*700637cbSDimitry Andric   return mlir::success();
2428*700637cbSDimitry Andric }
2429*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexCreateOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2430*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexCreateOpLowering::matchAndRewrite(
2431*700637cbSDimitry Andric     cir::ComplexCreateOp op, OpAdaptor adaptor,
2432*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2433*700637cbSDimitry Andric   mlir::Type complexLLVMTy =
2434*700637cbSDimitry Andric       getTypeConverter()->convertType(op.getResult().getType());
2435*700637cbSDimitry Andric   auto initialComplex =
2436*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::UndefOp>(op->getLoc(), complexLLVMTy);
2437*700637cbSDimitry Andric 
2438*700637cbSDimitry Andric   auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(
2439*700637cbSDimitry Andric       op->getLoc(), initialComplex, adaptor.getReal(), 0);
2440*700637cbSDimitry Andric 
2441*700637cbSDimitry Andric   auto complex = rewriter.create<mlir::LLVM::InsertValueOp>(
2442*700637cbSDimitry Andric       op->getLoc(), realComplex, adaptor.getImag(), 1);
2443*700637cbSDimitry Andric 
2444*700637cbSDimitry Andric   rewriter.replaceOp(op, complex);
2445*700637cbSDimitry Andric   return mlir::success();
2446*700637cbSDimitry Andric }
2447*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexRealOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2448*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexRealOpLowering::matchAndRewrite(
2449*700637cbSDimitry Andric     cir::ComplexRealOp op, OpAdaptor adaptor,
2450*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2451*700637cbSDimitry Andric   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
2452*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
2453*700637cbSDimitry Andric       op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{0});
2454*700637cbSDimitry Andric   return mlir::success();
2455*700637cbSDimitry Andric }
2456*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexSubOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2457*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexSubOpLowering::matchAndRewrite(
2458*700637cbSDimitry Andric     cir::ComplexSubOp op, OpAdaptor adaptor,
2459*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2460*700637cbSDimitry Andric   mlir::Value lhs = adaptor.getLhs();
2461*700637cbSDimitry Andric   mlir::Value rhs = adaptor.getRhs();
2462*700637cbSDimitry Andric   mlir::Location loc = op.getLoc();
2463*700637cbSDimitry Andric 
2464*700637cbSDimitry Andric   auto complexType = mlir::cast<cir::ComplexType>(op.getLhs().getType());
2465*700637cbSDimitry Andric   mlir::Type complexElemTy =
2466*700637cbSDimitry Andric       getTypeConverter()->convertType(complexType.getElementType());
2467*700637cbSDimitry Andric   auto lhsReal =
2468*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 0);
2469*700637cbSDimitry Andric   auto lhsImag =
2470*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, lhs, 1);
2471*700637cbSDimitry Andric   auto rhsReal =
2472*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 0);
2473*700637cbSDimitry Andric   auto rhsImag =
2474*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::ExtractValueOp>(loc, complexElemTy, rhs, 1);
2475*700637cbSDimitry Andric 
2476*700637cbSDimitry Andric   mlir::Value newReal;
2477*700637cbSDimitry Andric   mlir::Value newImag;
2478*700637cbSDimitry Andric   if (complexElemTy.isInteger()) {
2479*700637cbSDimitry Andric     newReal = rewriter.create<mlir::LLVM::SubOp>(loc, complexElemTy, lhsReal,
2480*700637cbSDimitry Andric                                                  rhsReal);
2481*700637cbSDimitry Andric     newImag = rewriter.create<mlir::LLVM::SubOp>(loc, complexElemTy, lhsImag,
2482*700637cbSDimitry Andric                                                  rhsImag);
2483*700637cbSDimitry Andric   } else {
2484*700637cbSDimitry Andric     assert(!cir::MissingFeatures::fastMathFlags());
2485*700637cbSDimitry Andric     assert(!cir::MissingFeatures::fpConstraints());
2486*700637cbSDimitry Andric     newReal = rewriter.create<mlir::LLVM::FSubOp>(loc, complexElemTy, lhsReal,
2487*700637cbSDimitry Andric                                                   rhsReal);
2488*700637cbSDimitry Andric     newImag = rewriter.create<mlir::LLVM::FSubOp>(loc, complexElemTy, lhsImag,
2489*700637cbSDimitry Andric                                                   rhsImag);
2490*700637cbSDimitry Andric   }
2491*700637cbSDimitry Andric 
2492*700637cbSDimitry Andric   mlir::Type complexLLVMTy =
2493*700637cbSDimitry Andric       getTypeConverter()->convertType(op.getResult().getType());
2494*700637cbSDimitry Andric   auto initialComplex =
2495*700637cbSDimitry Andric       rewriter.create<mlir::LLVM::PoisonOp>(op->getLoc(), complexLLVMTy);
2496*700637cbSDimitry Andric 
2497*700637cbSDimitry Andric   auto realComplex = rewriter.create<mlir::LLVM::InsertValueOp>(
2498*700637cbSDimitry Andric       op->getLoc(), initialComplex, newReal, 0);
2499*700637cbSDimitry Andric 
2500*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(op, realComplex,
2501*700637cbSDimitry Andric                                                          newImag, 1);
2502*700637cbSDimitry Andric 
2503*700637cbSDimitry Andric   return mlir::success();
2504*700637cbSDimitry Andric }
2505*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexImagOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2506*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexImagOpLowering::matchAndRewrite(
2507*700637cbSDimitry Andric     cir::ComplexImagOp op, OpAdaptor adaptor,
2508*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2509*700637cbSDimitry Andric   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
2510*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
2511*700637cbSDimitry Andric       op, resultLLVMTy, adaptor.getOperand(), llvm::ArrayRef<std::int64_t>{1});
2512*700637cbSDimitry Andric   return mlir::success();
2513*700637cbSDimitry Andric }
2514*700637cbSDimitry Andric 
computeBitfieldIntType(mlir::Type storageType,mlir::MLIRContext * context,unsigned & storageSize)2515*700637cbSDimitry Andric mlir::IntegerType computeBitfieldIntType(mlir::Type storageType,
2516*700637cbSDimitry Andric                                          mlir::MLIRContext *context,
2517*700637cbSDimitry Andric                                          unsigned &storageSize) {
2518*700637cbSDimitry Andric   return TypeSwitch<mlir::Type, mlir::IntegerType>(storageType)
2519*700637cbSDimitry Andric       .Case<cir::ArrayType>([&](cir::ArrayType atTy) {
2520*700637cbSDimitry Andric         storageSize = atTy.getSize() * 8;
2521*700637cbSDimitry Andric         return mlir::IntegerType::get(context, storageSize);
2522*700637cbSDimitry Andric       })
2523*700637cbSDimitry Andric       .Case<cir::IntType>([&](cir::IntType intTy) {
2524*700637cbSDimitry Andric         storageSize = intTy.getWidth();
2525*700637cbSDimitry Andric         return mlir::IntegerType::get(context, storageSize);
2526*700637cbSDimitry Andric       })
2527*700637cbSDimitry Andric       .Default([](mlir::Type) -> mlir::IntegerType {
2528*700637cbSDimitry Andric         llvm_unreachable(
2529*700637cbSDimitry Andric             "Either ArrayType or IntType expected for bitfields storage");
2530*700637cbSDimitry Andric       });
2531*700637cbSDimitry Andric }
2532*700637cbSDimitry Andric 
matchAndRewrite(cir::SetBitfieldOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2533*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMSetBitfieldOpLowering::matchAndRewrite(
2534*700637cbSDimitry Andric     cir::SetBitfieldOp op, OpAdaptor adaptor,
2535*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2536*700637cbSDimitry Andric   mlir::OpBuilder::InsertionGuard guard(rewriter);
2537*700637cbSDimitry Andric   rewriter.setInsertionPoint(op);
2538*700637cbSDimitry Andric 
2539*700637cbSDimitry Andric   cir::BitfieldInfoAttr info = op.getBitfieldInfo();
2540*700637cbSDimitry Andric   uint64_t size = info.getSize();
2541*700637cbSDimitry Andric   uint64_t offset = info.getOffset();
2542*700637cbSDimitry Andric   mlir::Type storageType = info.getStorageType();
2543*700637cbSDimitry Andric   mlir::MLIRContext *context = storageType.getContext();
2544*700637cbSDimitry Andric 
2545*700637cbSDimitry Andric   unsigned storageSize = 0;
2546*700637cbSDimitry Andric 
2547*700637cbSDimitry Andric   mlir::IntegerType intType =
2548*700637cbSDimitry Andric       computeBitfieldIntType(storageType, context, storageSize);
2549*700637cbSDimitry Andric 
2550*700637cbSDimitry Andric   mlir::Value srcVal = createIntCast(rewriter, adaptor.getSrc(), intType);
2551*700637cbSDimitry Andric   unsigned srcWidth = storageSize;
2552*700637cbSDimitry Andric   mlir::Value resultVal = srcVal;
2553*700637cbSDimitry Andric 
2554*700637cbSDimitry Andric   if (storageSize != size) {
2555*700637cbSDimitry Andric     assert(storageSize > size && "Invalid bitfield size.");
2556*700637cbSDimitry Andric 
2557*700637cbSDimitry Andric     mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(
2558*700637cbSDimitry Andric         op.getLoc(), intType, adaptor.getAddr(), /* alignment */ 0,
2559*700637cbSDimitry Andric         op.getIsVolatile());
2560*700637cbSDimitry Andric 
2561*700637cbSDimitry Andric     srcVal =
2562*700637cbSDimitry Andric         createAnd(rewriter, srcVal, llvm::APInt::getLowBitsSet(srcWidth, size));
2563*700637cbSDimitry Andric     resultVal = srcVal;
2564*700637cbSDimitry Andric     srcVal = createShL(rewriter, srcVal, offset);
2565*700637cbSDimitry Andric 
2566*700637cbSDimitry Andric     // Mask out the original value.
2567*700637cbSDimitry Andric     val = createAnd(rewriter, val,
2568*700637cbSDimitry Andric                     ~llvm::APInt::getBitsSet(srcWidth, offset, offset + size));
2569*700637cbSDimitry Andric 
2570*700637cbSDimitry Andric     // Or together the unchanged values and the source value.
2571*700637cbSDimitry Andric     srcVal = rewriter.create<mlir::LLVM::OrOp>(op.getLoc(), val, srcVal);
2572*700637cbSDimitry Andric   }
2573*700637cbSDimitry Andric 
2574*700637cbSDimitry Andric   rewriter.create<mlir::LLVM::StoreOp>(op.getLoc(), srcVal, adaptor.getAddr(),
2575*700637cbSDimitry Andric                                        /* alignment */ 0, op.getIsVolatile());
2576*700637cbSDimitry Andric 
2577*700637cbSDimitry Andric   mlir::Type resultTy = getTypeConverter()->convertType(op.getType());
2578*700637cbSDimitry Andric 
2579*700637cbSDimitry Andric   if (info.getIsSigned()) {
2580*700637cbSDimitry Andric     assert(size <= storageSize);
2581*700637cbSDimitry Andric     unsigned highBits = storageSize - size;
2582*700637cbSDimitry Andric 
2583*700637cbSDimitry Andric     if (highBits) {
2584*700637cbSDimitry Andric       resultVal = createShL(rewriter, resultVal, highBits);
2585*700637cbSDimitry Andric       resultVal = createAShR(rewriter, resultVal, highBits);
2586*700637cbSDimitry Andric     }
2587*700637cbSDimitry Andric   }
2588*700637cbSDimitry Andric 
2589*700637cbSDimitry Andric   resultVal = createIntCast(rewriter, resultVal,
2590*700637cbSDimitry Andric                             mlir::cast<mlir::IntegerType>(resultTy),
2591*700637cbSDimitry Andric                             info.getIsSigned());
2592*700637cbSDimitry Andric 
2593*700637cbSDimitry Andric   rewriter.replaceOp(op, resultVal);
2594*700637cbSDimitry Andric   return mlir::success();
2595*700637cbSDimitry Andric }
2596*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexImagPtrOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2597*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexImagPtrOpLowering::matchAndRewrite(
2598*700637cbSDimitry Andric     cir::ComplexImagPtrOp op, OpAdaptor adaptor,
2599*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2600*700637cbSDimitry Andric   cir::PointerType operandTy = op.getOperand().getType();
2601*700637cbSDimitry Andric   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
2602*700637cbSDimitry Andric   mlir::Type elementLLVMTy =
2603*700637cbSDimitry Andric       getTypeConverter()->convertType(operandTy.getPointee());
2604*700637cbSDimitry Andric 
2605*700637cbSDimitry Andric   mlir::LLVM::GEPArg gepIndices[2] = {{0}, {1}};
2606*700637cbSDimitry Andric   mlir::LLVM::GEPNoWrapFlags inboundsNuw =
2607*700637cbSDimitry Andric       mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;
2608*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
2609*700637cbSDimitry Andric       op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,
2610*700637cbSDimitry Andric       inboundsNuw);
2611*700637cbSDimitry Andric   return mlir::success();
2612*700637cbSDimitry Andric }
2613*700637cbSDimitry Andric 
matchAndRewrite(cir::ComplexRealPtrOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2614*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMComplexRealPtrOpLowering::matchAndRewrite(
2615*700637cbSDimitry Andric     cir::ComplexRealPtrOp op, OpAdaptor adaptor,
2616*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2617*700637cbSDimitry Andric   cir::PointerType operandTy = op.getOperand().getType();
2618*700637cbSDimitry Andric   mlir::Type resultLLVMTy = getTypeConverter()->convertType(op.getType());
2619*700637cbSDimitry Andric   mlir::Type elementLLVMTy =
2620*700637cbSDimitry Andric       getTypeConverter()->convertType(operandTy.getPointee());
2621*700637cbSDimitry Andric 
2622*700637cbSDimitry Andric   mlir::LLVM::GEPArg gepIndices[2] = {0, 0};
2623*700637cbSDimitry Andric   mlir::LLVM::GEPNoWrapFlags inboundsNuw =
2624*700637cbSDimitry Andric       mlir::LLVM::GEPNoWrapFlags::inbounds | mlir::LLVM::GEPNoWrapFlags::nuw;
2625*700637cbSDimitry Andric   rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
2626*700637cbSDimitry Andric       op, resultLLVMTy, elementLLVMTy, adaptor.getOperand(), gepIndices,
2627*700637cbSDimitry Andric       inboundsNuw);
2628*700637cbSDimitry Andric   return mlir::success();
2629*700637cbSDimitry Andric }
2630*700637cbSDimitry Andric 
matchAndRewrite(cir::GetBitfieldOp op,OpAdaptor adaptor,mlir::ConversionPatternRewriter & rewriter) const2631*700637cbSDimitry Andric mlir::LogicalResult CIRToLLVMGetBitfieldOpLowering::matchAndRewrite(
2632*700637cbSDimitry Andric     cir::GetBitfieldOp op, OpAdaptor adaptor,
2633*700637cbSDimitry Andric     mlir::ConversionPatternRewriter &rewriter) const {
2634*700637cbSDimitry Andric 
2635*700637cbSDimitry Andric   mlir::OpBuilder::InsertionGuard guard(rewriter);
2636*700637cbSDimitry Andric   rewriter.setInsertionPoint(op);
2637*700637cbSDimitry Andric 
2638*700637cbSDimitry Andric   cir::BitfieldInfoAttr info = op.getBitfieldInfo();
2639*700637cbSDimitry Andric   uint64_t size = info.getSize();
2640*700637cbSDimitry Andric   uint64_t offset = info.getOffset();
2641*700637cbSDimitry Andric   mlir::Type storageType = info.getStorageType();
2642*700637cbSDimitry Andric   mlir::MLIRContext *context = storageType.getContext();
2643*700637cbSDimitry Andric   unsigned storageSize = 0;
2644*700637cbSDimitry Andric 
2645*700637cbSDimitry Andric   mlir::IntegerType intType =
2646*700637cbSDimitry Andric       computeBitfieldIntType(storageType, context, storageSize);
2647*700637cbSDimitry Andric 
2648*700637cbSDimitry Andric   mlir::Value val = rewriter.create<mlir::LLVM::LoadOp>(
2649*700637cbSDimitry Andric       op.getLoc(), intType, adaptor.getAddr(), 0, op.getIsVolatile());
2650*700637cbSDimitry Andric   val = rewriter.create<mlir::LLVM::BitcastOp>(op.getLoc(), intType, val);
2651*700637cbSDimitry Andric 
2652*700637cbSDimitry Andric   if (info.getIsSigned()) {
2653*700637cbSDimitry Andric     assert(static_cast<unsigned>(offset + size) <= storageSize);
2654*700637cbSDimitry Andric     unsigned highBits = storageSize - offset - size;
2655*700637cbSDimitry Andric     val = createShL(rewriter, val, highBits);
2656*700637cbSDimitry Andric     val = createAShR(rewriter, val, offset + highBits);
2657*700637cbSDimitry Andric   } else {
2658*700637cbSDimitry Andric     val = createLShR(rewriter, val, offset);
2659*700637cbSDimitry Andric 
2660*700637cbSDimitry Andric     if (static_cast<unsigned>(offset) + size < storageSize)
2661*700637cbSDimitry Andric       val = createAnd(rewriter, val,
2662*700637cbSDimitry Andric                       llvm::APInt::getLowBitsSet(storageSize, size));
2663*700637cbSDimitry Andric   }
2664*700637cbSDimitry Andric 
2665*700637cbSDimitry Andric   mlir::Type resTy = getTypeConverter()->convertType(op.getType());
2666*700637cbSDimitry Andric   mlir::Value newOp = createIntCast(
2667*700637cbSDimitry Andric       rewriter, val, mlir::cast<mlir::IntegerType>(resTy), info.getIsSigned());
2668*700637cbSDimitry Andric   rewriter.replaceOp(op, newOp);
2669*700637cbSDimitry Andric   return mlir::success();
2670*700637cbSDimitry Andric }
2671*700637cbSDimitry Andric 
createConvertCIRToLLVMPass()2672*700637cbSDimitry Andric std::unique_ptr<mlir::Pass> createConvertCIRToLLVMPass() {
2673*700637cbSDimitry Andric   return std::make_unique<ConvertCIRToLLVMPass>();
2674*700637cbSDimitry Andric }
2675*700637cbSDimitry Andric 
populateCIRToLLVMPasses(mlir::OpPassManager & pm)2676*700637cbSDimitry Andric void populateCIRToLLVMPasses(mlir::OpPassManager &pm) {
2677*700637cbSDimitry Andric   mlir::populateCIRPreLoweringPasses(pm);
2678*700637cbSDimitry Andric   pm.addPass(createConvertCIRToLLVMPass());
2679*700637cbSDimitry Andric }
2680*700637cbSDimitry Andric 
2681*700637cbSDimitry Andric std::unique_ptr<llvm::Module>
lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule,LLVMContext & llvmCtx)2682*700637cbSDimitry Andric lowerDirectlyFromCIRToLLVMIR(mlir::ModuleOp mlirModule, LLVMContext &llvmCtx) {
2683*700637cbSDimitry Andric   llvm::TimeTraceScope scope("lower from CIR to LLVM directly");
2684*700637cbSDimitry Andric 
2685*700637cbSDimitry Andric   mlir::MLIRContext *mlirCtx = mlirModule.getContext();
2686*700637cbSDimitry Andric 
2687*700637cbSDimitry Andric   mlir::PassManager pm(mlirCtx);
2688*700637cbSDimitry Andric   populateCIRToLLVMPasses(pm);
2689*700637cbSDimitry Andric 
2690*700637cbSDimitry Andric   (void)mlir::applyPassManagerCLOptions(pm);
2691*700637cbSDimitry Andric 
2692*700637cbSDimitry Andric   if (mlir::failed(pm.run(mlirModule))) {
2693*700637cbSDimitry Andric     // FIXME: Handle any errors where they occurs and return a nullptr here.
2694*700637cbSDimitry Andric     report_fatal_error(
2695*700637cbSDimitry Andric         "The pass manager failed to lower CIR to LLVMIR dialect!");
2696*700637cbSDimitry Andric   }
2697*700637cbSDimitry Andric 
2698*700637cbSDimitry Andric   mlir::registerBuiltinDialectTranslation(*mlirCtx);
2699*700637cbSDimitry Andric   mlir::registerLLVMDialectTranslation(*mlirCtx);
2700*700637cbSDimitry Andric   mlir::registerCIRDialectTranslation(*mlirCtx);
2701*700637cbSDimitry Andric 
2702*700637cbSDimitry Andric   llvm::TimeTraceScope translateScope("translateModuleToLLVMIR");
2703*700637cbSDimitry Andric 
2704*700637cbSDimitry Andric   StringRef moduleName = mlirModule.getName().value_or("CIRToLLVMModule");
2705*700637cbSDimitry Andric   std::unique_ptr<llvm::Module> llvmModule =
2706*700637cbSDimitry Andric       mlir::translateModuleToLLVMIR(mlirModule, llvmCtx, moduleName);
2707*700637cbSDimitry Andric 
2708*700637cbSDimitry Andric   if (!llvmModule) {
2709*700637cbSDimitry Andric     // FIXME: Handle any errors where they occurs and return a nullptr here.
2710*700637cbSDimitry Andric     report_fatal_error("Lowering from LLVMIR dialect to llvm IR failed!");
2711*700637cbSDimitry Andric   }
2712*700637cbSDimitry Andric 
2713*700637cbSDimitry Andric   return llvmModule;
2714*700637cbSDimitry Andric }
2715*700637cbSDimitry Andric } // namespace direct
2716*700637cbSDimitry Andric } // namespace cir
2717