1044d5b5dSValentin Clement //===-- CodeGen.cpp -- bridge to lower to LLVM ----------------------------===//
2044d5b5dSValentin Clement //
3044d5b5dSValentin Clement // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4044d5b5dSValentin Clement // See https://llvm.org/LICENSE.txt for license information.
5044d5b5dSValentin Clement // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6044d5b5dSValentin Clement //
7044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
8044d5b5dSValentin Clement //
9044d5b5dSValentin Clement // Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
10044d5b5dSValentin Clement //
11044d5b5dSValentin Clement //===----------------------------------------------------------------------===//
12044d5b5dSValentin Clement 
13044d5b5dSValentin Clement #include "flang/Optimizer/CodeGen/CodeGen.h"
14044d5b5dSValentin Clement #include "PassDetail.h"
15*b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
16044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIRType.h"
187b5132daSValentin Clement #include "flang/Optimizer/Support/FIRContext.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/TypeConverter.h"
22044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
23044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
243ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
25044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
26044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
27044d5b5dSValentin Clement 
28044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
29044d5b5dSValentin Clement 
30044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
31044d5b5dSValentin Clement #include "TypeConverter.h"
32044d5b5dSValentin Clement 
33*b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
34*b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
35*b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
36*b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
37*b6e44ecdSValentin Clement 
38044d5b5dSValentin Clement namespace {
39044d5b5dSValentin Clement /// FIR conversion pattern template
40044d5b5dSValentin Clement template <typename FromOp>
41044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
42044d5b5dSValentin Clement public:
43044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
44044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
45044d5b5dSValentin Clement 
46044d5b5dSValentin Clement protected:
47044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
48044d5b5dSValentin Clement     return lowerTy().convertType(ty);
49044d5b5dSValentin Clement   }
50044d5b5dSValentin Clement 
51df3b9810SValentin Clement   mlir::LLVM::ConstantOp
52df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
53df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
54df3b9810SValentin Clement                     int offset) const {
55df3b9810SValentin Clement     auto ity = lowerTy().offsetType();
56df3b9810SValentin Clement     auto cattr = rewriter.getI32IntegerAttr(offset);
57df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
58df3b9810SValentin Clement   }
59df3b9810SValentin Clement 
60*b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
61*b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
62df3b9810SValentin Clement                               mlir::Type resultTy,
63*b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
64*b6e44ecdSValentin Clement                               unsigned boxValue) const {
65df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
66*b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
67*b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
68df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
69df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
70*b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
71df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
72df3b9810SValentin Clement   }
73df3b9810SValentin Clement 
74df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
75df3b9810SValentin Clement   /// from a box.
76df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
77df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
78df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
79df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
80df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
81df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
82df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
83df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
84df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
85df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
86df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
87df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
88df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
89df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
90df3b9810SValentin Clement   }
91df3b9810SValentin Clement 
92df3b9810SValentin Clement   mlir::LLVM::LoadOp
93df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
94df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
95df3b9810SValentin Clement                  mlir::Type ty,
96df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
97df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
98df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
99df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
100df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
101df3b9810SValentin Clement   }
102df3b9810SValentin Clement 
103df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
104df3b9810SValentin Clement   mlir::Value
105df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
106df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
107df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
108df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
109df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
110df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
111df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
112df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
113df3b9810SValentin Clement   }
114df3b9810SValentin Clement 
115df3b9810SValentin Clement   mlir::Value
116df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
117df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
118df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
119df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
120df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
121df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
122df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
123df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
124df3b9810SValentin Clement   }
125df3b9810SValentin Clement 
126*b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
127*b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
128*b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
129*b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
130*b6e44ecdSValentin Clement                                    unsigned maskValue) const {
131*b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
132*b6e44ecdSValentin Clement     mlir::Value attribute =
133*b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
134*b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
135*b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
136*b6e44ecdSValentin Clement     auto maskRes =
137*b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
138*b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
139*b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
140*b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
141*b6e44ecdSValentin Clement   }
142*b6e44ecdSValentin Clement 
143df3b9810SValentin Clement   template <typename... ARGS>
144df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
145df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
146df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
147df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
148df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
149df3b9810SValentin Clement   }
150df3b9810SValentin Clement 
151044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
152044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
153044d5b5dSValentin Clement   }
154044d5b5dSValentin Clement };
155044d5b5dSValentin Clement 
1563ae8e442SValentin Clement /// FIR conversion pattern template
1573ae8e442SValentin Clement template <typename FromOp>
1583ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
1593ae8e442SValentin Clement public:
1603ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
1613ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
1623ae8e442SValentin Clement 
1633ae8e442SValentin Clement   mlir::LogicalResult
1643ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
1653ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
1663ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
1673ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
1683ae8e442SValentin Clement   }
1693ae8e442SValentin Clement 
1703ae8e442SValentin Clement   virtual mlir::LogicalResult
1713ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
1723ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
1733ae8e442SValentin Clement };
1743ae8e442SValentin Clement 
1750c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
176044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
177044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
178044d5b5dSValentin Clement 
179044d5b5dSValentin Clement   mlir::LogicalResult
180044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
181044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
182044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
183044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
184044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
185044d5b5dSValentin Clement     return success();
186044d5b5dSValentin Clement   }
187044d5b5dSValentin Clement };
188044d5b5dSValentin Clement 
189df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
190df3b9810SValentin Clement /// element of the box.
191df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
192df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
193df3b9810SValentin Clement 
194df3b9810SValentin Clement   mlir::LogicalResult
195df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
196df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
197df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
198df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
199df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
200df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
201df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
202df3b9810SValentin Clement     } else {
203df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
204df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
205df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
206df3b9810SValentin Clement                                                               c0);
207df3b9810SValentin Clement     }
208df3b9810SValentin Clement     return success();
209df3b9810SValentin Clement   }
210df3b9810SValentin Clement };
211df3b9810SValentin Clement 
212df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
213df3b9810SValentin Clement /// dimension infomartion from the boxed value.
214df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
215df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
216df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
217df3b9810SValentin Clement 
218df3b9810SValentin Clement   mlir::LogicalResult
219df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
220df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
221df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
222df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
223df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
224df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
225df3b9810SValentin Clement     };
226df3b9810SValentin Clement     auto results =
227df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
228df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
229df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
230df3b9810SValentin Clement     return success();
231df3b9810SValentin Clement   }
232df3b9810SValentin Clement };
233df3b9810SValentin Clement 
234df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
235df3b9810SValentin Clement /// an element in the boxed value.
236df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
237df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
238df3b9810SValentin Clement 
239df3b9810SValentin Clement   mlir::LogicalResult
240df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
241df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
242df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
243df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
244df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
245*b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
246*b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
247*b6e44ecdSValentin Clement     return success();
248*b6e44ecdSValentin Clement   }
249*b6e44ecdSValentin Clement };
250*b6e44ecdSValentin Clement 
251*b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
252*b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
253*b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
254*b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
255*b6e44ecdSValentin Clement 
256*b6e44ecdSValentin Clement   mlir::LogicalResult
257*b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
258*b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
259*b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
260*b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
261*b6e44ecdSValentin Clement     mlir::Value check =
262*b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
263*b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
264*b6e44ecdSValentin Clement     return success();
265*b6e44ecdSValentin Clement   }
266*b6e44ecdSValentin Clement };
267*b6e44ecdSValentin Clement 
268*b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
269*b6e44ecdSValentin Clement /// boxed is an array.
270*b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
271*b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
272*b6e44ecdSValentin Clement 
273*b6e44ecdSValentin Clement   mlir::LogicalResult
274*b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
275*b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
276*b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
277*b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
278*b6e44ecdSValentin Clement     auto rank =
279*b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
280*b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
281*b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
282*b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
283*b6e44ecdSValentin Clement     return success();
284*b6e44ecdSValentin Clement   }
285*b6e44ecdSValentin Clement };
286*b6e44ecdSValentin Clement 
287*b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
288*b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
289*b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
290*b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
291*b6e44ecdSValentin Clement 
292*b6e44ecdSValentin Clement   mlir::LogicalResult
293*b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
294*b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
295*b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
296*b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
297*b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
298*b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
299df3b9810SValentin Clement     return success();
300df3b9810SValentin Clement   }
301df3b9810SValentin Clement };
302df3b9810SValentin Clement 
303df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
304df3b9810SValentin Clement /// the box.
305df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
306df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
307df3b9810SValentin Clement 
308df3b9810SValentin Clement   mlir::LogicalResult
309df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
310df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
311df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
312df3b9810SValentin Clement     auto loc = boxrank.getLoc();
313df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
314*b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
315df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
316df3b9810SValentin Clement     return success();
317df3b9810SValentin Clement   }
318df3b9810SValentin Clement };
319df3b9810SValentin Clement 
320ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
321ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
322ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
323ddd11b9aSAndrzej Warzynski 
324ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
325ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
326ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
327ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
328ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
329ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
330ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
331ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
332ddd11b9aSAndrzej Warzynski     return success();
333ddd11b9aSAndrzej Warzynski   }
334ddd11b9aSAndrzej Warzynski };
335ddd11b9aSAndrzej Warzynski 
336092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
337092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
338092cee5fSValentin Clement     return cc.getElementType();
339092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
340092cee5fSValentin Clement }
341092cee5fSValentin Clement 
342092cee5fSValentin Clement /// convert value of from-type to value of to-type
343092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
344092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
345092cee5fSValentin Clement 
346092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
347092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
348092cee5fSValentin Clement   }
349092cee5fSValentin Clement 
350092cee5fSValentin Clement   mlir::LogicalResult
351092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
352092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
353092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
354092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
355092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
356092cee5fSValentin Clement     if (fromTy == toTy) {
357092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
358092cee5fSValentin Clement       return success();
359092cee5fSValentin Clement     }
360092cee5fSValentin Clement     auto loc = convert.getLoc();
361092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
362092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
363092cee5fSValentin Clement       if (fromBits == toBits) {
364092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
365092cee5fSValentin Clement         // same bitwidth is not allowed for now.
366092cee5fSValentin Clement         mlir::emitError(loc,
367092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
368092cee5fSValentin Clement                         "representations of the same bitwidth");
369092cee5fSValentin Clement         return {};
370092cee5fSValentin Clement       }
371092cee5fSValentin Clement       if (fromBits > toBits)
372092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
373092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
374092cee5fSValentin Clement     };
375092cee5fSValentin Clement     // Complex to complex conversion.
376092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
377092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
378092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
379092cee5fSValentin Clement       // real and imaginary parts are converted together.
380092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
381092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
382092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
383092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
384092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
385092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
386092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
387092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
388092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
389092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
390092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
391092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
392092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
393092cee5fSValentin Clement       auto i1 =
394092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
395092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
396092cee5fSValentin Clement                                                              ic, one);
397092cee5fSValentin Clement       return mlir::success();
398092cee5fSValentin Clement     }
399092cee5fSValentin Clement     // Floating point to floating point conversion.
400092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
401092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
402092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
403092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
404092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
405092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
406092cee5fSValentin Clement         return mlir::success();
407092cee5fSValentin Clement       }
408092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
409092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
410092cee5fSValentin Clement         return mlir::success();
411092cee5fSValentin Clement       }
412092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
413092cee5fSValentin Clement       // Integer to integer conversion.
414092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
415092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
416092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
417092cee5fSValentin Clement         assert(fromBits != toBits);
418092cee5fSValentin Clement         if (fromBits > toBits) {
419092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
420092cee5fSValentin Clement           return mlir::success();
421092cee5fSValentin Clement         }
422092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
423092cee5fSValentin Clement         return mlir::success();
424092cee5fSValentin Clement       }
425092cee5fSValentin Clement       // Integer to floating point conversion.
426092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
427092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
428092cee5fSValentin Clement         return mlir::success();
429092cee5fSValentin Clement       }
430092cee5fSValentin Clement       // Integer to pointer conversion.
431092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
432092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
433092cee5fSValentin Clement         return mlir::success();
434092cee5fSValentin Clement       }
435092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
436092cee5fSValentin Clement       // Pointer to integer conversion.
437092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
438092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
439092cee5fSValentin Clement         return mlir::success();
440092cee5fSValentin Clement       }
441092cee5fSValentin Clement       // Pointer to pointer conversion.
442092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
443092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
444092cee5fSValentin Clement         return mlir::success();
445092cee5fSValentin Clement       }
446092cee5fSValentin Clement     }
447092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
448092cee5fSValentin Clement   }
449092cee5fSValentin Clement };
450092cee5fSValentin Clement 
4510c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
452044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
453044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
454044d5b5dSValentin Clement 
455044d5b5dSValentin Clement   mlir::LogicalResult
456044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
457044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
458044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
459044d5b5dSValentin Clement     return success();
460044d5b5dSValentin Clement   }
461044d5b5dSValentin Clement };
462044d5b5dSValentin Clement 
4630c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
4640c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
4650c4a7a52SValentin Clement /// if they are applied on the full range.
466044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
467044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
468044d5b5dSValentin Clement 
469044d5b5dSValentin Clement   mlir::LogicalResult
470044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
471044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
472044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
473044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
474044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
475044d5b5dSValentin Clement     auto loc = global.getLoc();
476044d5b5dSValentin Clement     mlir::Attribute initAttr{};
477044d5b5dSValentin Clement     if (global.initVal())
478044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
479044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
480044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
481044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
482044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
483044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
484044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
485044d5b5dSValentin Clement     if (!gr.empty()) {
486044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
487044d5b5dSValentin Clement       // initialization is on the full range.
488044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
489044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
490044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
491044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
492044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
493044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
494044d5b5dSValentin Clement           if (!constant) {
495044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
496044d5b5dSValentin Clement             if (!convertOp)
497044d5b5dSValentin Clement               continue;
498044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
499044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
500044d5b5dSValentin Clement           }
501044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
502044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
503044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
504044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
505044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
506044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
507044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
508044d5b5dSValentin Clement         }
509044d5b5dSValentin Clement       }
510044d5b5dSValentin Clement     }
511044d5b5dSValentin Clement     rewriter.eraseOp(global);
512044d5b5dSValentin Clement     return success();
513044d5b5dSValentin Clement   }
514044d5b5dSValentin Clement 
515044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
516044d5b5dSValentin Clement     auto extents = seqTy.getShape();
517044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
518044d5b5dSValentin Clement       return false;
519044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
520044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
521044d5b5dSValentin Clement         return false;
522044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
523044d5b5dSValentin Clement         return false;
524044d5b5dSValentin Clement     }
525044d5b5dSValentin Clement     return true;
526044d5b5dSValentin Clement   }
527044d5b5dSValentin Clement 
5280c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
5290c4a7a52SValentin Clement   // enumeration.
530044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
531044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
532044d5b5dSValentin Clement       auto name = optLinkage.getValue();
533044d5b5dSValentin Clement       if (name == "internal")
534044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
535044d5b5dSValentin Clement       if (name == "linkonce")
536044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
537044d5b5dSValentin Clement       if (name == "common")
538044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
539044d5b5dSValentin Clement       if (name == "weak")
540044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
541044d5b5dSValentin Clement     }
542044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
543044d5b5dSValentin Clement   }
544044d5b5dSValentin Clement };
545044d5b5dSValentin Clement 
5468c239909SValentin Clement template <typename OP>
5478c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
5488c239909SValentin Clement                            typename OP::Adaptor adaptor,
5498c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
5508c239909SValentin Clement   unsigned conds = select.getNumConditions();
5518c239909SValentin Clement   auto cases = select.getCases().getValue();
5528c239909SValentin Clement   mlir::Value selector = adaptor.selector();
5538c239909SValentin Clement   auto loc = select.getLoc();
5548c239909SValentin Clement   assert(conds > 0 && "select must have cases");
5558c239909SValentin Clement 
5568c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
5578c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
5588c239909SValentin Clement   mlir::Block *defaultDestination;
5598c239909SValentin Clement   mlir::ValueRange defaultOperands;
5608c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
5618c239909SValentin Clement 
5628c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
5638c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
5648c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
5658c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
5668c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
5678c239909SValentin Clement       destinations.push_back(dest);
5688c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
5698c239909SValentin Clement                                                         : ValueRange());
5708c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
5718c239909SValentin Clement       continue;
5728c239909SValentin Clement     }
5738c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
5748c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
5758c239909SValentin Clement     defaultDestination = dest;
5768c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
5778c239909SValentin Clement   }
5788c239909SValentin Clement 
5798c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
5808c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
5818c239909SValentin Clement     selector =
5828c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
5838c239909SValentin Clement 
5848c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
5858c239909SValentin Clement       select, selector,
5868c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
5878c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
5888c239909SValentin Clement       /*caseValues=*/caseValues,
5898c239909SValentin Clement       /*caseDestinations=*/destinations,
5908c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
5918c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
5928c239909SValentin Clement }
5938c239909SValentin Clement 
5948c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
5958c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
5968c239909SValentin Clement   using FIROpConversion::FIROpConversion;
5978c239909SValentin Clement 
5988c239909SValentin Clement   mlir::LogicalResult
5998c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
6008c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6018c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
6028c239909SValentin Clement     return success();
6038c239909SValentin Clement   }
6048c239909SValentin Clement };
6058c239909SValentin Clement 
606e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
607e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
608e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
609e3349fa1SAndrzej Warzynski 
610e3349fa1SAndrzej Warzynski   mlir::LogicalResult
611e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
612e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
613e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
614e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
615e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
616e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
617e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
618e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
619e3349fa1SAndrzej Warzynski     } else {
620e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
621e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
622e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
623e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
624e3349fa1SAndrzej Warzynski     }
625e3349fa1SAndrzej Warzynski     return success();
626e3349fa1SAndrzej Warzynski   }
627e3349fa1SAndrzej Warzynski };
628e3349fa1SAndrzej Warzynski 
6298c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
6308c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
6318c239909SValentin Clement   using FIROpConversion::FIROpConversion;
6328c239909SValentin Clement 
6338c239909SValentin Clement   mlir::LogicalResult
6348c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
6358c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6368c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
6378c239909SValentin Clement     return success();
6388c239909SValentin Clement   }
6398c239909SValentin Clement };
6408c239909SValentin Clement 
641e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
642e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
643e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
644e3349fa1SAndrzej Warzynski 
645e3349fa1SAndrzej Warzynski   mlir::LogicalResult
646e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
647e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
648e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
649e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
650e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
651e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
652e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
653e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
654e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
655e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
656e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
657e3349fa1SAndrzej Warzynski     } else {
658e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
659e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
660e3349fa1SAndrzej Warzynski     }
661e3349fa1SAndrzej Warzynski     return success();
662e3349fa1SAndrzej Warzynski   }
663e3349fa1SAndrzej Warzynski };
664e3349fa1SAndrzej Warzynski 
665e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
666044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
667044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
668044d5b5dSValentin Clement 
669044d5b5dSValentin Clement   mlir::LogicalResult
670044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
671044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
672044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
673044d5b5dSValentin Clement         undef, convertType(undef.getType()));
674044d5b5dSValentin Clement     return success();
675044d5b5dSValentin Clement   }
676044d5b5dSValentin Clement };
677a7a61359SValentin Clement 
678e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
67932e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
68032e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
68132e08248SAndrzej Warzynski 
68232e08248SAndrzej Warzynski   mlir::LogicalResult
68332e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
68432e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
68532e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
68632e08248SAndrzej Warzynski     return success();
68732e08248SAndrzej Warzynski   }
68832e08248SAndrzej Warzynski };
68932e08248SAndrzej Warzynski 
690a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
691a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
692a7a61359SValentin Clement 
693a7a61359SValentin Clement   mlir::LogicalResult
694a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
695a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
696a7a61359SValentin Clement     auto ty = convertType(zero.getType());
697a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
698a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
699a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
700a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
701a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
702a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
703a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
704a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
705a7a61359SValentin Clement     } else {
706a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
70752d813edSValentin Clement       return rewriter.notifyMatchFailure(
70852d813edSValentin Clement           zero,
709a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
710a7a61359SValentin Clement     }
711a7a61359SValentin Clement     return success();
712a7a61359SValentin Clement   }
713a7a61359SValentin Clement };
71432e08248SAndrzej Warzynski 
71554c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
71654c56347SValentin Clement struct ValueOpCommon {
71754c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
71854c56347SValentin Clement   // row-major order for LLVM-IR.
71954c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
72054c56347SValentin Clement                          mlir::Type ty) {
72154c56347SValentin Clement     assert(ty && "type is null");
72254c56347SValentin Clement     const auto end = attrs.size();
72354c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
72454c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
72554c56347SValentin Clement         const auto dim = getDimension(seq);
72654c56347SValentin Clement         if (dim > 1) {
72754c56347SValentin Clement           auto ub = std::min(i + dim, end);
72854c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
72954c56347SValentin Clement           i += dim - 1;
73054c56347SValentin Clement         }
73154c56347SValentin Clement         ty = getArrayElementType(seq);
73254c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
73354c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
73454c56347SValentin Clement       } else {
73554c56347SValentin Clement         llvm_unreachable("index into invalid type");
73654c56347SValentin Clement       }
73754c56347SValentin Clement     }
73854c56347SValentin Clement   }
73954c56347SValentin Clement 
74054c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
74154c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
74254c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
74354c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
74454c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
74554c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
74654c56347SValentin Clement         attrs.push_back(*i);
74754c56347SValentin Clement       } else {
74854c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
74954c56347SValentin Clement         ++i;
75054c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
75154c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
75254c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
75354c56347SValentin Clement       }
75454c56347SValentin Clement     }
75554c56347SValentin Clement     return attrs;
75654c56347SValentin Clement   }
75754c56347SValentin Clement 
75854c56347SValentin Clement private:
75954c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
76054c56347SValentin Clement     unsigned result = 1;
76154c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
76254c56347SValentin Clement          eleTy;
76354c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
76454c56347SValentin Clement       ++result;
76554c56347SValentin Clement     return result;
76654c56347SValentin Clement   }
76754c56347SValentin Clement 
76854c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
76954c56347SValentin Clement     auto eleTy = ty.getElementType();
77054c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
77154c56347SValentin Clement       eleTy = arrTy.getElementType();
77254c56347SValentin Clement     return eleTy;
77354c56347SValentin Clement   }
77454c56347SValentin Clement };
77554c56347SValentin Clement 
77654c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
77754c56347SValentin Clement struct ExtractValueOpConversion
77854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
77954c56347SValentin Clement       public ValueOpCommon {
78054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
78154c56347SValentin Clement 
78254c56347SValentin Clement   mlir::LogicalResult
78354c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
78454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
78554c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
78654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
78754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
78854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
78954c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
79054c56347SValentin Clement     return success();
79154c56347SValentin Clement   }
79254c56347SValentin Clement };
79354c56347SValentin Clement 
79454c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
79554c56347SValentin Clement /// aggregate type values.
79654c56347SValentin Clement struct InsertValueOpConversion
79754c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
79854c56347SValentin Clement       public ValueOpCommon {
79954c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
80054c56347SValentin Clement 
80154c56347SValentin Clement   mlir::LogicalResult
80254c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
80354c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
80454c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
80554c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
80654c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
80754c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
80854c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
80954c56347SValentin Clement         position);
81054c56347SValentin Clement     return success();
81154c56347SValentin Clement   }
81254c56347SValentin Clement };
81354c56347SValentin Clement 
8143ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
8153ae8e442SValentin Clement struct InsertOnRangeOpConversion
8163ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
8173ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
8183ae8e442SValentin Clement 
8193ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
8203ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
8213ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
8223ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
8233ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
8243ae8e442SValentin Clement         return;
8253ae8e442SValentin Clement       }
8263ae8e442SValentin Clement       subscripts[i - 1] = 0;
8273ae8e442SValentin Clement     }
8283ae8e442SValentin Clement   }
8293ae8e442SValentin Clement 
8303ae8e442SValentin Clement   mlir::LogicalResult
8313ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
8323ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
8333ae8e442SValentin Clement 
8343ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
8353ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
8363ae8e442SValentin Clement 
8373ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
8383ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
8393ae8e442SValentin Clement       dims.push_back(t.getNumElements());
8403ae8e442SValentin Clement       type = t.getElementType();
8413ae8e442SValentin Clement     }
8423ae8e442SValentin Clement 
8433ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
8443ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
8453ae8e442SValentin Clement 
8463ae8e442SValentin Clement     // Extract integer value from the attribute
8473ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
8483ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
8493ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
8503ae8e442SValentin Clement         }));
8513ae8e442SValentin Clement 
8523ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
8533ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
8543ae8e442SValentin Clement       uBounds.push_back(*i++);
8553ae8e442SValentin Clement       lBounds.push_back(*i);
8563ae8e442SValentin Clement     }
8573ae8e442SValentin Clement 
8583ae8e442SValentin Clement     auto &subscripts = lBounds;
8593ae8e442SValentin Clement     auto loc = range.getLoc();
8603ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
8613ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
8623ae8e442SValentin Clement 
8633ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
8643ae8e442SValentin Clement     while (subscripts != uBounds) {
8653ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
8663ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
8673ae8e442SValentin Clement       for (const auto &subscript : subscripts)
8683ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
8693ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
8703ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
8713ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
8723ae8e442SValentin Clement 
8733ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
8743ae8e442SValentin Clement     }
8753ae8e442SValentin Clement 
8763ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
8773ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
8783ae8e442SValentin Clement     for (const auto &subscript : subscripts)
8793ae8e442SValentin Clement       subscriptAttrs.push_back(
8803ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
8813ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
8823ae8e442SValentin Clement 
8833ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
8843ae8e442SValentin Clement         range, ty, lastOp, insertVal,
8853ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
8863ae8e442SValentin Clement 
8873ae8e442SValentin Clement     return success();
8883ae8e442SValentin Clement   }
8893ae8e442SValentin Clement };
8907b5132daSValentin Clement 
8917b5132daSValentin Clement //
8927b5132daSValentin Clement // Primitive operations on Complex types
8937b5132daSValentin Clement //
8947b5132daSValentin Clement 
8957b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
8967b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
8977b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
8987b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
8997b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
9007b5132daSValentin Clement   mlir::Value a = opnds[0];
9017b5132daSValentin Clement   mlir::Value b = opnds[1];
9027b5132daSValentin Clement   auto loc = sumop.getLoc();
9037b5132daSValentin Clement   auto ctx = sumop.getContext();
9047b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
9057b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
9067b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
9077b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
9087b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
9097b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
9107b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
9117b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
9127b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
9137b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
9147b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
9157b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
9167b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
9177b5132daSValentin Clement }
9187b5132daSValentin Clement 
9197b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
9207b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
9217b5132daSValentin Clement 
9227b5132daSValentin Clement   mlir::LogicalResult
9237b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
9247b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9257b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
9267b5132daSValentin Clement     // result: (x + x') + i(y + y')
9277b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
9287b5132daSValentin Clement                                             rewriter, lowerTy());
9297b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
9307b5132daSValentin Clement     return success();
9317b5132daSValentin Clement   }
9327b5132daSValentin Clement };
9337b5132daSValentin Clement 
9347b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
9357b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
9367b5132daSValentin Clement 
9377b5132daSValentin Clement   mlir::LogicalResult
9387b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
9397b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9407b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
9417b5132daSValentin Clement     // result: (x - x') + i(y - y')
9427b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
9437b5132daSValentin Clement                                             rewriter, lowerTy());
9447b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
9457b5132daSValentin Clement     return success();
9467b5132daSValentin Clement   }
9477b5132daSValentin Clement };
9487b5132daSValentin Clement 
9497b5132daSValentin Clement /// Inlined complex multiply
9507b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
9517b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
9527b5132daSValentin Clement 
9537b5132daSValentin Clement   mlir::LogicalResult
9547b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
9557b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9567b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
9577b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
9587b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
9597b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
9607b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
9617b5132daSValentin Clement     auto loc = mulc.getLoc();
9627b5132daSValentin Clement     auto *ctx = mulc.getContext();
9637b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
9647b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
9657b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
9667b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
9677b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
9687b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
9697b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
9707b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
9717b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
9727b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
9737b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
9747b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
9757b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
9767b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
9777b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
9787b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
9797b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
9807b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
9817b5132daSValentin Clement     return success();
9827b5132daSValentin Clement   }
9837b5132daSValentin Clement };
9847b5132daSValentin Clement 
9857b5132daSValentin Clement /// Inlined complex division
9867b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
9877b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
9887b5132daSValentin Clement 
9897b5132daSValentin Clement   mlir::LogicalResult
9907b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
9917b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9927b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
9937b5132daSValentin Clement     // Just generate inline code for now.
9947b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
9957b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
9967b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
9977b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
9987b5132daSValentin Clement     auto loc = divc.getLoc();
9997b5132daSValentin Clement     auto *ctx = divc.getContext();
10007b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
10017b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
10027b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
10037b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
10047b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
10057b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
10067b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
10077b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
10087b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
10097b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
10107b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
10117b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
10127b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
10137b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
10147b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
10157b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
10167b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
10177b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
10187b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
10197b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
10207b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
10217b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
10227b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
10237b5132daSValentin Clement     return success();
10247b5132daSValentin Clement   }
10257b5132daSValentin Clement };
10267b5132daSValentin Clement 
10277b5132daSValentin Clement /// Inlined complex negation
10287b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
10297b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
10307b5132daSValentin Clement 
10317b5132daSValentin Clement   mlir::LogicalResult
10327b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
10337b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
10347b5132daSValentin Clement     // given: -(x + iy)
10357b5132daSValentin Clement     // result: -x - iy
10367b5132daSValentin Clement     auto *ctxt = neg.getContext();
10377b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
10387b5132daSValentin Clement     auto ty = convertType(neg.getType());
10397b5132daSValentin Clement     auto loc = neg.getLoc();
10407b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
10417b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
10427b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
10437b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
10447b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
10457b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
10467b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
10477b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
10487b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
10497b5132daSValentin Clement     return success();
10507b5132daSValentin Clement   }
10517b5132daSValentin Clement };
10527b5132daSValentin Clement 
1053044d5b5dSValentin Clement } // namespace
1054044d5b5dSValentin Clement 
1055044d5b5dSValentin Clement namespace {
1056044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1057044d5b5dSValentin Clement ///
1058044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1059044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1060044d5b5dSValentin Clement ///
1061044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1062044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1063044d5b5dSValentin Clement public:
1064044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1065044d5b5dSValentin Clement 
1066044d5b5dSValentin Clement   void runOnOperation() override final {
10677b5132daSValentin Clement     auto mod = getModule();
10687b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
10697b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
10707b5132daSValentin Clement     }
10717b5132daSValentin Clement 
1072044d5b5dSValentin Clement     auto *context = getModule().getContext();
1073044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1074044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1075df3b9810SValentin Clement     pattern.insert<
1076df3b9810SValentin Clement         AddcOpConversion, AddrOfOpConversion, BoxAddrOpConversion,
1077*b6e44ecdSValentin Clement         BoxDimsOpConversion, BoxEleSizeOpConversion, BoxIsAllocOpConversion,
1078*b6e44ecdSValentin Clement         BoxIsArrayOpConversion, BoxIsPtrOpConversion, BoxRankOpConversion,
1079df3b9810SValentin Clement         CallOpConversion, ConvertOpConversion, DivcOpConversion,
1080df3b9810SValentin Clement         ExtractValueOpConversion, HasValueOpConversion, GlobalOpConversion,
1081df3b9810SValentin Clement         InsertOnRangeOpConversion, InsertValueOpConversion, LoadOpConversion,
1082df3b9810SValentin Clement         NegcOpConversion, MulcOpConversion, SelectOpConversion,
1083df3b9810SValentin Clement         SelectRankOpConversion, StoreOpConversion, SubcOpConversion,
1084df3b9810SValentin Clement         UndefOpConversion, UnreachableOpConversion, ZeroOpConversion>(
1085df3b9810SValentin Clement         typeConverter);
1086044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1087044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1088044d5b5dSValentin Clement                                                             pattern);
1089044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1090044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1091044d5b5dSValentin Clement 
1092044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1093044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1094044d5b5dSValentin Clement 
1095044d5b5dSValentin Clement     // apply the patterns
1096044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1097044d5b5dSValentin Clement                                                std::move(pattern)))) {
1098044d5b5dSValentin Clement       signalPassFailure();
1099044d5b5dSValentin Clement     }
1100044d5b5dSValentin Clement   }
1101044d5b5dSValentin Clement };
1102044d5b5dSValentin Clement } // namespace
1103044d5b5dSValentin Clement 
1104044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1105044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1106044d5b5dSValentin Clement }
1107