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 ®istry) 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