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"
15b6e44ecdSValentin Clement #include "flang/ISO_Fortran_binding.h"
16*39f4ef81SValentin Clement #include "flang/Optimizer/Dialect/FIRAttr.h"
17044d5b5dSValentin Clement #include "flang/Optimizer/Dialect/FIROps.h"
18044d5b5dSValentin Clement #include "mlir/Conversion/ArithmeticToLLVM/ArithmeticToLLVM.h"
19044d5b5dSValentin Clement #include "mlir/Conversion/LLVMCommon/Pattern.h"
20044d5b5dSValentin Clement #include "mlir/Conversion/StandardToLLVM/ConvertStandardToLLVM.h"
21044d5b5dSValentin Clement #include "mlir/IR/BuiltinTypes.h"
223ae8e442SValentin Clement #include "mlir/IR/Matchers.h"
23044d5b5dSValentin Clement #include "mlir/Pass/Pass.h"
24044d5b5dSValentin Clement #include "llvm/ADT/ArrayRef.h"
25044d5b5dSValentin Clement 
26044d5b5dSValentin Clement #define DEBUG_TYPE "flang-codegen"
27044d5b5dSValentin Clement 
28044d5b5dSValentin Clement // fir::LLVMTypeConverter for converting to LLVM IR dialect types.
29044d5b5dSValentin Clement #include "TypeConverter.h"
30044d5b5dSValentin Clement 
31b6e44ecdSValentin Clement /// `fir.box` attribute values as defined for CFI_attribute_t in
32b6e44ecdSValentin Clement /// flang/ISO_Fortran_binding.h.
33b6e44ecdSValentin Clement static constexpr unsigned kAttrPointer = CFI_attribute_pointer;
34b6e44ecdSValentin Clement static constexpr unsigned kAttrAllocatable = CFI_attribute_allocatable;
35b6e44ecdSValentin Clement 
361e6d9c06SDiana Picus static mlir::LLVM::ConstantOp
371e6d9c06SDiana Picus genConstantIndex(mlir::Location loc, mlir::Type ity,
381e6d9c06SDiana Picus                  mlir::ConversionPatternRewriter &rewriter,
391e6d9c06SDiana Picus                  std::int64_t offset) {
401e6d9c06SDiana Picus   auto cattr = rewriter.getI64IntegerAttr(offset);
411e6d9c06SDiana Picus   return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
421e6d9c06SDiana Picus }
431e6d9c06SDiana Picus 
44*39f4ef81SValentin Clement static Block *createBlock(mlir::ConversionPatternRewriter &rewriter,
45*39f4ef81SValentin Clement                           mlir::Block *insertBefore) {
46*39f4ef81SValentin Clement   assert(insertBefore && "expected valid insertion block");
47*39f4ef81SValentin Clement   return rewriter.createBlock(insertBefore->getParent(),
48*39f4ef81SValentin Clement                               mlir::Region::iterator(insertBefore));
49*39f4ef81SValentin Clement }
50*39f4ef81SValentin Clement 
51044d5b5dSValentin Clement namespace {
52044d5b5dSValentin Clement /// FIR conversion pattern template
53044d5b5dSValentin Clement template <typename FromOp>
54044d5b5dSValentin Clement class FIROpConversion : public mlir::ConvertOpToLLVMPattern<FromOp> {
55044d5b5dSValentin Clement public:
56044d5b5dSValentin Clement   explicit FIROpConversion(fir::LLVMTypeConverter &lowering)
57044d5b5dSValentin Clement       : mlir::ConvertOpToLLVMPattern<FromOp>(lowering) {}
58044d5b5dSValentin Clement 
59044d5b5dSValentin Clement protected:
60044d5b5dSValentin Clement   mlir::Type convertType(mlir::Type ty) const {
61044d5b5dSValentin Clement     return lowerTy().convertType(ty);
62044d5b5dSValentin Clement   }
63044d5b5dSValentin Clement 
64df3b9810SValentin Clement   mlir::LLVM::ConstantOp
65df3b9810SValentin Clement   genConstantOffset(mlir::Location loc,
66df3b9810SValentin Clement                     mlir::ConversionPatternRewriter &rewriter,
67df3b9810SValentin Clement                     int offset) const {
68df3b9810SValentin Clement     auto ity = lowerTy().offsetType();
69df3b9810SValentin Clement     auto cattr = rewriter.getI32IntegerAttr(offset);
70df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::ConstantOp>(loc, ity, cattr);
71df3b9810SValentin Clement   }
72df3b9810SValentin Clement 
73b6e44ecdSValentin Clement   /// Construct code sequence to extract the specifc value from a `fir.box`.
74b6e44ecdSValentin Clement   mlir::Value getValueFromBox(mlir::Location loc, mlir::Value box,
75df3b9810SValentin Clement                               mlir::Type resultTy,
76b6e44ecdSValentin Clement                               mlir::ConversionPatternRewriter &rewriter,
77b6e44ecdSValentin Clement                               unsigned boxValue) const {
78df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
79b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp cValuePos =
80b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, boxValue);
81df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(resultTy);
82df3b9810SValentin Clement     auto p = rewriter.create<mlir::LLVM::GEPOp>(
83b6e44ecdSValentin Clement         loc, pty, mlir::ValueRange{box, c0, cValuePos});
84df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, resultTy, p);
85df3b9810SValentin Clement   }
86df3b9810SValentin Clement 
87df3b9810SValentin Clement   /// Method to construct code sequence to get the triple for dimension `dim`
88df3b9810SValentin Clement   /// from a box.
89df3b9810SValentin Clement   SmallVector<mlir::Value, 3>
90df3b9810SValentin Clement   getDimsFromBox(mlir::Location loc, ArrayRef<mlir::Type> retTys,
91df3b9810SValentin Clement                  mlir::Value box, mlir::Value dim,
92df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
93df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
94df3b9810SValentin Clement     mlir::LLVM::ConstantOp cDims =
95df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kDimsPosInBox);
96df3b9810SValentin Clement     mlir::LLVM::LoadOp l0 =
97df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 0, retTys[0], rewriter);
98df3b9810SValentin Clement     mlir::LLVM::LoadOp l1 =
99df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 1, retTys[1], rewriter);
100df3b9810SValentin Clement     mlir::LLVM::LoadOp l2 =
101df3b9810SValentin Clement         loadFromOffset(loc, box, c0, cDims, dim, 2, retTys[2], rewriter);
102df3b9810SValentin Clement     return {l0.getResult(), l1.getResult(), l2.getResult()};
103df3b9810SValentin Clement   }
104df3b9810SValentin Clement 
105df3b9810SValentin Clement   mlir::LLVM::LoadOp
106df3b9810SValentin Clement   loadFromOffset(mlir::Location loc, mlir::Value a, mlir::LLVM::ConstantOp c0,
107df3b9810SValentin Clement                  mlir::LLVM::ConstantOp cDims, mlir::Value dim, int off,
108df3b9810SValentin Clement                  mlir::Type ty,
109df3b9810SValentin Clement                  mlir::ConversionPatternRewriter &rewriter) const {
110df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
111df3b9810SValentin Clement     mlir::LLVM::ConstantOp c = genConstantOffset(loc, rewriter, off);
112df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, a, c0, cDims, dim, c);
113df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
114df3b9810SValentin Clement   }
115df3b9810SValentin Clement 
116df3b9810SValentin Clement   /// Read base address from a fir.box. Returned address has type ty.
117df3b9810SValentin Clement   mlir::Value
118df3b9810SValentin Clement   loadBaseAddrFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
119df3b9810SValentin Clement                       mlir::ConversionPatternRewriter &rewriter) const {
120df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
121df3b9810SValentin Clement     mlir::LLVM::ConstantOp cAddr =
122df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kAddrPosInBox);
123df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
124df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cAddr);
125df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
126df3b9810SValentin Clement   }
127df3b9810SValentin Clement 
128df3b9810SValentin Clement   mlir::Value
129df3b9810SValentin Clement   loadElementSizeFromBox(mlir::Location loc, mlir::Type ty, mlir::Value box,
130df3b9810SValentin Clement                          mlir::ConversionPatternRewriter &rewriter) const {
131df3b9810SValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
132df3b9810SValentin Clement     mlir::LLVM::ConstantOp cElemLen =
133df3b9810SValentin Clement         genConstantOffset(loc, rewriter, kElemLenPosInBox);
134df3b9810SValentin Clement     auto pty = mlir::LLVM::LLVMPointerType::get(ty);
135df3b9810SValentin Clement     mlir::LLVM::GEPOp p = genGEP(loc, pty, rewriter, box, c0, cElemLen);
136df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::LoadOp>(loc, ty, p);
137df3b9810SValentin Clement   }
138df3b9810SValentin Clement 
139b6e44ecdSValentin Clement   // Load the attribute from the \p box and perform a check against \p maskValue
140b6e44ecdSValentin Clement   // The final comparison is implemented as `(attribute & maskValue) != 0`.
141b6e44ecdSValentin Clement   mlir::Value genBoxAttributeCheck(mlir::Location loc, mlir::Value box,
142b6e44ecdSValentin Clement                                    mlir::ConversionPatternRewriter &rewriter,
143b6e44ecdSValentin Clement                                    unsigned maskValue) const {
144b6e44ecdSValentin Clement     mlir::Type attrTy = rewriter.getI32Type();
145b6e44ecdSValentin Clement     mlir::Value attribute =
146b6e44ecdSValentin Clement         getValueFromBox(loc, box, attrTy, rewriter, kAttributePosInBox);
147b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp attrMask =
148b6e44ecdSValentin Clement         genConstantOffset(loc, rewriter, maskValue);
149b6e44ecdSValentin Clement     auto maskRes =
150b6e44ecdSValentin Clement         rewriter.create<mlir::LLVM::AndOp>(loc, attrTy, attribute, attrMask);
151b6e44ecdSValentin Clement     mlir::LLVM::ConstantOp c0 = genConstantOffset(loc, rewriter, 0);
152b6e44ecdSValentin Clement     return rewriter.create<mlir::LLVM::ICmpOp>(
153b6e44ecdSValentin Clement         loc, mlir::LLVM::ICmpPredicate::ne, maskRes, c0);
154b6e44ecdSValentin Clement   }
155b6e44ecdSValentin Clement 
156df3b9810SValentin Clement   template <typename... ARGS>
157df3b9810SValentin Clement   mlir::LLVM::GEPOp genGEP(mlir::Location loc, mlir::Type ty,
158df3b9810SValentin Clement                            mlir::ConversionPatternRewriter &rewriter,
159df3b9810SValentin Clement                            mlir::Value base, ARGS... args) const {
160df3b9810SValentin Clement     SmallVector<mlir::Value> cv{args...};
161df3b9810SValentin Clement     return rewriter.create<mlir::LLVM::GEPOp>(loc, ty, base, cv);
162df3b9810SValentin Clement   }
163df3b9810SValentin Clement 
1641e6d9c06SDiana Picus   /// Perform an extension or truncation as needed on an integer value. Lowering
1651e6d9c06SDiana Picus   /// to the specific target may involve some sign-extending or truncation of
1661e6d9c06SDiana Picus   /// values, particularly to fit them from abstract box types to the
1671e6d9c06SDiana Picus   /// appropriate reified structures.
1681e6d9c06SDiana Picus   mlir::Value integerCast(mlir::Location loc,
1691e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter,
1701e6d9c06SDiana Picus                           mlir::Type ty, mlir::Value val) const {
1711e6d9c06SDiana Picus     auto valTy = val.getType();
1721e6d9c06SDiana Picus     // If the value was not yet lowered, lower its type so that it can
1731e6d9c06SDiana Picus     // be used in getPrimitiveTypeSizeInBits.
1741e6d9c06SDiana Picus     if (!valTy.isa<mlir::IntegerType>())
1751e6d9c06SDiana Picus       valTy = convertType(valTy);
1761e6d9c06SDiana Picus     auto toSize = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
1771e6d9c06SDiana Picus     auto fromSize = mlir::LLVM::getPrimitiveTypeSizeInBits(valTy);
1781e6d9c06SDiana Picus     if (toSize < fromSize)
1791e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::TruncOp>(loc, ty, val);
1801e6d9c06SDiana Picus     if (toSize > fromSize)
1811e6d9c06SDiana Picus       return rewriter.create<mlir::LLVM::SExtOp>(loc, ty, val);
1821e6d9c06SDiana Picus     return val;
1831e6d9c06SDiana Picus   }
1841e6d9c06SDiana Picus 
185044d5b5dSValentin Clement   fir::LLVMTypeConverter &lowerTy() const {
186044d5b5dSValentin Clement     return *static_cast<fir::LLVMTypeConverter *>(this->getTypeConverter());
187044d5b5dSValentin Clement   }
188044d5b5dSValentin Clement };
189044d5b5dSValentin Clement 
1903ae8e442SValentin Clement /// FIR conversion pattern template
1913ae8e442SValentin Clement template <typename FromOp>
1923ae8e442SValentin Clement class FIROpAndTypeConversion : public FIROpConversion<FromOp> {
1933ae8e442SValentin Clement public:
1943ae8e442SValentin Clement   using FIROpConversion<FromOp>::FIROpConversion;
1953ae8e442SValentin Clement   using OpAdaptor = typename FromOp::Adaptor;
1963ae8e442SValentin Clement 
1973ae8e442SValentin Clement   mlir::LogicalResult
1983ae8e442SValentin Clement   matchAndRewrite(FromOp op, OpAdaptor adaptor,
1993ae8e442SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const final {
2003ae8e442SValentin Clement     mlir::Type ty = this->convertType(op.getType());
2013ae8e442SValentin Clement     return doRewrite(op, ty, adaptor, rewriter);
2023ae8e442SValentin Clement   }
2033ae8e442SValentin Clement 
2043ae8e442SValentin Clement   virtual mlir::LogicalResult
2053ae8e442SValentin Clement   doRewrite(FromOp addr, mlir::Type ty, OpAdaptor adaptor,
2063ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const = 0;
2073ae8e442SValentin Clement };
2083ae8e442SValentin Clement 
2090c4a7a52SValentin Clement // Lower `fir.address_of` operation to `llvm.address_of` operation.
210044d5b5dSValentin Clement struct AddrOfOpConversion : public FIROpConversion<fir::AddrOfOp> {
211044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
212044d5b5dSValentin Clement 
213044d5b5dSValentin Clement   mlir::LogicalResult
214044d5b5dSValentin Clement   matchAndRewrite(fir::AddrOfOp addr, OpAdaptor adaptor,
215044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
216044d5b5dSValentin Clement     auto ty = convertType(addr.getType());
217044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
218044d5b5dSValentin Clement         addr, ty, addr.symbol().getRootReference().getValue());
219044d5b5dSValentin Clement     return success();
220044d5b5dSValentin Clement   }
221044d5b5dSValentin Clement };
2221e6d9c06SDiana Picus } // namespace
2231e6d9c06SDiana Picus 
2241e6d9c06SDiana Picus /// Lookup the function to compute the memory size of this parametric derived
2251e6d9c06SDiana Picus /// type. The size of the object may depend on the LEN type parameters of the
2261e6d9c06SDiana Picus /// derived type.
2271e6d9c06SDiana Picus static mlir::LLVM::LLVMFuncOp
2281e6d9c06SDiana Picus getDependentTypeMemSizeFn(fir::RecordType recTy, fir::AllocaOp op,
2291e6d9c06SDiana Picus                           mlir::ConversionPatternRewriter &rewriter) {
2301e6d9c06SDiana Picus   auto module = op->getParentOfType<mlir::ModuleOp>();
2311e6d9c06SDiana Picus   std::string name = recTy.getName().str() + "P.mem.size";
2321e6d9c06SDiana Picus   return module.lookupSymbol<mlir::LLVM::LLVMFuncOp>(name);
2331e6d9c06SDiana Picus }
2341e6d9c06SDiana Picus 
2351e6d9c06SDiana Picus namespace {
2361e6d9c06SDiana Picus /// convert to LLVM IR dialect `alloca`
2371e6d9c06SDiana Picus struct AllocaOpConversion : public FIROpConversion<fir::AllocaOp> {
2381e6d9c06SDiana Picus   using FIROpConversion::FIROpConversion;
2391e6d9c06SDiana Picus 
2401e6d9c06SDiana Picus   mlir::LogicalResult
2411e6d9c06SDiana Picus   matchAndRewrite(fir::AllocaOp alloc, OpAdaptor adaptor,
2421e6d9c06SDiana Picus                   mlir::ConversionPatternRewriter &rewriter) const override {
2431e6d9c06SDiana Picus     mlir::ValueRange operands = adaptor.getOperands();
2441e6d9c06SDiana Picus     auto loc = alloc.getLoc();
2451e6d9c06SDiana Picus     mlir::Type ity = lowerTy().indexType();
2461e6d9c06SDiana Picus     unsigned i = 0;
2471e6d9c06SDiana Picus     mlir::Value size = genConstantIndex(loc, ity, rewriter, 1).getResult();
2481e6d9c06SDiana Picus     mlir::Type ty = convertType(alloc.getType());
2491e6d9c06SDiana Picus     mlir::Type resultTy = ty;
2501e6d9c06SDiana Picus     if (alloc.hasLenParams()) {
2511e6d9c06SDiana Picus       unsigned end = alloc.numLenParams();
2521e6d9c06SDiana Picus       llvm::SmallVector<mlir::Value> lenParams;
2531e6d9c06SDiana Picus       for (; i < end; ++i)
2541e6d9c06SDiana Picus         lenParams.push_back(operands[i]);
2551e6d9c06SDiana Picus       mlir::Type scalarType = fir::unwrapSequenceType(alloc.getInType());
2561e6d9c06SDiana Picus       if (auto chrTy = scalarType.dyn_cast<fir::CharacterType>()) {
2571e6d9c06SDiana Picus         fir::CharacterType rawCharTy = fir::CharacterType::getUnknownLen(
2581e6d9c06SDiana Picus             chrTy.getContext(), chrTy.getFKind());
2591e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(convertType(rawCharTy));
2601e6d9c06SDiana Picus         assert(end == 1);
2611e6d9c06SDiana Picus         size = integerCast(loc, rewriter, ity, lenParams[0]);
2621e6d9c06SDiana Picus       } else if (auto recTy = scalarType.dyn_cast<fir::RecordType>()) {
2631e6d9c06SDiana Picus         mlir::LLVM::LLVMFuncOp memSizeFn =
2641e6d9c06SDiana Picus             getDependentTypeMemSizeFn(recTy, alloc, rewriter);
2651e6d9c06SDiana Picus         if (!memSizeFn)
2661e6d9c06SDiana Picus           emitError(loc, "did not find allocation function");
2671e6d9c06SDiana Picus         mlir::NamedAttribute attr = rewriter.getNamedAttr(
2681e6d9c06SDiana Picus             "callee", mlir::SymbolRefAttr::get(memSizeFn));
2691e6d9c06SDiana Picus         auto call = rewriter.create<mlir::LLVM::CallOp>(
2701e6d9c06SDiana Picus             loc, ity, lenParams, llvm::ArrayRef<mlir::NamedAttribute>{attr});
2711e6d9c06SDiana Picus         size = call.getResult(0);
2721e6d9c06SDiana Picus         ty = mlir::LLVM::LLVMPointerType::get(
2731e6d9c06SDiana Picus             mlir::IntegerType::get(alloc.getContext(), 8));
2741e6d9c06SDiana Picus       } else {
2751e6d9c06SDiana Picus         return emitError(loc, "unexpected type ")
2761e6d9c06SDiana Picus                << scalarType << " with type parameters";
2771e6d9c06SDiana Picus       }
2781e6d9c06SDiana Picus     }
2791e6d9c06SDiana Picus     if (alloc.hasShapeOperands()) {
2801e6d9c06SDiana Picus       mlir::Type allocEleTy = fir::unwrapRefType(alloc.getType());
2811e6d9c06SDiana Picus       // Scale the size by constant factors encoded in the array type.
2821e6d9c06SDiana Picus       if (auto seqTy = allocEleTy.dyn_cast<fir::SequenceType>()) {
2831e6d9c06SDiana Picus         fir::SequenceType::Extent constSize = 1;
2841e6d9c06SDiana Picus         for (auto extent : seqTy.getShape())
2851e6d9c06SDiana Picus           if (extent != fir::SequenceType::getUnknownExtent())
2861e6d9c06SDiana Picus             constSize *= extent;
2871e6d9c06SDiana Picus         mlir::Value constVal{
2881e6d9c06SDiana Picus             genConstantIndex(loc, ity, rewriter, constSize).getResult()};
2891e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(loc, ity, size, constVal);
2901e6d9c06SDiana Picus       }
2911e6d9c06SDiana Picus       unsigned end = operands.size();
2921e6d9c06SDiana Picus       for (; i < end; ++i)
2931e6d9c06SDiana Picus         size = rewriter.create<mlir::LLVM::MulOp>(
2941e6d9c06SDiana Picus             loc, ity, size, integerCast(loc, rewriter, ity, operands[i]));
2951e6d9c06SDiana Picus     }
2961e6d9c06SDiana Picus     if (ty == resultTy) {
2971e6d9c06SDiana Picus       // Do not emit the bitcast if ty and resultTy are the same.
2981e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::AllocaOp>(alloc, ty, size,
2991e6d9c06SDiana Picus                                                         alloc->getAttrs());
3001e6d9c06SDiana Picus     } else {
3011e6d9c06SDiana Picus       auto al = rewriter.create<mlir::LLVM::AllocaOp>(loc, ty, size,
3021e6d9c06SDiana Picus                                                       alloc->getAttrs());
3031e6d9c06SDiana Picus       rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(alloc, resultTy, al);
3041e6d9c06SDiana Picus     }
3051e6d9c06SDiana Picus     return success();
3061e6d9c06SDiana Picus   }
3071e6d9c06SDiana Picus };
308044d5b5dSValentin Clement 
309df3b9810SValentin Clement /// Lower `fir.box_addr` to the sequence of operations to extract the first
310df3b9810SValentin Clement /// element of the box.
311df3b9810SValentin Clement struct BoxAddrOpConversion : public FIROpConversion<fir::BoxAddrOp> {
312df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
313df3b9810SValentin Clement 
314df3b9810SValentin Clement   mlir::LogicalResult
315df3b9810SValentin Clement   matchAndRewrite(fir::BoxAddrOp boxaddr, OpAdaptor adaptor,
316df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
317df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
318df3b9810SValentin Clement     auto loc = boxaddr.getLoc();
319df3b9810SValentin Clement     mlir::Type ty = convertType(boxaddr.getType());
320df3b9810SValentin Clement     if (auto argty = boxaddr.val().getType().dyn_cast<fir::BoxType>()) {
321df3b9810SValentin Clement       rewriter.replaceOp(boxaddr, loadBaseAddrFromBox(loc, ty, a, rewriter));
322df3b9810SValentin Clement     } else {
323df3b9810SValentin Clement       auto c0attr = rewriter.getI32IntegerAttr(0);
324df3b9810SValentin Clement       auto c0 = mlir::ArrayAttr::get(boxaddr.getContext(), c0attr);
325df3b9810SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(boxaddr, ty, a,
326df3b9810SValentin Clement                                                               c0);
327df3b9810SValentin Clement     }
328df3b9810SValentin Clement     return success();
329df3b9810SValentin Clement   }
330df3b9810SValentin Clement };
331df3b9810SValentin Clement 
332df3b9810SValentin Clement /// Lower `fir.box_dims` to a sequence of operations to extract the requested
333df3b9810SValentin Clement /// dimension infomartion from the boxed value.
334df3b9810SValentin Clement /// Result in a triple set of GEPs and loads.
335df3b9810SValentin Clement struct BoxDimsOpConversion : public FIROpConversion<fir::BoxDimsOp> {
336df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
337df3b9810SValentin Clement 
338df3b9810SValentin Clement   mlir::LogicalResult
339df3b9810SValentin Clement   matchAndRewrite(fir::BoxDimsOp boxdims, OpAdaptor adaptor,
340df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
341df3b9810SValentin Clement     SmallVector<mlir::Type, 3> resultTypes = {
342df3b9810SValentin Clement         convertType(boxdims.getResult(0).getType()),
343df3b9810SValentin Clement         convertType(boxdims.getResult(1).getType()),
344df3b9810SValentin Clement         convertType(boxdims.getResult(2).getType()),
345df3b9810SValentin Clement     };
346df3b9810SValentin Clement     auto results =
347df3b9810SValentin Clement         getDimsFromBox(boxdims.getLoc(), resultTypes, adaptor.getOperands()[0],
348df3b9810SValentin Clement                        adaptor.getOperands()[1], rewriter);
349df3b9810SValentin Clement     rewriter.replaceOp(boxdims, results);
350df3b9810SValentin Clement     return success();
351df3b9810SValentin Clement   }
352df3b9810SValentin Clement };
353df3b9810SValentin Clement 
354df3b9810SValentin Clement /// Lower `fir.box_elesize` to a sequence of operations ro extract the size of
355df3b9810SValentin Clement /// an element in the boxed value.
356df3b9810SValentin Clement struct BoxEleSizeOpConversion : public FIROpConversion<fir::BoxEleSizeOp> {
357df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
358df3b9810SValentin Clement 
359df3b9810SValentin Clement   mlir::LogicalResult
360df3b9810SValentin Clement   matchAndRewrite(fir::BoxEleSizeOp boxelesz, OpAdaptor adaptor,
361df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
362df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
363df3b9810SValentin Clement     auto loc = boxelesz.getLoc();
364df3b9810SValentin Clement     auto ty = convertType(boxelesz.getType());
365b6e44ecdSValentin Clement     auto elemSize = getValueFromBox(loc, a, ty, rewriter, kElemLenPosInBox);
366b6e44ecdSValentin Clement     rewriter.replaceOp(boxelesz, elemSize);
367b6e44ecdSValentin Clement     return success();
368b6e44ecdSValentin Clement   }
369b6e44ecdSValentin Clement };
370b6e44ecdSValentin Clement 
371b6e44ecdSValentin Clement /// Lower `fir.box_isalloc` to a sequence of operations to determine if the
372b6e44ecdSValentin Clement /// boxed value was from an ALLOCATABLE entity.
373b6e44ecdSValentin Clement struct BoxIsAllocOpConversion : public FIROpConversion<fir::BoxIsAllocOp> {
374b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
375b6e44ecdSValentin Clement 
376b6e44ecdSValentin Clement   mlir::LogicalResult
377b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsAllocOp boxisalloc, OpAdaptor adaptor,
378b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
379b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
380b6e44ecdSValentin Clement     auto loc = boxisalloc.getLoc();
381b6e44ecdSValentin Clement     mlir::Value check =
382b6e44ecdSValentin Clement         genBoxAttributeCheck(loc, box, rewriter, kAttrAllocatable);
383b6e44ecdSValentin Clement     rewriter.replaceOp(boxisalloc, check);
384b6e44ecdSValentin Clement     return success();
385b6e44ecdSValentin Clement   }
386b6e44ecdSValentin Clement };
387b6e44ecdSValentin Clement 
388b6e44ecdSValentin Clement /// Lower `fir.box_isarray` to a sequence of operations to determine if the
389b6e44ecdSValentin Clement /// boxed is an array.
390b6e44ecdSValentin Clement struct BoxIsArrayOpConversion : public FIROpConversion<fir::BoxIsArrayOp> {
391b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
392b6e44ecdSValentin Clement 
393b6e44ecdSValentin Clement   mlir::LogicalResult
394b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsArrayOp boxisarray, OpAdaptor adaptor,
395b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
396b6e44ecdSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
397b6e44ecdSValentin Clement     auto loc = boxisarray.getLoc();
398b6e44ecdSValentin Clement     auto rank =
399b6e44ecdSValentin Clement         getValueFromBox(loc, a, rewriter.getI32Type(), rewriter, kRankPosInBox);
400b6e44ecdSValentin Clement     auto c0 = genConstantOffset(loc, rewriter, 0);
401b6e44ecdSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ICmpOp>(
402b6e44ecdSValentin Clement         boxisarray, mlir::LLVM::ICmpPredicate::ne, rank, c0);
403b6e44ecdSValentin Clement     return success();
404b6e44ecdSValentin Clement   }
405b6e44ecdSValentin Clement };
406b6e44ecdSValentin Clement 
407b6e44ecdSValentin Clement /// Lower `fir.box_isptr` to a sequence of operations to determined if the
408b6e44ecdSValentin Clement /// boxed value was from a POINTER entity.
409b6e44ecdSValentin Clement struct BoxIsPtrOpConversion : public FIROpConversion<fir::BoxIsPtrOp> {
410b6e44ecdSValentin Clement   using FIROpConversion::FIROpConversion;
411b6e44ecdSValentin Clement 
412b6e44ecdSValentin Clement   mlir::LogicalResult
413b6e44ecdSValentin Clement   matchAndRewrite(fir::BoxIsPtrOp boxisptr, OpAdaptor adaptor,
414b6e44ecdSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
415b6e44ecdSValentin Clement     mlir::Value box = adaptor.getOperands()[0];
416b6e44ecdSValentin Clement     auto loc = boxisptr.getLoc();
417b6e44ecdSValentin Clement     mlir::Value check = genBoxAttributeCheck(loc, box, rewriter, kAttrPointer);
418b6e44ecdSValentin Clement     rewriter.replaceOp(boxisptr, check);
419df3b9810SValentin Clement     return success();
420df3b9810SValentin Clement   }
421df3b9810SValentin Clement };
422df3b9810SValentin Clement 
423df3b9810SValentin Clement /// Lower `fir.box_rank` to the sequence of operation to extract the rank from
424df3b9810SValentin Clement /// the box.
425df3b9810SValentin Clement struct BoxRankOpConversion : public FIROpConversion<fir::BoxRankOp> {
426df3b9810SValentin Clement   using FIROpConversion::FIROpConversion;
427df3b9810SValentin Clement 
428df3b9810SValentin Clement   mlir::LogicalResult
429df3b9810SValentin Clement   matchAndRewrite(fir::BoxRankOp boxrank, OpAdaptor adaptor,
430df3b9810SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
431df3b9810SValentin Clement     mlir::Value a = adaptor.getOperands()[0];
432df3b9810SValentin Clement     auto loc = boxrank.getLoc();
433df3b9810SValentin Clement     mlir::Type ty = convertType(boxrank.getType());
434b6e44ecdSValentin Clement     auto result = getValueFromBox(loc, a, ty, rewriter, kRankPosInBox);
435df3b9810SValentin Clement     rewriter.replaceOp(boxrank, result);
436df3b9810SValentin Clement     return success();
437df3b9810SValentin Clement   }
438df3b9810SValentin Clement };
439df3b9810SValentin Clement 
440ddd11b9aSAndrzej Warzynski // `fir.call` -> `llvm.call`
441ddd11b9aSAndrzej Warzynski struct CallOpConversion : public FIROpConversion<fir::CallOp> {
442ddd11b9aSAndrzej Warzynski   using FIROpConversion::FIROpConversion;
443ddd11b9aSAndrzej Warzynski 
444ddd11b9aSAndrzej Warzynski   mlir::LogicalResult
445ddd11b9aSAndrzej Warzynski   matchAndRewrite(fir::CallOp call, OpAdaptor adaptor,
446ddd11b9aSAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
447ddd11b9aSAndrzej Warzynski     SmallVector<mlir::Type> resultTys;
448ddd11b9aSAndrzej Warzynski     for (auto r : call.getResults())
449ddd11b9aSAndrzej Warzynski       resultTys.push_back(convertType(r.getType()));
450ddd11b9aSAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::CallOp>(
451ddd11b9aSAndrzej Warzynski         call, resultTys, adaptor.getOperands(), call->getAttrs());
452ddd11b9aSAndrzej Warzynski     return success();
453ddd11b9aSAndrzej Warzynski   }
454ddd11b9aSAndrzej Warzynski };
455ddd11b9aSAndrzej Warzynski 
456092cee5fSValentin Clement static mlir::Type getComplexEleTy(mlir::Type complex) {
457092cee5fSValentin Clement   if (auto cc = complex.dyn_cast<mlir::ComplexType>())
458092cee5fSValentin Clement     return cc.getElementType();
459092cee5fSValentin Clement   return complex.cast<fir::ComplexType>().getElementType();
460092cee5fSValentin Clement }
461092cee5fSValentin Clement 
462092cee5fSValentin Clement /// convert value of from-type to value of to-type
463092cee5fSValentin Clement struct ConvertOpConversion : public FIROpConversion<fir::ConvertOp> {
464092cee5fSValentin Clement   using FIROpConversion::FIROpConversion;
465092cee5fSValentin Clement 
466092cee5fSValentin Clement   static bool isFloatingPointTy(mlir::Type ty) {
467092cee5fSValentin Clement     return ty.isa<mlir::FloatType>();
468092cee5fSValentin Clement   }
469092cee5fSValentin Clement 
470092cee5fSValentin Clement   mlir::LogicalResult
471092cee5fSValentin Clement   matchAndRewrite(fir::ConvertOp convert, OpAdaptor adaptor,
472092cee5fSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
473092cee5fSValentin Clement     auto fromTy = convertType(convert.value().getType());
474092cee5fSValentin Clement     auto toTy = convertType(convert.res().getType());
475092cee5fSValentin Clement     mlir::Value op0 = adaptor.getOperands()[0];
476092cee5fSValentin Clement     if (fromTy == toTy) {
477092cee5fSValentin Clement       rewriter.replaceOp(convert, op0);
478092cee5fSValentin Clement       return success();
479092cee5fSValentin Clement     }
480092cee5fSValentin Clement     auto loc = convert.getLoc();
481092cee5fSValentin Clement     auto convertFpToFp = [&](mlir::Value val, unsigned fromBits,
482092cee5fSValentin Clement                              unsigned toBits, mlir::Type toTy) -> mlir::Value {
483092cee5fSValentin Clement       if (fromBits == toBits) {
484092cee5fSValentin Clement         // TODO: Converting between two floating-point representations with the
485092cee5fSValentin Clement         // same bitwidth is not allowed for now.
486092cee5fSValentin Clement         mlir::emitError(loc,
487092cee5fSValentin Clement                         "cannot implicitly convert between two floating-point "
488092cee5fSValentin Clement                         "representations of the same bitwidth");
489092cee5fSValentin Clement         return {};
490092cee5fSValentin Clement       }
491092cee5fSValentin Clement       if (fromBits > toBits)
492092cee5fSValentin Clement         return rewriter.create<mlir::LLVM::FPTruncOp>(loc, toTy, val);
493092cee5fSValentin Clement       return rewriter.create<mlir::LLVM::FPExtOp>(loc, toTy, val);
494092cee5fSValentin Clement     };
495092cee5fSValentin Clement     // Complex to complex conversion.
496092cee5fSValentin Clement     if (fir::isa_complex(convert.value().getType()) &&
497092cee5fSValentin Clement         fir::isa_complex(convert.res().getType())) {
498092cee5fSValentin Clement       // Special case: handle the conversion of a complex such that both the
499092cee5fSValentin Clement       // real and imaginary parts are converted together.
500092cee5fSValentin Clement       auto zero = mlir::ArrayAttr::get(convert.getContext(),
501092cee5fSValentin Clement                                        rewriter.getI32IntegerAttr(0));
502092cee5fSValentin Clement       auto one = mlir::ArrayAttr::get(convert.getContext(),
503092cee5fSValentin Clement                                       rewriter.getI32IntegerAttr(1));
504092cee5fSValentin Clement       auto ty = convertType(getComplexEleTy(convert.value().getType()));
505092cee5fSValentin Clement       auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, zero);
506092cee5fSValentin Clement       auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, ty, op0, one);
507092cee5fSValentin Clement       auto nt = convertType(getComplexEleTy(convert.res().getType()));
508092cee5fSValentin Clement       auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(ty);
509092cee5fSValentin Clement       auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(nt);
510092cee5fSValentin Clement       auto rc = convertFpToFp(rp, fromBits, toBits, nt);
511092cee5fSValentin Clement       auto ic = convertFpToFp(ip, fromBits, toBits, nt);
512092cee5fSValentin Clement       auto un = rewriter.create<mlir::LLVM::UndefOp>(loc, toTy);
513092cee5fSValentin Clement       auto i1 =
514092cee5fSValentin Clement           rewriter.create<mlir::LLVM::InsertValueOp>(loc, toTy, un, rc, zero);
515092cee5fSValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(convert, toTy, i1,
516092cee5fSValentin Clement                                                              ic, one);
517092cee5fSValentin Clement       return mlir::success();
518092cee5fSValentin Clement     }
519092cee5fSValentin Clement     // Floating point to floating point conversion.
520092cee5fSValentin Clement     if (isFloatingPointTy(fromTy)) {
521092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
522092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
523092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
524092cee5fSValentin Clement         auto v = convertFpToFp(op0, fromBits, toBits, toTy);
525092cee5fSValentin Clement         rewriter.replaceOp(convert, v);
526092cee5fSValentin Clement         return mlir::success();
527092cee5fSValentin Clement       }
528092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
529092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::FPToSIOp>(convert, toTy, op0);
530092cee5fSValentin Clement         return mlir::success();
531092cee5fSValentin Clement       }
532092cee5fSValentin Clement     } else if (fromTy.isa<mlir::IntegerType>()) {
533092cee5fSValentin Clement       // Integer to integer conversion.
534092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
535092cee5fSValentin Clement         auto fromBits = mlir::LLVM::getPrimitiveTypeSizeInBits(fromTy);
536092cee5fSValentin Clement         auto toBits = mlir::LLVM::getPrimitiveTypeSizeInBits(toTy);
537092cee5fSValentin Clement         assert(fromBits != toBits);
538092cee5fSValentin Clement         if (fromBits > toBits) {
539092cee5fSValentin Clement           rewriter.replaceOpWithNewOp<mlir::LLVM::TruncOp>(convert, toTy, op0);
540092cee5fSValentin Clement           return mlir::success();
541092cee5fSValentin Clement         }
542092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SExtOp>(convert, toTy, op0);
543092cee5fSValentin Clement         return mlir::success();
544092cee5fSValentin Clement       }
545092cee5fSValentin Clement       // Integer to floating point conversion.
546092cee5fSValentin Clement       if (isFloatingPointTy(toTy)) {
547092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::SIToFPOp>(convert, toTy, op0);
548092cee5fSValentin Clement         return mlir::success();
549092cee5fSValentin Clement       }
550092cee5fSValentin Clement       // Integer to pointer conversion.
551092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
552092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::IntToPtrOp>(convert, toTy, op0);
553092cee5fSValentin Clement         return mlir::success();
554092cee5fSValentin Clement       }
555092cee5fSValentin Clement     } else if (fromTy.isa<mlir::LLVM::LLVMPointerType>()) {
556092cee5fSValentin Clement       // Pointer to integer conversion.
557092cee5fSValentin Clement       if (toTy.isa<mlir::IntegerType>()) {
558092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::PtrToIntOp>(convert, toTy, op0);
559092cee5fSValentin Clement         return mlir::success();
560092cee5fSValentin Clement       }
561092cee5fSValentin Clement       // Pointer to pointer conversion.
562092cee5fSValentin Clement       if (toTy.isa<mlir::LLVM::LLVMPointerType>()) {
563092cee5fSValentin Clement         rewriter.replaceOpWithNewOp<mlir::LLVM::BitcastOp>(convert, toTy, op0);
564092cee5fSValentin Clement         return mlir::success();
565092cee5fSValentin Clement       }
566092cee5fSValentin Clement     }
567092cee5fSValentin Clement     return emitError(loc) << "cannot convert " << fromTy << " to " << toTy;
568092cee5fSValentin Clement   }
569092cee5fSValentin Clement };
570092cee5fSValentin Clement 
5719534e361SValentin Clement /// Lower `fir.dispatch` operation. A virtual call to a method in a dispatch
5729534e361SValentin Clement /// table.
5739534e361SValentin Clement struct DispatchOpConversion : public FIROpConversion<fir::DispatchOp> {
5749534e361SValentin Clement   using FIROpConversion::FIROpConversion;
5759534e361SValentin Clement 
5769534e361SValentin Clement   mlir::LogicalResult
5779534e361SValentin Clement   matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
5789534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5799534e361SValentin Clement     return rewriter.notifyMatchFailure(
5809534e361SValentin Clement         dispatch, "fir.dispatch codegen is not implemented yet");
5819534e361SValentin Clement   }
5829534e361SValentin Clement };
5839534e361SValentin Clement 
5849534e361SValentin Clement /// Lower `fir.dispatch_table` operation. The dispatch table for a Fortran
5859534e361SValentin Clement /// derived type.
5869534e361SValentin Clement struct DispatchTableOpConversion
5879534e361SValentin Clement     : public FIROpConversion<fir::DispatchTableOp> {
5889534e361SValentin Clement   using FIROpConversion::FIROpConversion;
5899534e361SValentin Clement 
5909534e361SValentin Clement   mlir::LogicalResult
5919534e361SValentin Clement   matchAndRewrite(fir::DispatchTableOp dispTab, OpAdaptor adaptor,
5929534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
5939534e361SValentin Clement     return rewriter.notifyMatchFailure(
5949534e361SValentin Clement         dispTab, "fir.dispatch_table codegen is not implemented yet");
5959534e361SValentin Clement   }
5969534e361SValentin Clement };
5979534e361SValentin Clement 
5989534e361SValentin Clement /// Lower `fir.dt_entry` operation. An entry in a dispatch table; binds a
5999534e361SValentin Clement /// method-name to a function.
6009534e361SValentin Clement struct DTEntryOpConversion : public FIROpConversion<fir::DTEntryOp> {
6019534e361SValentin Clement   using FIROpConversion::FIROpConversion;
6029534e361SValentin Clement 
6039534e361SValentin Clement   mlir::LogicalResult
6049534e361SValentin Clement   matchAndRewrite(fir::DTEntryOp dtEnt, OpAdaptor adaptor,
6059534e361SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
6069534e361SValentin Clement     return rewriter.notifyMatchFailure(
6079534e361SValentin Clement         dtEnt, "fir.dt_entry codegen is not implemented yet");
6089534e361SValentin Clement   }
6099534e361SValentin Clement };
6109534e361SValentin Clement 
6110c4a7a52SValentin Clement /// Lower `fir.has_value` operation to `llvm.return` operation.
612044d5b5dSValentin Clement struct HasValueOpConversion : public FIROpConversion<fir::HasValueOp> {
613044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
614044d5b5dSValentin Clement 
615044d5b5dSValentin Clement   mlir::LogicalResult
616044d5b5dSValentin Clement   matchAndRewrite(fir::HasValueOp op, OpAdaptor adaptor,
617044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
618044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<LLVM::ReturnOp>(op, adaptor.getOperands());
619044d5b5dSValentin Clement     return success();
620044d5b5dSValentin Clement   }
621044d5b5dSValentin Clement };
622044d5b5dSValentin Clement 
6230c4a7a52SValentin Clement /// Lower `fir.global` operation to `llvm.global` operation.
6240c4a7a52SValentin Clement /// `fir.insert_on_range` operations are replaced with constant dense attribute
6250c4a7a52SValentin Clement /// if they are applied on the full range.
626044d5b5dSValentin Clement struct GlobalOpConversion : public FIROpConversion<fir::GlobalOp> {
627044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
628044d5b5dSValentin Clement 
629044d5b5dSValentin Clement   mlir::LogicalResult
630044d5b5dSValentin Clement   matchAndRewrite(fir::GlobalOp global, OpAdaptor adaptor,
631044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
632044d5b5dSValentin Clement     auto tyAttr = convertType(global.getType());
633044d5b5dSValentin Clement     if (global.getType().isa<fir::BoxType>())
634044d5b5dSValentin Clement       tyAttr = tyAttr.cast<mlir::LLVM::LLVMPointerType>().getElementType();
635044d5b5dSValentin Clement     auto loc = global.getLoc();
636044d5b5dSValentin Clement     mlir::Attribute initAttr{};
637044d5b5dSValentin Clement     if (global.initVal())
638044d5b5dSValentin Clement       initAttr = global.initVal().getValue();
639044d5b5dSValentin Clement     auto linkage = convertLinkage(global.linkName());
640044d5b5dSValentin Clement     auto isConst = global.constant().hasValue();
641044d5b5dSValentin Clement     auto g = rewriter.create<mlir::LLVM::GlobalOp>(
642044d5b5dSValentin Clement         loc, tyAttr, isConst, linkage, global.sym_name(), initAttr);
643044d5b5dSValentin Clement     auto &gr = g.getInitializerRegion();
644044d5b5dSValentin Clement     rewriter.inlineRegionBefore(global.region(), gr, gr.end());
645044d5b5dSValentin Clement     if (!gr.empty()) {
646044d5b5dSValentin Clement       // Replace insert_on_range with a constant dense attribute if the
647044d5b5dSValentin Clement       // initialization is on the full range.
648044d5b5dSValentin Clement       auto insertOnRangeOps = gr.front().getOps<fir::InsertOnRangeOp>();
649044d5b5dSValentin Clement       for (auto insertOp : insertOnRangeOps) {
650044d5b5dSValentin Clement         if (isFullRange(insertOp.coor(), insertOp.getType())) {
651044d5b5dSValentin Clement           auto seqTyAttr = convertType(insertOp.getType());
652044d5b5dSValentin Clement           auto *op = insertOp.val().getDefiningOp();
653044d5b5dSValentin Clement           auto constant = mlir::dyn_cast<mlir::arith::ConstantOp>(op);
654044d5b5dSValentin Clement           if (!constant) {
655044d5b5dSValentin Clement             auto convertOp = mlir::dyn_cast<fir::ConvertOp>(op);
656044d5b5dSValentin Clement             if (!convertOp)
657044d5b5dSValentin Clement               continue;
658044d5b5dSValentin Clement             constant = cast<mlir::arith::ConstantOp>(
659044d5b5dSValentin Clement                 convertOp.value().getDefiningOp());
660044d5b5dSValentin Clement           }
661044d5b5dSValentin Clement           mlir::Type vecType = mlir::VectorType::get(
662044d5b5dSValentin Clement               insertOp.getType().getShape(), constant.getType());
663044d5b5dSValentin Clement           auto denseAttr = mlir::DenseElementsAttr::get(
664044d5b5dSValentin Clement               vecType.cast<ShapedType>(), constant.value());
665044d5b5dSValentin Clement           rewriter.setInsertionPointAfter(insertOp);
666044d5b5dSValentin Clement           rewriter.replaceOpWithNewOp<mlir::arith::ConstantOp>(
667044d5b5dSValentin Clement               insertOp, seqTyAttr, denseAttr);
668044d5b5dSValentin Clement         }
669044d5b5dSValentin Clement       }
670044d5b5dSValentin Clement     }
671044d5b5dSValentin Clement     rewriter.eraseOp(global);
672044d5b5dSValentin Clement     return success();
673044d5b5dSValentin Clement   }
674044d5b5dSValentin Clement 
675044d5b5dSValentin Clement   bool isFullRange(mlir::ArrayAttr indexes, fir::SequenceType seqTy) const {
676044d5b5dSValentin Clement     auto extents = seqTy.getShape();
677044d5b5dSValentin Clement     if (indexes.size() / 2 != extents.size())
678044d5b5dSValentin Clement       return false;
679044d5b5dSValentin Clement     for (unsigned i = 0; i < indexes.size(); i += 2) {
680044d5b5dSValentin Clement       if (indexes[i].cast<IntegerAttr>().getInt() != 0)
681044d5b5dSValentin Clement         return false;
682044d5b5dSValentin Clement       if (indexes[i + 1].cast<IntegerAttr>().getInt() != extents[i / 2] - 1)
683044d5b5dSValentin Clement         return false;
684044d5b5dSValentin Clement     }
685044d5b5dSValentin Clement     return true;
686044d5b5dSValentin Clement   }
687044d5b5dSValentin Clement 
6880c4a7a52SValentin Clement   // TODO: String comparaison should be avoided. Replace linkName with an
6890c4a7a52SValentin Clement   // enumeration.
690044d5b5dSValentin Clement   mlir::LLVM::Linkage convertLinkage(Optional<StringRef> optLinkage) const {
691044d5b5dSValentin Clement     if (optLinkage.hasValue()) {
692044d5b5dSValentin Clement       auto name = optLinkage.getValue();
693044d5b5dSValentin Clement       if (name == "internal")
694044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Internal;
695044d5b5dSValentin Clement       if (name == "linkonce")
696044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Linkonce;
697044d5b5dSValentin Clement       if (name == "common")
698044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Common;
699044d5b5dSValentin Clement       if (name == "weak")
700044d5b5dSValentin Clement         return mlir::LLVM::Linkage::Weak;
701044d5b5dSValentin Clement     }
702044d5b5dSValentin Clement     return mlir::LLVM::Linkage::External;
703044d5b5dSValentin Clement   }
704044d5b5dSValentin Clement };
705044d5b5dSValentin Clement 
706*39f4ef81SValentin Clement void genCondBrOp(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
707*39f4ef81SValentin Clement                  Optional<mlir::ValueRange> destOps,
708*39f4ef81SValentin Clement                  mlir::ConversionPatternRewriter &rewriter,
709*39f4ef81SValentin Clement                  mlir::Block *newBlock) {
710*39f4ef81SValentin Clement   if (destOps.hasValue())
711*39f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, destOps.getValue(),
712*39f4ef81SValentin Clement                                           newBlock, mlir::ValueRange());
713*39f4ef81SValentin Clement   else
714*39f4ef81SValentin Clement     rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, dest, newBlock);
715*39f4ef81SValentin Clement }
716*39f4ef81SValentin Clement 
717*39f4ef81SValentin Clement template <typename A, typename B>
718*39f4ef81SValentin Clement void genBrOp(A caseOp, mlir::Block *dest, Optional<B> destOps,
719*39f4ef81SValentin Clement              mlir::ConversionPatternRewriter &rewriter) {
720*39f4ef81SValentin Clement   if (destOps.hasValue())
721*39f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, destOps.getValue(),
722*39f4ef81SValentin Clement                                                   dest);
723*39f4ef81SValentin Clement   else
724*39f4ef81SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::BrOp>(caseOp, llvm::None, dest);
725*39f4ef81SValentin Clement }
726*39f4ef81SValentin Clement 
727*39f4ef81SValentin Clement void genCaseLadderStep(mlir::Location loc, mlir::Value cmp, mlir::Block *dest,
728*39f4ef81SValentin Clement                        Optional<mlir::ValueRange> destOps,
729*39f4ef81SValentin Clement                        mlir::ConversionPatternRewriter &rewriter) {
730*39f4ef81SValentin Clement   auto *thisBlock = rewriter.getInsertionBlock();
731*39f4ef81SValentin Clement   auto *newBlock = createBlock(rewriter, dest);
732*39f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(thisBlock);
733*39f4ef81SValentin Clement   genCondBrOp(loc, cmp, dest, destOps, rewriter, newBlock);
734*39f4ef81SValentin Clement   rewriter.setInsertionPointToEnd(newBlock);
735*39f4ef81SValentin Clement }
736*39f4ef81SValentin Clement 
737*39f4ef81SValentin Clement /// Conversion of `fir.select_case`
738*39f4ef81SValentin Clement ///
739*39f4ef81SValentin Clement /// The `fir.select_case` operation is converted to a if-then-else ladder.
740*39f4ef81SValentin Clement /// Depending on the case condition type, one or several comparison and
741*39f4ef81SValentin Clement /// conditional branching can be generated.
742*39f4ef81SValentin Clement ///
743*39f4ef81SValentin Clement /// A a point value case such as `case(4)`, a lower bound case such as
744*39f4ef81SValentin Clement /// `case(5:)` or an upper bound case such as `case(:3)` are converted to a
745*39f4ef81SValentin Clement /// simple comparison between the selector value and the constant value in the
746*39f4ef81SValentin Clement /// case. The block associated with the case condition is then executed if
747*39f4ef81SValentin Clement /// the comparison succeed otherwise it branch to the next block with the
748*39f4ef81SValentin Clement /// comparison for the the next case conditon.
749*39f4ef81SValentin Clement ///
750*39f4ef81SValentin Clement /// A closed interval case condition such as `case(7:10)` is converted with a
751*39f4ef81SValentin Clement /// first comparison and conditional branching for the lower bound. If
752*39f4ef81SValentin Clement /// successful, it branch to a second block with the comparison for the
753*39f4ef81SValentin Clement /// upper bound in the same case condition.
754*39f4ef81SValentin Clement ///
755*39f4ef81SValentin Clement /// TODO: lowering of CHARACTER type cases is not handled yet.
756*39f4ef81SValentin Clement struct SelectCaseOpConversion : public FIROpConversion<fir::SelectCaseOp> {
757*39f4ef81SValentin Clement   using FIROpConversion::FIROpConversion;
758*39f4ef81SValentin Clement 
759*39f4ef81SValentin Clement   mlir::LogicalResult
760*39f4ef81SValentin Clement   matchAndRewrite(fir::SelectCaseOp caseOp, OpAdaptor adaptor,
761*39f4ef81SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
762*39f4ef81SValentin Clement     unsigned conds = caseOp.getNumConditions();
763*39f4ef81SValentin Clement     llvm::ArrayRef<mlir::Attribute> cases = caseOp.getCases().getValue();
764*39f4ef81SValentin Clement     // Type can be CHARACTER, INTEGER, or LOGICAL (C1145)
765*39f4ef81SValentin Clement     LLVM_ATTRIBUTE_UNUSED auto ty = caseOp.getSelector().getType();
766*39f4ef81SValentin Clement     if (ty.isa<fir::CharacterType>())
767*39f4ef81SValentin Clement       return rewriter.notifyMatchFailure(caseOp,
768*39f4ef81SValentin Clement                                          "conversion of fir.select_case with "
769*39f4ef81SValentin Clement                                          "character type not implemented yet");
770*39f4ef81SValentin Clement     mlir::Value selector = caseOp.getSelector(adaptor.getOperands());
771*39f4ef81SValentin Clement     auto loc = caseOp.getLoc();
772*39f4ef81SValentin Clement     for (unsigned t = 0; t != conds; ++t) {
773*39f4ef81SValentin Clement       mlir::Block *dest = caseOp.getSuccessor(t);
774*39f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> destOps =
775*39f4ef81SValentin Clement           caseOp.getSuccessorOperands(adaptor.getOperands(), t);
776*39f4ef81SValentin Clement       llvm::Optional<mlir::ValueRange> cmpOps =
777*39f4ef81SValentin Clement           *caseOp.getCompareOperands(adaptor.getOperands(), t);
778*39f4ef81SValentin Clement       mlir::Value caseArg = *(cmpOps.getValue().begin());
779*39f4ef81SValentin Clement       mlir::Attribute attr = cases[t];
780*39f4ef81SValentin Clement       if (attr.isa<fir::PointIntervalAttr>()) {
781*39f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
782*39f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::eq, selector, caseArg);
783*39f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
784*39f4ef81SValentin Clement         continue;
785*39f4ef81SValentin Clement       }
786*39f4ef81SValentin Clement       if (attr.isa<fir::LowerBoundAttr>()) {
787*39f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
788*39f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
789*39f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
790*39f4ef81SValentin Clement         continue;
791*39f4ef81SValentin Clement       }
792*39f4ef81SValentin Clement       if (attr.isa<fir::UpperBoundAttr>()) {
793*39f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
794*39f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg);
795*39f4ef81SValentin Clement         genCaseLadderStep(loc, cmp, dest, destOps, rewriter);
796*39f4ef81SValentin Clement         continue;
797*39f4ef81SValentin Clement       }
798*39f4ef81SValentin Clement       if (attr.isa<fir::ClosedIntervalAttr>()) {
799*39f4ef81SValentin Clement         auto cmp = rewriter.create<mlir::LLVM::ICmpOp>(
800*39f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, caseArg, selector);
801*39f4ef81SValentin Clement         auto *thisBlock = rewriter.getInsertionBlock();
802*39f4ef81SValentin Clement         auto *newBlock1 = createBlock(rewriter, dest);
803*39f4ef81SValentin Clement         auto *newBlock2 = createBlock(rewriter, dest);
804*39f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(thisBlock);
805*39f4ef81SValentin Clement         rewriter.create<mlir::LLVM::CondBrOp>(loc, cmp, newBlock1, newBlock2);
806*39f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock1);
807*39f4ef81SValentin Clement         mlir::Value caseArg0 = *(cmpOps.getValue().begin() + 1);
808*39f4ef81SValentin Clement         auto cmp0 = rewriter.create<mlir::LLVM::ICmpOp>(
809*39f4ef81SValentin Clement             loc, mlir::LLVM::ICmpPredicate::sle, selector, caseArg0);
810*39f4ef81SValentin Clement         genCondBrOp(loc, cmp0, dest, destOps, rewriter, newBlock2);
811*39f4ef81SValentin Clement         rewriter.setInsertionPointToEnd(newBlock2);
812*39f4ef81SValentin Clement         continue;
813*39f4ef81SValentin Clement       }
814*39f4ef81SValentin Clement       assert(attr.isa<mlir::UnitAttr>());
815*39f4ef81SValentin Clement       assert((t + 1 == conds) && "unit must be last");
816*39f4ef81SValentin Clement       genBrOp(caseOp, dest, destOps, rewriter);
817*39f4ef81SValentin Clement     }
818*39f4ef81SValentin Clement     return success();
819*39f4ef81SValentin Clement   }
820*39f4ef81SValentin Clement };
821*39f4ef81SValentin Clement 
8228c239909SValentin Clement template <typename OP>
8238c239909SValentin Clement void selectMatchAndRewrite(fir::LLVMTypeConverter &lowering, OP select,
8248c239909SValentin Clement                            typename OP::Adaptor adaptor,
8258c239909SValentin Clement                            mlir::ConversionPatternRewriter &rewriter) {
8268c239909SValentin Clement   unsigned conds = select.getNumConditions();
8278c239909SValentin Clement   auto cases = select.getCases().getValue();
8288c239909SValentin Clement   mlir::Value selector = adaptor.selector();
8298c239909SValentin Clement   auto loc = select.getLoc();
8308c239909SValentin Clement   assert(conds > 0 && "select must have cases");
8318c239909SValentin Clement 
8328c239909SValentin Clement   llvm::SmallVector<mlir::Block *> destinations;
8338c239909SValentin Clement   llvm::SmallVector<mlir::ValueRange> destinationsOperands;
8348c239909SValentin Clement   mlir::Block *defaultDestination;
8358c239909SValentin Clement   mlir::ValueRange defaultOperands;
8368c239909SValentin Clement   llvm::SmallVector<int32_t> caseValues;
8378c239909SValentin Clement 
8388c239909SValentin Clement   for (unsigned t = 0; t != conds; ++t) {
8398c239909SValentin Clement     mlir::Block *dest = select.getSuccessor(t);
8408c239909SValentin Clement     auto destOps = select.getSuccessorOperands(adaptor.getOperands(), t);
8418c239909SValentin Clement     const mlir::Attribute &attr = cases[t];
8428c239909SValentin Clement     if (auto intAttr = attr.template dyn_cast<mlir::IntegerAttr>()) {
8438c239909SValentin Clement       destinations.push_back(dest);
8448c239909SValentin Clement       destinationsOperands.push_back(destOps.hasValue() ? *destOps
8458c239909SValentin Clement                                                         : ValueRange());
8468c239909SValentin Clement       caseValues.push_back(intAttr.getInt());
8478c239909SValentin Clement       continue;
8488c239909SValentin Clement     }
8498c239909SValentin Clement     assert(attr.template dyn_cast_or_null<mlir::UnitAttr>());
8508c239909SValentin Clement     assert((t + 1 == conds) && "unit must be last");
8518c239909SValentin Clement     defaultDestination = dest;
8528c239909SValentin Clement     defaultOperands = destOps.hasValue() ? *destOps : ValueRange();
8538c239909SValentin Clement   }
8548c239909SValentin Clement 
8558c239909SValentin Clement   // LLVM::SwitchOp takes a i32 type for the selector.
8568c239909SValentin Clement   if (select.getSelector().getType() != rewriter.getI32Type())
8578c239909SValentin Clement     selector =
8588c239909SValentin Clement         rewriter.create<LLVM::TruncOp>(loc, rewriter.getI32Type(), selector);
8598c239909SValentin Clement 
8608c239909SValentin Clement   rewriter.replaceOpWithNewOp<mlir::LLVM::SwitchOp>(
8618c239909SValentin Clement       select, selector,
8628c239909SValentin Clement       /*defaultDestination=*/defaultDestination,
8638c239909SValentin Clement       /*defaultOperands=*/defaultOperands,
8648c239909SValentin Clement       /*caseValues=*/caseValues,
8658c239909SValentin Clement       /*caseDestinations=*/destinations,
8668c239909SValentin Clement       /*caseOperands=*/destinationsOperands,
8678c239909SValentin Clement       /*branchWeights=*/ArrayRef<int32_t>());
8688c239909SValentin Clement }
8698c239909SValentin Clement 
8708c239909SValentin Clement /// conversion of fir::SelectOp to an if-then-else ladder
8718c239909SValentin Clement struct SelectOpConversion : public FIROpConversion<fir::SelectOp> {
8728c239909SValentin Clement   using FIROpConversion::FIROpConversion;
8738c239909SValentin Clement 
8748c239909SValentin Clement   mlir::LogicalResult
8758c239909SValentin Clement   matchAndRewrite(fir::SelectOp op, OpAdaptor adaptor,
8768c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
8778c239909SValentin Clement     selectMatchAndRewrite<fir::SelectOp>(lowerTy(), op, adaptor, rewriter);
8788c239909SValentin Clement     return success();
8798c239909SValentin Clement   }
8808c239909SValentin Clement };
8818c239909SValentin Clement 
882e3349fa1SAndrzej Warzynski /// `fir.load` --> `llvm.load`
883e3349fa1SAndrzej Warzynski struct LoadOpConversion : public FIROpConversion<fir::LoadOp> {
884e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
885e3349fa1SAndrzej Warzynski 
886e3349fa1SAndrzej Warzynski   mlir::LogicalResult
887e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::LoadOp load, OpAdaptor adaptor,
888e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
889e3349fa1SAndrzej Warzynski     // fir.box is a special case because it is considered as an ssa values in
890e3349fa1SAndrzej Warzynski     // fir, but it is lowered as a pointer to a descriptor. So fir.ref<fir.box>
891e3349fa1SAndrzej Warzynski     // and fir.box end up being the same llvm types and loading a
892e3349fa1SAndrzej Warzynski     // fir.ref<fir.box> is actually a no op in LLVM.
893e3349fa1SAndrzej Warzynski     if (load.getType().isa<fir::BoxType>()) {
894e3349fa1SAndrzej Warzynski       rewriter.replaceOp(load, adaptor.getOperands()[0]);
895e3349fa1SAndrzej Warzynski     } else {
896e3349fa1SAndrzej Warzynski       mlir::Type ty = convertType(load.getType());
897e3349fa1SAndrzej Warzynski       ArrayRef<NamedAttribute> at = load->getAttrs();
898e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::LoadOp>(
899e3349fa1SAndrzej Warzynski           load, ty, adaptor.getOperands(), at);
900e3349fa1SAndrzej Warzynski     }
901e3349fa1SAndrzej Warzynski     return success();
902e3349fa1SAndrzej Warzynski   }
903e3349fa1SAndrzej Warzynski };
904e3349fa1SAndrzej Warzynski 
9058c239909SValentin Clement /// conversion of fir::SelectRankOp to an if-then-else ladder
9068c239909SValentin Clement struct SelectRankOpConversion : public FIROpConversion<fir::SelectRankOp> {
9078c239909SValentin Clement   using FIROpConversion::FIROpConversion;
9088c239909SValentin Clement 
9098c239909SValentin Clement   mlir::LogicalResult
9108c239909SValentin Clement   matchAndRewrite(fir::SelectRankOp op, OpAdaptor adaptor,
9118c239909SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
9128c239909SValentin Clement     selectMatchAndRewrite<fir::SelectRankOp>(lowerTy(), op, adaptor, rewriter);
9138c239909SValentin Clement     return success();
9148c239909SValentin Clement   }
9158c239909SValentin Clement };
9168c239909SValentin Clement 
917e3349fa1SAndrzej Warzynski /// `fir.store` --> `llvm.store`
918e3349fa1SAndrzej Warzynski struct StoreOpConversion : public FIROpConversion<fir::StoreOp> {
919e3349fa1SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
920e3349fa1SAndrzej Warzynski 
921e3349fa1SAndrzej Warzynski   mlir::LogicalResult
922e3349fa1SAndrzej Warzynski   matchAndRewrite(fir::StoreOp store, OpAdaptor adaptor,
923e3349fa1SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
924e3349fa1SAndrzej Warzynski     if (store.value().getType().isa<fir::BoxType>()) {
925e3349fa1SAndrzej Warzynski       // fir.box value is actually in memory, load it first before storing it.
926e3349fa1SAndrzej Warzynski       mlir::Location loc = store.getLoc();
927e3349fa1SAndrzej Warzynski       mlir::Type boxPtrTy = adaptor.getOperands()[0].getType();
928e3349fa1SAndrzej Warzynski       auto val = rewriter.create<mlir::LLVM::LoadOp>(
929e3349fa1SAndrzej Warzynski           loc, boxPtrTy.cast<mlir::LLVM::LLVMPointerType>().getElementType(),
930e3349fa1SAndrzej Warzynski           adaptor.getOperands()[0]);
931e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
932e3349fa1SAndrzej Warzynski           store, val, adaptor.getOperands()[1]);
933e3349fa1SAndrzej Warzynski     } else {
934e3349fa1SAndrzej Warzynski       rewriter.replaceOpWithNewOp<mlir::LLVM::StoreOp>(
935e3349fa1SAndrzej Warzynski           store, adaptor.getOperands()[0], adaptor.getOperands()[1]);
936e3349fa1SAndrzej Warzynski     }
937e3349fa1SAndrzej Warzynski     return success();
938e3349fa1SAndrzej Warzynski   }
939e3349fa1SAndrzej Warzynski };
940e3349fa1SAndrzej Warzynski 
941e3349fa1SAndrzej Warzynski /// convert to LLVM IR dialect `undef`
942044d5b5dSValentin Clement struct UndefOpConversion : public FIROpConversion<fir::UndefOp> {
943044d5b5dSValentin Clement   using FIROpConversion::FIROpConversion;
944044d5b5dSValentin Clement 
945044d5b5dSValentin Clement   mlir::LogicalResult
946044d5b5dSValentin Clement   matchAndRewrite(fir::UndefOp undef, OpAdaptor,
947044d5b5dSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
948044d5b5dSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::UndefOp>(
949044d5b5dSValentin Clement         undef, convertType(undef.getType()));
950044d5b5dSValentin Clement     return success();
951044d5b5dSValentin Clement   }
952044d5b5dSValentin Clement };
953a7a61359SValentin Clement 
954e3349fa1SAndrzej Warzynski /// `fir.unreachable` --> `llvm.unreachable`
95532e08248SAndrzej Warzynski struct UnreachableOpConversion : public FIROpConversion<fir::UnreachableOp> {
95632e08248SAndrzej Warzynski   using FIROpConversion::FIROpConversion;
95732e08248SAndrzej Warzynski 
95832e08248SAndrzej Warzynski   mlir::LogicalResult
95932e08248SAndrzej Warzynski   matchAndRewrite(fir::UnreachableOp unreach, OpAdaptor adaptor,
96032e08248SAndrzej Warzynski                   mlir::ConversionPatternRewriter &rewriter) const override {
96132e08248SAndrzej Warzynski     rewriter.replaceOpWithNewOp<mlir::LLVM::UnreachableOp>(unreach);
96232e08248SAndrzej Warzynski     return success();
96332e08248SAndrzej Warzynski   }
96432e08248SAndrzej Warzynski };
96532e08248SAndrzej Warzynski 
966a7a61359SValentin Clement struct ZeroOpConversion : public FIROpConversion<fir::ZeroOp> {
967a7a61359SValentin Clement   using FIROpConversion::FIROpConversion;
968a7a61359SValentin Clement 
969a7a61359SValentin Clement   mlir::LogicalResult
970a7a61359SValentin Clement   matchAndRewrite(fir::ZeroOp zero, OpAdaptor,
971a7a61359SValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
972a7a61359SValentin Clement     auto ty = convertType(zero.getType());
973a7a61359SValentin Clement     if (ty.isa<mlir::LLVM::LLVMPointerType>()) {
974a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::NullOp>(zero, ty);
975a7a61359SValentin Clement     } else if (ty.isa<mlir::IntegerType>()) {
976a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
977a7a61359SValentin Clement           zero, ty, mlir::IntegerAttr::get(zero.getType(), 0));
978a7a61359SValentin Clement     } else if (mlir::LLVM::isCompatibleFloatingPointType(ty)) {
979a7a61359SValentin Clement       rewriter.replaceOpWithNewOp<mlir::LLVM::ConstantOp>(
980a7a61359SValentin Clement           zero, ty, mlir::FloatAttr::get(zero.getType(), 0.0));
981a7a61359SValentin Clement     } else {
982a7a61359SValentin Clement       // TODO: create ConstantAggregateZero for FIR aggregate/array types.
98352d813edSValentin Clement       return rewriter.notifyMatchFailure(
98452d813edSValentin Clement           zero,
985a7a61359SValentin Clement           "conversion of fir.zero with aggregate type not implemented yet");
986a7a61359SValentin Clement     }
987a7a61359SValentin Clement     return success();
988a7a61359SValentin Clement   }
989a7a61359SValentin Clement };
99032e08248SAndrzej Warzynski 
99154c56347SValentin Clement // Code shared between insert_value and extract_value Ops.
99254c56347SValentin Clement struct ValueOpCommon {
99354c56347SValentin Clement   // Translate the arguments pertaining to any multidimensional array to
99454c56347SValentin Clement   // row-major order for LLVM-IR.
99554c56347SValentin Clement   static void toRowMajor(SmallVectorImpl<mlir::Attribute> &attrs,
99654c56347SValentin Clement                          mlir::Type ty) {
99754c56347SValentin Clement     assert(ty && "type is null");
99854c56347SValentin Clement     const auto end = attrs.size();
99954c56347SValentin Clement     for (std::remove_const_t<decltype(end)> i = 0; i < end; ++i) {
100054c56347SValentin Clement       if (auto seq = ty.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
100154c56347SValentin Clement         const auto dim = getDimension(seq);
100254c56347SValentin Clement         if (dim > 1) {
100354c56347SValentin Clement           auto ub = std::min(i + dim, end);
100454c56347SValentin Clement           std::reverse(attrs.begin() + i, attrs.begin() + ub);
100554c56347SValentin Clement           i += dim - 1;
100654c56347SValentin Clement         }
100754c56347SValentin Clement         ty = getArrayElementType(seq);
100854c56347SValentin Clement       } else if (auto st = ty.dyn_cast<mlir::LLVM::LLVMStructType>()) {
100954c56347SValentin Clement         ty = st.getBody()[attrs[i].cast<mlir::IntegerAttr>().getInt()];
101054c56347SValentin Clement       } else {
101154c56347SValentin Clement         llvm_unreachable("index into invalid type");
101254c56347SValentin Clement       }
101354c56347SValentin Clement     }
101454c56347SValentin Clement   }
101554c56347SValentin Clement 
101654c56347SValentin Clement   static llvm::SmallVector<mlir::Attribute>
101754c56347SValentin Clement   collectIndices(mlir::ConversionPatternRewriter &rewriter,
101854c56347SValentin Clement                  mlir::ArrayAttr arrAttr) {
101954c56347SValentin Clement     llvm::SmallVector<mlir::Attribute> attrs;
102054c56347SValentin Clement     for (auto i = arrAttr.begin(), e = arrAttr.end(); i != e; ++i) {
102154c56347SValentin Clement       if (i->isa<mlir::IntegerAttr>()) {
102254c56347SValentin Clement         attrs.push_back(*i);
102354c56347SValentin Clement       } else {
102454c56347SValentin Clement         auto fieldName = i->cast<mlir::StringAttr>().getValue();
102554c56347SValentin Clement         ++i;
102654c56347SValentin Clement         auto ty = i->cast<mlir::TypeAttr>().getValue();
102754c56347SValentin Clement         auto index = ty.cast<fir::RecordType>().getFieldIndex(fieldName);
102854c56347SValentin Clement         attrs.push_back(mlir::IntegerAttr::get(rewriter.getI32Type(), index));
102954c56347SValentin Clement       }
103054c56347SValentin Clement     }
103154c56347SValentin Clement     return attrs;
103254c56347SValentin Clement   }
103354c56347SValentin Clement 
103454c56347SValentin Clement private:
103554c56347SValentin Clement   static unsigned getDimension(mlir::LLVM::LLVMArrayType ty) {
103654c56347SValentin Clement     unsigned result = 1;
103754c56347SValentin Clement     for (auto eleTy = ty.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>();
103854c56347SValentin Clement          eleTy;
103954c56347SValentin Clement          eleTy = eleTy.getElementType().dyn_cast<mlir::LLVM::LLVMArrayType>())
104054c56347SValentin Clement       ++result;
104154c56347SValentin Clement     return result;
104254c56347SValentin Clement   }
104354c56347SValentin Clement 
104454c56347SValentin Clement   static mlir::Type getArrayElementType(mlir::LLVM::LLVMArrayType ty) {
104554c56347SValentin Clement     auto eleTy = ty.getElementType();
104654c56347SValentin Clement     while (auto arrTy = eleTy.dyn_cast<mlir::LLVM::LLVMArrayType>())
104754c56347SValentin Clement       eleTy = arrTy.getElementType();
104854c56347SValentin Clement     return eleTy;
104954c56347SValentin Clement   }
105054c56347SValentin Clement };
105154c56347SValentin Clement 
105254c56347SValentin Clement /// Extract a subobject value from an ssa-value of aggregate type
105354c56347SValentin Clement struct ExtractValueOpConversion
105454c56347SValentin Clement     : public FIROpAndTypeConversion<fir::ExtractValueOp>,
105554c56347SValentin Clement       public ValueOpCommon {
105654c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
105754c56347SValentin Clement 
105854c56347SValentin Clement   mlir::LogicalResult
105954c56347SValentin Clement   doRewrite(fir::ExtractValueOp extractVal, mlir::Type ty, OpAdaptor adaptor,
106054c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
106154c56347SValentin Clement     auto attrs = collectIndices(rewriter, extractVal.coor());
106254c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
106354c56347SValentin Clement     auto position = mlir::ArrayAttr::get(extractVal.getContext(), attrs);
106454c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::ExtractValueOp>(
106554c56347SValentin Clement         extractVal, ty, adaptor.getOperands()[0], position);
106654c56347SValentin Clement     return success();
106754c56347SValentin Clement   }
106854c56347SValentin Clement };
106954c56347SValentin Clement 
107054c56347SValentin Clement /// InsertValue is the generalized instruction for the composition of new
107154c56347SValentin Clement /// aggregate type values.
107254c56347SValentin Clement struct InsertValueOpConversion
107354c56347SValentin Clement     : public FIROpAndTypeConversion<fir::InsertValueOp>,
107454c56347SValentin Clement       public ValueOpCommon {
107554c56347SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
107654c56347SValentin Clement 
107754c56347SValentin Clement   mlir::LogicalResult
107854c56347SValentin Clement   doRewrite(fir::InsertValueOp insertVal, mlir::Type ty, OpAdaptor adaptor,
107954c56347SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
108054c56347SValentin Clement     auto attrs = collectIndices(rewriter, insertVal.coor());
108154c56347SValentin Clement     toRowMajor(attrs, adaptor.getOperands()[0].getType());
108254c56347SValentin Clement     auto position = mlir::ArrayAttr::get(insertVal.getContext(), attrs);
108354c56347SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
108454c56347SValentin Clement         insertVal, ty, adaptor.getOperands()[0], adaptor.getOperands()[1],
108554c56347SValentin Clement         position);
108654c56347SValentin Clement     return success();
108754c56347SValentin Clement   }
108854c56347SValentin Clement };
108954c56347SValentin Clement 
10903ae8e442SValentin Clement /// InsertOnRange inserts a value into a sequence over a range of offsets.
10913ae8e442SValentin Clement struct InsertOnRangeOpConversion
10923ae8e442SValentin Clement     : public FIROpAndTypeConversion<fir::InsertOnRangeOp> {
10933ae8e442SValentin Clement   using FIROpAndTypeConversion::FIROpAndTypeConversion;
10943ae8e442SValentin Clement 
10953ae8e442SValentin Clement   // Increments an array of subscripts in a row major fasion.
10963ae8e442SValentin Clement   void incrementSubscripts(const SmallVector<uint64_t> &dims,
10973ae8e442SValentin Clement                            SmallVector<uint64_t> &subscripts) const {
10983ae8e442SValentin Clement     for (size_t i = dims.size(); i > 0; --i) {
10993ae8e442SValentin Clement       if (++subscripts[i - 1] < dims[i - 1]) {
11003ae8e442SValentin Clement         return;
11013ae8e442SValentin Clement       }
11023ae8e442SValentin Clement       subscripts[i - 1] = 0;
11033ae8e442SValentin Clement     }
11043ae8e442SValentin Clement   }
11053ae8e442SValentin Clement 
11063ae8e442SValentin Clement   mlir::LogicalResult
11073ae8e442SValentin Clement   doRewrite(fir::InsertOnRangeOp range, mlir::Type ty, OpAdaptor adaptor,
11083ae8e442SValentin Clement             mlir::ConversionPatternRewriter &rewriter) const override {
11093ae8e442SValentin Clement 
11103ae8e442SValentin Clement     llvm::SmallVector<uint64_t> dims;
11113ae8e442SValentin Clement     auto type = adaptor.getOperands()[0].getType();
11123ae8e442SValentin Clement 
11133ae8e442SValentin Clement     // Iteratively extract the array dimensions from the type.
11143ae8e442SValentin Clement     while (auto t = type.dyn_cast<mlir::LLVM::LLVMArrayType>()) {
11153ae8e442SValentin Clement       dims.push_back(t.getNumElements());
11163ae8e442SValentin Clement       type = t.getElementType();
11173ae8e442SValentin Clement     }
11183ae8e442SValentin Clement 
11193ae8e442SValentin Clement     SmallVector<uint64_t> lBounds;
11203ae8e442SValentin Clement     SmallVector<uint64_t> uBounds;
11213ae8e442SValentin Clement 
11223ae8e442SValentin Clement     // Extract integer value from the attribute
11233ae8e442SValentin Clement     SmallVector<int64_t> coordinates = llvm::to_vector<4>(
11243ae8e442SValentin Clement         llvm::map_range(range.coor(), [](Attribute a) -> int64_t {
11253ae8e442SValentin Clement           return a.cast<IntegerAttr>().getInt();
11263ae8e442SValentin Clement         }));
11273ae8e442SValentin Clement 
11283ae8e442SValentin Clement     // Unzip the upper and lower bound and convert to a row major format.
11293ae8e442SValentin Clement     for (auto i = coordinates.rbegin(), e = coordinates.rend(); i != e; ++i) {
11303ae8e442SValentin Clement       uBounds.push_back(*i++);
11313ae8e442SValentin Clement       lBounds.push_back(*i);
11323ae8e442SValentin Clement     }
11333ae8e442SValentin Clement 
11343ae8e442SValentin Clement     auto &subscripts = lBounds;
11353ae8e442SValentin Clement     auto loc = range.getLoc();
11363ae8e442SValentin Clement     mlir::Value lastOp = adaptor.getOperands()[0];
11373ae8e442SValentin Clement     mlir::Value insertVal = adaptor.getOperands()[1];
11383ae8e442SValentin Clement 
11393ae8e442SValentin Clement     auto i64Ty = rewriter.getI64Type();
11403ae8e442SValentin Clement     while (subscripts != uBounds) {
11413ae8e442SValentin Clement       // Convert uint64_t's to Attribute's.
11423ae8e442SValentin Clement       SmallVector<mlir::Attribute> subscriptAttrs;
11433ae8e442SValentin Clement       for (const auto &subscript : subscripts)
11443ae8e442SValentin Clement         subscriptAttrs.push_back(IntegerAttr::get(i64Ty, subscript));
11453ae8e442SValentin Clement       lastOp = rewriter.create<mlir::LLVM::InsertValueOp>(
11463ae8e442SValentin Clement           loc, ty, lastOp, insertVal,
11473ae8e442SValentin Clement           ArrayAttr::get(range.getContext(), subscriptAttrs));
11483ae8e442SValentin Clement 
11493ae8e442SValentin Clement       incrementSubscripts(dims, subscripts);
11503ae8e442SValentin Clement     }
11513ae8e442SValentin Clement 
11523ae8e442SValentin Clement     // Convert uint64_t's to Attribute's.
11533ae8e442SValentin Clement     SmallVector<mlir::Attribute> subscriptAttrs;
11543ae8e442SValentin Clement     for (const auto &subscript : subscripts)
11553ae8e442SValentin Clement       subscriptAttrs.push_back(
11563ae8e442SValentin Clement           IntegerAttr::get(rewriter.getI64Type(), subscript));
11573ae8e442SValentin Clement     mlir::ArrayRef<mlir::Attribute> arrayRef(subscriptAttrs);
11583ae8e442SValentin Clement 
11593ae8e442SValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(
11603ae8e442SValentin Clement         range, ty, lastOp, insertVal,
11613ae8e442SValentin Clement         ArrayAttr::get(range.getContext(), arrayRef));
11623ae8e442SValentin Clement 
11633ae8e442SValentin Clement     return success();
11643ae8e442SValentin Clement   }
11653ae8e442SValentin Clement };
11667b5132daSValentin Clement 
11677b5132daSValentin Clement //
11687b5132daSValentin Clement // Primitive operations on Complex types
11697b5132daSValentin Clement //
11707b5132daSValentin Clement 
11717b5132daSValentin Clement /// Generate inline code for complex addition/subtraction
11727b5132daSValentin Clement template <typename LLVMOP, typename OPTY>
11737b5132daSValentin Clement mlir::LLVM::InsertValueOp complexSum(OPTY sumop, mlir::ValueRange opnds,
11747b5132daSValentin Clement                                      mlir::ConversionPatternRewriter &rewriter,
11757b5132daSValentin Clement                                      fir::LLVMTypeConverter &lowering) {
11767b5132daSValentin Clement   mlir::Value a = opnds[0];
11777b5132daSValentin Clement   mlir::Value b = opnds[1];
11787b5132daSValentin Clement   auto loc = sumop.getLoc();
11797b5132daSValentin Clement   auto ctx = sumop.getContext();
11807b5132daSValentin Clement   auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
11817b5132daSValentin Clement   auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
11827b5132daSValentin Clement   mlir::Type eleTy = lowering.convertType(getComplexEleTy(sumop.getType()));
11837b5132daSValentin Clement   mlir::Type ty = lowering.convertType(sumop.getType());
11847b5132daSValentin Clement   auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
11857b5132daSValentin Clement   auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
11867b5132daSValentin Clement   auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
11877b5132daSValentin Clement   auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
11887b5132daSValentin Clement   auto rx = rewriter.create<LLVMOP>(loc, eleTy, x0, x1);
11897b5132daSValentin Clement   auto ry = rewriter.create<LLVMOP>(loc, eleTy, y0, y1);
11907b5132daSValentin Clement   auto r0 = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
11917b5132daSValentin Clement   auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r0, rx, c0);
11927b5132daSValentin Clement   return rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ry, c1);
11937b5132daSValentin Clement }
11947b5132daSValentin Clement 
11957b5132daSValentin Clement struct AddcOpConversion : public FIROpConversion<fir::AddcOp> {
11967b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
11977b5132daSValentin Clement 
11987b5132daSValentin Clement   mlir::LogicalResult
11997b5132daSValentin Clement   matchAndRewrite(fir::AddcOp addc, OpAdaptor adaptor,
12007b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12017b5132daSValentin Clement     // given: (x + iy) + (x' + iy')
12027b5132daSValentin Clement     // result: (x + x') + i(y + y')
12037b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FAddOp>(addc, adaptor.getOperands(),
12047b5132daSValentin Clement                                             rewriter, lowerTy());
12057b5132daSValentin Clement     rewriter.replaceOp(addc, r.getResult());
12067b5132daSValentin Clement     return success();
12077b5132daSValentin Clement   }
12087b5132daSValentin Clement };
12097b5132daSValentin Clement 
12107b5132daSValentin Clement struct SubcOpConversion : public FIROpConversion<fir::SubcOp> {
12117b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12127b5132daSValentin Clement 
12137b5132daSValentin Clement   mlir::LogicalResult
12147b5132daSValentin Clement   matchAndRewrite(fir::SubcOp subc, OpAdaptor adaptor,
12157b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12167b5132daSValentin Clement     // given: (x + iy) - (x' + iy')
12177b5132daSValentin Clement     // result: (x - x') + i(y - y')
12187b5132daSValentin Clement     auto r = complexSum<mlir::LLVM::FSubOp>(subc, adaptor.getOperands(),
12197b5132daSValentin Clement                                             rewriter, lowerTy());
12207b5132daSValentin Clement     rewriter.replaceOp(subc, r.getResult());
12217b5132daSValentin Clement     return success();
12227b5132daSValentin Clement   }
12237b5132daSValentin Clement };
12247b5132daSValentin Clement 
12257b5132daSValentin Clement /// Inlined complex multiply
12267b5132daSValentin Clement struct MulcOpConversion : public FIROpConversion<fir::MulcOp> {
12277b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12287b5132daSValentin Clement 
12297b5132daSValentin Clement   mlir::LogicalResult
12307b5132daSValentin Clement   matchAndRewrite(fir::MulcOp mulc, OpAdaptor adaptor,
12317b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12327b5132daSValentin Clement     // TODO: Can we use a call to __muldc3 ?
12337b5132daSValentin Clement     // given: (x + iy) * (x' + iy')
12347b5132daSValentin Clement     // result: (xx'-yy')+i(xy'+yx')
12357b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
12367b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
12377b5132daSValentin Clement     auto loc = mulc.getLoc();
12387b5132daSValentin Clement     auto *ctx = mulc.getContext();
12397b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
12407b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
12417b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(mulc.getType()));
12427b5132daSValentin Clement     mlir::Type ty = convertType(mulc.getType());
12437b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
12447b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
12457b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
12467b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
12477b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
12487b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
12497b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
12507b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xy, yx);
12517b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
12527b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, xx, yy);
12537b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
12547b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
12557b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
12567b5132daSValentin Clement     rewriter.replaceOp(mulc, r0.getResult());
12577b5132daSValentin Clement     return success();
12587b5132daSValentin Clement   }
12597b5132daSValentin Clement };
12607b5132daSValentin Clement 
12617b5132daSValentin Clement /// Inlined complex division
12627b5132daSValentin Clement struct DivcOpConversion : public FIROpConversion<fir::DivcOp> {
12637b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
12647b5132daSValentin Clement 
12657b5132daSValentin Clement   mlir::LogicalResult
12667b5132daSValentin Clement   matchAndRewrite(fir::DivcOp divc, OpAdaptor adaptor,
12677b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
12687b5132daSValentin Clement     // TODO: Can we use a call to __divdc3 instead?
12697b5132daSValentin Clement     // Just generate inline code for now.
12707b5132daSValentin Clement     // given: (x + iy) / (x' + iy')
12717b5132daSValentin Clement     // result: ((xx'+yy')/d) + i((yx'-xy')/d) where d = x'x' + y'y'
12727b5132daSValentin Clement     mlir::Value a = adaptor.getOperands()[0];
12737b5132daSValentin Clement     mlir::Value b = adaptor.getOperands()[1];
12747b5132daSValentin Clement     auto loc = divc.getLoc();
12757b5132daSValentin Clement     auto *ctx = divc.getContext();
12767b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(0));
12777b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctx, rewriter.getI32IntegerAttr(1));
12787b5132daSValentin Clement     mlir::Type eleTy = convertType(getComplexEleTy(divc.getType()));
12797b5132daSValentin Clement     mlir::Type ty = convertType(divc.getType());
12807b5132daSValentin Clement     auto x0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c0);
12817b5132daSValentin Clement     auto y0 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, a, c1);
12827b5132daSValentin Clement     auto x1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c0);
12837b5132daSValentin Clement     auto y1 = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, b, c1);
12847b5132daSValentin Clement     auto xx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, x1);
12857b5132daSValentin Clement     auto x1x1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x1, x1);
12867b5132daSValentin Clement     auto yx = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, x1);
12877b5132daSValentin Clement     auto xy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, x0, y1);
12887b5132daSValentin Clement     auto yy = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y0, y1);
12897b5132daSValentin Clement     auto y1y1 = rewriter.create<mlir::LLVM::FMulOp>(loc, eleTy, y1, y1);
12907b5132daSValentin Clement     auto d = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, x1x1, y1y1);
12917b5132daSValentin Clement     auto rrn = rewriter.create<mlir::LLVM::FAddOp>(loc, eleTy, xx, yy);
12927b5132daSValentin Clement     auto rin = rewriter.create<mlir::LLVM::FSubOp>(loc, eleTy, yx, xy);
12937b5132daSValentin Clement     auto rr = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rrn, d);
12947b5132daSValentin Clement     auto ri = rewriter.create<mlir::LLVM::FDivOp>(loc, eleTy, rin, d);
12957b5132daSValentin Clement     auto ra = rewriter.create<mlir::LLVM::UndefOp>(loc, ty);
12967b5132daSValentin Clement     auto r1 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, ra, rr, c0);
12977b5132daSValentin Clement     auto r0 = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, r1, ri, c1);
12987b5132daSValentin Clement     rewriter.replaceOp(divc, r0.getResult());
12997b5132daSValentin Clement     return success();
13007b5132daSValentin Clement   }
13017b5132daSValentin Clement };
13027b5132daSValentin Clement 
13037b5132daSValentin Clement /// Inlined complex negation
13047b5132daSValentin Clement struct NegcOpConversion : public FIROpConversion<fir::NegcOp> {
13057b5132daSValentin Clement   using FIROpConversion::FIROpConversion;
13067b5132daSValentin Clement 
13077b5132daSValentin Clement   mlir::LogicalResult
13087b5132daSValentin Clement   matchAndRewrite(fir::NegcOp neg, OpAdaptor adaptor,
13097b5132daSValentin Clement                   mlir::ConversionPatternRewriter &rewriter) const override {
13107b5132daSValentin Clement     // given: -(x + iy)
13117b5132daSValentin Clement     // result: -x - iy
13127b5132daSValentin Clement     auto *ctxt = neg.getContext();
13137b5132daSValentin Clement     auto eleTy = convertType(getComplexEleTy(neg.getType()));
13147b5132daSValentin Clement     auto ty = convertType(neg.getType());
13157b5132daSValentin Clement     auto loc = neg.getLoc();
13167b5132daSValentin Clement     mlir::Value o0 = adaptor.getOperands()[0];
13177b5132daSValentin Clement     auto c0 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(0));
13187b5132daSValentin Clement     auto c1 = mlir::ArrayAttr::get(ctxt, rewriter.getI32IntegerAttr(1));
13197b5132daSValentin Clement     auto rp = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c0);
13207b5132daSValentin Clement     auto ip = rewriter.create<mlir::LLVM::ExtractValueOp>(loc, eleTy, o0, c1);
13217b5132daSValentin Clement     auto nrp = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, rp);
13227b5132daSValentin Clement     auto nip = rewriter.create<mlir::LLVM::FNegOp>(loc, eleTy, ip);
13237b5132daSValentin Clement     auto r = rewriter.create<mlir::LLVM::InsertValueOp>(loc, ty, o0, nrp, c0);
13247b5132daSValentin Clement     rewriter.replaceOpWithNewOp<mlir::LLVM::InsertValueOp>(neg, ty, r, nip, c1);
13257b5132daSValentin Clement     return success();
13267b5132daSValentin Clement   }
13277b5132daSValentin Clement };
13287b5132daSValentin Clement 
1329044d5b5dSValentin Clement } // namespace
1330044d5b5dSValentin Clement 
1331044d5b5dSValentin Clement namespace {
1332044d5b5dSValentin Clement /// Convert FIR dialect to LLVM dialect
1333044d5b5dSValentin Clement ///
1334044d5b5dSValentin Clement /// This pass lowers all FIR dialect operations to LLVM IR dialect. An
1335044d5b5dSValentin Clement /// MLIR pass is used to lower residual Std dialect to LLVM IR dialect.
1336044d5b5dSValentin Clement ///
1337044d5b5dSValentin Clement /// This pass is not complete yet. We are upstreaming it in small patches.
1338044d5b5dSValentin Clement class FIRToLLVMLowering : public fir::FIRToLLVMLoweringBase<FIRToLLVMLowering> {
1339044d5b5dSValentin Clement public:
1340044d5b5dSValentin Clement   mlir::ModuleOp getModule() { return getOperation(); }
1341044d5b5dSValentin Clement 
1342044d5b5dSValentin Clement   void runOnOperation() override final {
13437b5132daSValentin Clement     auto mod = getModule();
13447b5132daSValentin Clement     if (!forcedTargetTriple.empty()) {
13457b5132daSValentin Clement       fir::setTargetTriple(mod, forcedTargetTriple);
13467b5132daSValentin Clement     }
13477b5132daSValentin Clement 
1348044d5b5dSValentin Clement     auto *context = getModule().getContext();
1349044d5b5dSValentin Clement     fir::LLVMTypeConverter typeConverter{getModule()};
1350044d5b5dSValentin Clement     mlir::OwningRewritePatternList pattern(context);
1351df3b9810SValentin Clement     pattern.insert<
13521e6d9c06SDiana Picus         AddcOpConversion, AddrOfOpConversion, AllocaOpConversion,
13531e6d9c06SDiana Picus         BoxAddrOpConversion, BoxDimsOpConversion, BoxEleSizeOpConversion,
13541e6d9c06SDiana Picus         BoxIsAllocOpConversion, BoxIsArrayOpConversion, BoxIsPtrOpConversion,
13551e6d9c06SDiana Picus         BoxRankOpConversion, CallOpConversion, ConvertOpConversion,
13569534e361SValentin Clement         DispatchOpConversion, DispatchTableOpConversion, DTEntryOpConversion,
13571e6d9c06SDiana Picus         DivcOpConversion, ExtractValueOpConversion, HasValueOpConversion,
13581e6d9c06SDiana Picus         GlobalOpConversion, InsertOnRangeOpConversion, InsertValueOpConversion,
13591e6d9c06SDiana Picus         LoadOpConversion, NegcOpConversion, MulcOpConversion,
1360*39f4ef81SValentin Clement         SelectCaseOpConversion, SelectOpConversion, SelectRankOpConversion,
1361*39f4ef81SValentin Clement         StoreOpConversion, SubcOpConversion, UndefOpConversion,
1362*39f4ef81SValentin Clement         UnreachableOpConversion, ZeroOpConversion>(typeConverter);
1363044d5b5dSValentin Clement     mlir::populateStdToLLVMConversionPatterns(typeConverter, pattern);
1364044d5b5dSValentin Clement     mlir::arith::populateArithmeticToLLVMConversionPatterns(typeConverter,
1365044d5b5dSValentin Clement                                                             pattern);
1366044d5b5dSValentin Clement     mlir::ConversionTarget target{*context};
1367044d5b5dSValentin Clement     target.addLegalDialect<mlir::LLVM::LLVMDialect>();
1368044d5b5dSValentin Clement 
1369044d5b5dSValentin Clement     // required NOPs for applying a full conversion
1370044d5b5dSValentin Clement     target.addLegalOp<mlir::ModuleOp>();
1371044d5b5dSValentin Clement 
1372044d5b5dSValentin Clement     // apply the patterns
1373044d5b5dSValentin Clement     if (mlir::failed(mlir::applyFullConversion(getModule(), target,
1374044d5b5dSValentin Clement                                                std::move(pattern)))) {
1375044d5b5dSValentin Clement       signalPassFailure();
1376044d5b5dSValentin Clement     }
1377044d5b5dSValentin Clement   }
1378044d5b5dSValentin Clement };
1379044d5b5dSValentin Clement } // namespace
1380044d5b5dSValentin Clement 
1381044d5b5dSValentin Clement std::unique_ptr<mlir::Pass> fir::createFIRToLLVMPass() {
1382044d5b5dSValentin Clement   return std::make_unique<FIRToLLVMLowering>();
1383044d5b5dSValentin Clement }
1384