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"
15044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
16044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIRType.h"
17*7b5132daSValentin Clement #include "flang/Optimizer/Support/FIRContext.h"
18044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/TypeConverter.h"
21044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
22044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
233ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
24044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
25044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
26044d5b5dSValentin Clement 
27044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
28044d5b5dSValentin Clement 
29044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
30044d5b5dSValentin Clement #include "TypeConverter.h"
31044d5b5dSValentin Clement 
32044d5b5dSValentin Clement namespace {
33044d5b5dSValentin Clement /// FIR conversion pattern template
34044d5b5dSValentin Clement template <typename FromOp>
35044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
36044d5b5dSValentin Clement public:
37044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
38044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
39044d5b5dSValentin Clement 
40044d5b5dSValentin Clement protected:
41044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
42044d5b5dSValentin Clement     return lowerTy().convertType(ty);
43044d5b5dSValentin Clement   }
44044d5b5dSValentin Clement 
45044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
46044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
47044d5b5dSValentin Clement   }
48044d5b5dSValentin Clement };
49044d5b5dSValentin Clement 
503ae8e442SValentin Clement /// FIR conversion pattern template
513ae8e442SValentin Clement template <typename FromOp>
523ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
533ae8e442SValentin Clement public:
543ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
553ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
563ae8e442SValentin Clement 
573ae8e442SValentin Clement   mlir::LogicalResult
583ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
593ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
603ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
613ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
623ae8e442SValentin Clement   }
633ae8e442SValentin Clement 
643ae8e442SValentin Clement   virtual mlir::LogicalResult
653ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
663ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
673ae8e442SValentin Clement };
683ae8e442SValentin Clement 
690c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
70044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
71044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
72044d5b5dSValentin Clement 
73044d5b5dSValentin Clement   mlir::LogicalResult
74044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
75044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
76044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
77044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
78044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
79044d5b5dSValentin Clement     return success();
80044d5b5dSValentin Clement   }
81044d5b5dSValentin Clement };
82044d5b5dSValentin Clement 
83ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
84ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
85ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
86ddd11b9aSAndrzej Warzynski 
87ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
88ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
89ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
90ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
91ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
92ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
93ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
94ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
95ddd11b9aSAndrzej Warzynski     return success();
96ddd11b9aSAndrzej Warzynski   }
97ddd11b9aSAndrzej Warzynski };
98ddd11b9aSAndrzej Warzynski 
990c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
100044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
101044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
102044d5b5dSValentin Clement 
103044d5b5dSValentin Clement   mlir::LogicalResult
104044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
105044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
106044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
107044d5b5dSValentin Clement     return success();
108044d5b5dSValentin Clement   }
109044d5b5dSValentin Clement };
110044d5b5dSValentin Clement 
1110c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
1120c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
1130c4a7a52SValentin Clement /// if they are applied on the full range.
114044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
115044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
116044d5b5dSValentin Clement 
117044d5b5dSValentin Clement   mlir::LogicalResult
118044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
119044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
120044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
121044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
122044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
123044d5b5dSValentin Clement     auto loc = global.getLoc();
124044d5b5dSValentin Clement     mlir::Attribute initAttr{};
125044d5b5dSValentin Clement     if (global.initVal())
126044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
127044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
128044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
129044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
130044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
131044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
132044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
133044d5b5dSValentin Clement     if (!gr.empty()) {
134044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
135044d5b5dSValentin Clement       // initialization is on the full range.
136044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
137044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
138044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
139044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
140044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
141044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
142044d5b5dSValentin Clement           if (!constant) {
143044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
144044d5b5dSValentin Clement             if (!convertOp)
145044d5b5dSValentin Clement               continue;
146044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
147044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
148044d5b5dSValentin Clement           }
149044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
150044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
151044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
152044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
153044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
154044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
155044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
156044d5b5dSValentin Clement         }
157044d5b5dSValentin Clement       }
158044d5b5dSValentin Clement     }
159044d5b5dSValentin Clement     rewriter.eraseOp(global);
160044d5b5dSValentin Clement     return success();
161044d5b5dSValentin Clement   }
162044d5b5dSValentin Clement 
163044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
164044d5b5dSValentin Clement     auto extents = seqTy.getShape();
165044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
166044d5b5dSValentin Clement       return false;
167044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
168044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
169044d5b5dSValentin Clement         return false;
170044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
171044d5b5dSValentin Clement         return false;
172044d5b5dSValentin Clement     }
173044d5b5dSValentin Clement     return true;
174044d5b5dSValentin Clement   }
175044d5b5dSValentin Clement 
1760c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
1770c4a7a52SValentin Clement   // enumeration.
178044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
179044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
180044d5b5dSValentin Clement       auto name = optLinkage.getValue();
181044d5b5dSValentin Clement       if (name == "internal")
182044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
183044d5b5dSValentin Clement       if (name == "linkonce")
184044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
185044d5b5dSValentin Clement       if (name == "common")
186044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
187044d5b5dSValentin Clement       if (name == "weak")
188044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
189044d5b5dSValentin Clement     }
190044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
191044d5b5dSValentin Clement   }
192044d5b5dSValentin Clement };
193044d5b5dSValentin Clement 
1948c239909SValentin Clement template <typename OP>
1958c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
1968c239909SValentin Clement                            typename OP::Adaptor adaptor,
1978c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
1988c239909SValentin Clement   unsigned conds = select.getNumConditions();
1998c239909SValentin Clement   auto cases = select.getCases().getValue();
2008c239909SValentin Clement   mlir::Value selector = adaptor.selector();
2018c239909SValentin Clement   auto loc = select.getLoc();
2028c239909SValentin Clement   assert(conds > 0 && "select must have cases");
2038c239909SValentin Clement 
2048c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
2058c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
2068c239909SValentin Clement   mlir::Block *defaultDestination;
2078c239909SValentin Clement   mlir::ValueRange defaultOperands;
2088c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
2098c239909SValentin Clement 
2108c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
2118c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
2128c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
2138c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
2148c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
2158c239909SValentin Clement       destinations.push_back(dest);
2168c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
2178c239909SValentin Clement                                                         : ValueRange());
2188c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
2198c239909SValentin Clement       continue;
2208c239909SValentin Clement     }
2218c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
2228c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
2238c239909SValentin Clement     defaultDestination = dest;
2248c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
2258c239909SValentin Clement   }
2268c239909SValentin Clement 
2278c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
2288c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
2298c239909SValentin Clement     selector =
2308c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
2318c239909SValentin Clement 
2328c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
2338c239909SValentin Clement       select, selector,
2348c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
2358c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
2368c239909SValentin Clement       /*caseValues=*/caseValues,
2378c239909SValentin Clement       /*caseDestinations=*/destinations,
2388c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
2398c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
2408c239909SValentin Clement }
2418c239909SValentin Clement 
2428c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
2438c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
2448c239909SValentin Clement   using FIROpConversion::FIROpConversion;
2458c239909SValentin Clement 
2468c239909SValentin Clement   mlir::LogicalResult
2478c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
2488c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
2498c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
2508c239909SValentin Clement     return success();
2518c239909SValentin Clement   }
2528c239909SValentin Clement };
2538c239909SValentin Clement 
2548c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
2558c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
2568c239909SValentin Clement   using FIROpConversion::FIROpConversion;
2578c239909SValentin Clement 
2588c239909SValentin Clement   mlir::LogicalResult
2598c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
2608c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
2618c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
2628c239909SValentin Clement     return success();
2638c239909SValentin Clement   }
2648c239909SValentin Clement };
2658c239909SValentin Clement 
266044d5b5dSValentin Clement // convert to LLVM IR dialect `undef`
267044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
268044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
269044d5b5dSValentin Clement 
270044d5b5dSValentin Clement   mlir::LogicalResult
271044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
272044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
273044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
274044d5b5dSValentin Clement         undef, convertType(undef.getType()));
275044d5b5dSValentin Clement     return success();
276044d5b5dSValentin Clement   }
277044d5b5dSValentin Clement };
278a7a61359SValentin Clement 
27932e08248SAndrzej Warzynski // convert to LLVM IR dialect `unreachable`
28032e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
28132e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
28232e08248SAndrzej Warzynski 
28332e08248SAndrzej Warzynski   mlir::LogicalResult
28432e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
28532e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
28632e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
28732e08248SAndrzej Warzynski     return success();
28832e08248SAndrzej Warzynski   }
28932e08248SAndrzej Warzynski };
29032e08248SAndrzej Warzynski 
291a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
292a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
293a7a61359SValentin Clement 
294a7a61359SValentin Clement   mlir::LogicalResult
295a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
296a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
297a7a61359SValentin Clement     auto ty = convertType(zero.getType());
298a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
299a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
300a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
301a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
302a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
303a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
304a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
305a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
306a7a61359SValentin Clement     } else {
307a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
30852d813edSValentin Clement       return rewriter.notifyMatchFailure(
30952d813edSValentin Clement           zero,
310a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
311a7a61359SValentin Clement     }
312a7a61359SValentin Clement     return success();
313a7a61359SValentin Clement   }
314a7a61359SValentin Clement };
31532e08248SAndrzej Warzynski 
31654c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
31754c56347SValentin Clement struct ValueOpCommon {
31854c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
31954c56347SValentin Clement   // row-major order for LLVM-IR.
32054c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
32154c56347SValentin Clement                          mlir::Type ty) {
32254c56347SValentin Clement     assert(ty && "type is null");
32354c56347SValentin Clement     const auto end = attrs.size();
32454c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
32554c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
32654c56347SValentin Clement         const auto dim = getDimension(seq);
32754c56347SValentin Clement         if (dim > 1) {
32854c56347SValentin Clement           auto ub = std::min(i + dim, end);
32954c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
33054c56347SValentin Clement           i += dim - 1;
33154c56347SValentin Clement         }
33254c56347SValentin Clement         ty = getArrayElementType(seq);
33354c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
33454c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
33554c56347SValentin Clement       } else {
33654c56347SValentin Clement         llvm_unreachable("index into invalid type");
33754c56347SValentin Clement       }
33854c56347SValentin Clement     }
33954c56347SValentin Clement   }
34054c56347SValentin Clement 
34154c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
34254c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
34354c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
34454c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
34554c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
34654c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
34754c56347SValentin Clement         attrs.push_back(*i);
34854c56347SValentin Clement       } else {
34954c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
35054c56347SValentin Clement         ++i;
35154c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
35254c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
35354c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
35454c56347SValentin Clement       }
35554c56347SValentin Clement     }
35654c56347SValentin Clement     return attrs;
35754c56347SValentin Clement   }
35854c56347SValentin Clement 
35954c56347SValentin Clement private:
36054c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
36154c56347SValentin Clement     unsigned result = 1;
36254c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
36354c56347SValentin Clement          eleTy;
36454c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
36554c56347SValentin Clement       ++result;
36654c56347SValentin Clement     return result;
36754c56347SValentin Clement   }
36854c56347SValentin Clement 
36954c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
37054c56347SValentin Clement     auto eleTy = ty.getElementType();
37154c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
37254c56347SValentin Clement       eleTy = arrTy.getElementType();
37354c56347SValentin Clement     return eleTy;
37454c56347SValentin Clement   }
37554c56347SValentin Clement };
37654c56347SValentin Clement 
37754c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
37854c56347SValentin Clement struct ExtractValueOpConversion
37954c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
38054c56347SValentin Clement       public ValueOpCommon {
38154c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
38254c56347SValentin Clement 
38354c56347SValentin Clement   mlir::LogicalResult
38454c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
38554c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
38654c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
38754c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
38854c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
38954c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
39054c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
39154c56347SValentin Clement     return success();
39254c56347SValentin Clement   }
39354c56347SValentin Clement };
39454c56347SValentin Clement 
39554c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
39654c56347SValentin Clement /// aggregate type values.
39754c56347SValentin Clement struct InsertValueOpConversion
39854c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
39954c56347SValentin Clement       public ValueOpCommon {
40054c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
40154c56347SValentin Clement 
40254c56347SValentin Clement   mlir::LogicalResult
40354c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
40454c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
40554c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
40654c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
40754c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
40854c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
40954c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
41054c56347SValentin Clement         position);
41154c56347SValentin Clement     return success();
41254c56347SValentin Clement   }
41354c56347SValentin Clement };
41454c56347SValentin Clement 
4153ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
4163ae8e442SValentin Clement struct InsertOnRangeOpConversion
4173ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
4183ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
4193ae8e442SValentin Clement 
4203ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
4213ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
4223ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
4233ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
4243ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
4253ae8e442SValentin Clement         return;
4263ae8e442SValentin Clement       }
4273ae8e442SValentin Clement       subscripts[i - 1] = 0;
4283ae8e442SValentin Clement     }
4293ae8e442SValentin Clement   }
4303ae8e442SValentin Clement 
4313ae8e442SValentin Clement   mlir::LogicalResult
4323ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
4333ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
4343ae8e442SValentin Clement 
4353ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
4363ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
4373ae8e442SValentin Clement 
4383ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
4393ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
4403ae8e442SValentin Clement       dims.push_back(t.getNumElements());
4413ae8e442SValentin Clement       type = t.getElementType();
4423ae8e442SValentin Clement     }
4433ae8e442SValentin Clement 
4443ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
4453ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
4463ae8e442SValentin Clement 
4473ae8e442SValentin Clement     // Extract integer value from the attribute
4483ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
4493ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
4503ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
4513ae8e442SValentin Clement         }));
4523ae8e442SValentin Clement 
4533ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
4543ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
4553ae8e442SValentin Clement       uBounds.push_back(*i++);
4563ae8e442SValentin Clement       lBounds.push_back(*i);
4573ae8e442SValentin Clement     }
4583ae8e442SValentin Clement 
4593ae8e442SValentin Clement     auto &subscripts = lBounds;
4603ae8e442SValentin Clement     auto loc = range.getLoc();
4613ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
4623ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
4633ae8e442SValentin Clement 
4643ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
4653ae8e442SValentin Clement     while (subscripts != uBounds) {
4663ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
4673ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
4683ae8e442SValentin Clement       for (const auto &subscript : subscripts)
4693ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
4703ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
4713ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
4723ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
4733ae8e442SValentin Clement 
4743ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
4753ae8e442SValentin Clement     }
4763ae8e442SValentin Clement 
4773ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
4783ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
4793ae8e442SValentin Clement     for (const auto &subscript : subscripts)
4803ae8e442SValentin Clement       subscriptAttrs.push_back(
4813ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
4823ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
4833ae8e442SValentin Clement 
4843ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
4853ae8e442SValentin Clement         range, ty, lastOp, insertVal,
4863ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
4873ae8e442SValentin Clement 
4883ae8e442SValentin Clement     return success();
4893ae8e442SValentin Clement   }
4903ae8e442SValentin Clement };
491*7b5132daSValentin Clement 
492*7b5132daSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
493*7b5132daSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
494*7b5132daSValentin Clement     return cc.getElementType();
495*7b5132daSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
496*7b5132daSValentin Clement }
497*7b5132daSValentin Clement 
498*7b5132daSValentin Clement //
499*7b5132daSValentin Clement // Primitive operations on Complex types
500*7b5132daSValentin Clement //
501*7b5132daSValentin Clement 
502*7b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
503*7b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
504*7b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
505*7b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
506*7b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
507*7b5132daSValentin Clement   mlir::Value a = opnds[0];
508*7b5132daSValentin Clement   mlir::Value b = opnds[1];
509*7b5132daSValentin Clement   auto loc = sumop.getLoc();
510*7b5132daSValentin Clement   auto ctx = sumop.getContext();
511*7b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
512*7b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
513*7b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
514*7b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
515*7b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
516*7b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
517*7b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
518*7b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
519*7b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
520*7b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
521*7b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
522*7b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
523*7b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
524*7b5132daSValentin Clement }
525*7b5132daSValentin Clement 
526*7b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
527*7b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
528*7b5132daSValentin Clement 
529*7b5132daSValentin Clement   mlir::LogicalResult
530*7b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
531*7b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
532*7b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
533*7b5132daSValentin Clement     // result: (x + x') + i(y + y')
534*7b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
535*7b5132daSValentin Clement                                             rewriter, lowerTy());
536*7b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
537*7b5132daSValentin Clement     return success();
538*7b5132daSValentin Clement   }
539*7b5132daSValentin Clement };
540*7b5132daSValentin Clement 
541*7b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
542*7b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
543*7b5132daSValentin Clement 
544*7b5132daSValentin Clement   mlir::LogicalResult
545*7b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
546*7b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
547*7b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
548*7b5132daSValentin Clement     // result: (x - x') + i(y - y')
549*7b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
550*7b5132daSValentin Clement                                             rewriter, lowerTy());
551*7b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
552*7b5132daSValentin Clement     return success();
553*7b5132daSValentin Clement   }
554*7b5132daSValentin Clement };
555*7b5132daSValentin Clement 
556*7b5132daSValentin Clement /// Inlined complex multiply
557*7b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
558*7b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
559*7b5132daSValentin Clement 
560*7b5132daSValentin Clement   mlir::LogicalResult
561*7b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
562*7b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
563*7b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
564*7b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
565*7b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
566*7b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
567*7b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
568*7b5132daSValentin Clement     auto loc = mulc.getLoc();
569*7b5132daSValentin Clement     auto *ctx = mulc.getContext();
570*7b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
571*7b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
572*7b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
573*7b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
574*7b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
575*7b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
576*7b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
577*7b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
578*7b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
579*7b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
580*7b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
581*7b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
582*7b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
583*7b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
584*7b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
585*7b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
586*7b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
587*7b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
588*7b5132daSValentin Clement     return success();
589*7b5132daSValentin Clement   }
590*7b5132daSValentin Clement };
591*7b5132daSValentin Clement 
592*7b5132daSValentin Clement /// Inlined complex division
593*7b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
594*7b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
595*7b5132daSValentin Clement 
596*7b5132daSValentin Clement   mlir::LogicalResult
597*7b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
598*7b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
599*7b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
600*7b5132daSValentin Clement     // Just generate inline code for now.
601*7b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
602*7b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
603*7b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
604*7b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
605*7b5132daSValentin Clement     auto loc = divc.getLoc();
606*7b5132daSValentin Clement     auto *ctx = divc.getContext();
607*7b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
608*7b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
609*7b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
610*7b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
611*7b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
612*7b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
613*7b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
614*7b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
615*7b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
616*7b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
617*7b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
618*7b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
619*7b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
620*7b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
621*7b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
622*7b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
623*7b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
624*7b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
625*7b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
626*7b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
627*7b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
628*7b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
629*7b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
630*7b5132daSValentin Clement     return success();
631*7b5132daSValentin Clement   }
632*7b5132daSValentin Clement };
633*7b5132daSValentin Clement 
634*7b5132daSValentin Clement /// Inlined complex negation
635*7b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
636*7b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
637*7b5132daSValentin Clement 
638*7b5132daSValentin Clement   mlir::LogicalResult
639*7b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
640*7b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
641*7b5132daSValentin Clement     // given: -(x + iy)
642*7b5132daSValentin Clement     // result: -x - iy
643*7b5132daSValentin Clement     auto *ctxt = neg.getContext();
644*7b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
645*7b5132daSValentin Clement     auto ty = convertType(neg.getType());
646*7b5132daSValentin Clement     auto loc = neg.getLoc();
647*7b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
648*7b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
649*7b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
650*7b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
651*7b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
652*7b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
653*7b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
654*7b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
655*7b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
656*7b5132daSValentin Clement     return success();
657*7b5132daSValentin Clement   }
658*7b5132daSValentin Clement };
659*7b5132daSValentin Clement 
660044d5b5dSValentin Clement } // namespace
661044d5b5dSValentin Clement 
662044d5b5dSValentin Clement namespace {
663044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
664044d5b5dSValentin Clement ///
665044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
666044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
667044d5b5dSValentin Clement ///
668044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
669044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
670044d5b5dSValentin Clement public:
671044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
672044d5b5dSValentin Clement 
673044d5b5dSValentin Clement   void runOnOperation() override final {
674*7b5132daSValentin Clement     auto mod = getModule();
675*7b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
676*7b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
677*7b5132daSValentin Clement     }
678*7b5132daSValentin Clement 
679044d5b5dSValentin Clement     auto *context = getModule().getContext();
680044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
681044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
682*7b5132daSValentin Clement     pattern.insert<AddcOpConversion, AddrOfOpConversion, CallOpConversion,
683*7b5132daSValentin Clement                    DivcOpConversion, ExtractValueOpConversion,
684*7b5132daSValentin Clement                    HasValueOpConversion, GlobalOpConversion,
685*7b5132daSValentin Clement                    InsertOnRangeOpConversion, InsertValueOpConversion,
686*7b5132daSValentin Clement                    NegcOpConversion, MulcOpConversion, SelectOpConversion,
687*7b5132daSValentin Clement                    SelectRankOpConversion, SubcOpConversion, UndefOpConversion,
688*7b5132daSValentin Clement                    UnreachableOpConversion, ZeroOpConversion>(typeConverter);
689044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
690044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
691044d5b5dSValentin Clement                                                             pattern);
692044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
693044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
694044d5b5dSValentin Clement 
695044d5b5dSValentin Clement     // required NOPs for applying a full conversion
696044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
697044d5b5dSValentin Clement 
698044d5b5dSValentin Clement     // apply the patterns
699044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
700044d5b5dSValentin Clement                                                std::move(pattern)))) {
701044d5b5dSValentin Clement       signalPassFailure();
702044d5b5dSValentin Clement     }
703044d5b5dSValentin Clement   }
704044d5b5dSValentin Clement };
705044d5b5dSValentin Clement } // namespace
706044d5b5dSValentin Clement 
707044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
708044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
709044d5b5dSValentin Clement }
710