[flang-commits] [flang] [flang] FIR memory ops lowering to MemRef dialect (PR #173507)

via flang-commits flang-commits at lists.llvm.org
Wed Dec 24 11:43:24 PST 2025


llvmbot wrote:


<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-flang-codegen

@llvm/pr-subscribers-flang-fir-hlfir

Author: Susan Tan (ス-ザン タン) (SusanTan)

<details>
<summary>Changes</summary>

This patch introduces FIRToMemRef, a lowering pass that lowers FIR memory ops to MemRef dialect, including slices and shifts handling. Since we use `fir.convert` to convert between memref and fir types such that partial lowering is possible, we also added a customized `fir.convert` implementation that handles memref type lowering. 

---

Patch is 162.97 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/173507.diff


25 Files Affected:

- (added) flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h (+226) 
- (modified) flang/include/flang/Optimizer/Transforms/Passes.td (+12) 
- (modified) flang/lib/Optimizer/CodeGen/CodeGen.cpp (+53-7) 
- (modified) flang/lib/Optimizer/Transforms/CMakeLists.txt (+1) 
- (added) flang/lib/Optimizer/Transforms/FIRToMemRef.cpp (+1171) 
- (added) flang/test/Fir/FIRToMemRef/alloca.mlir (+97) 
- (added) flang/test/Fir/FIRToMemRef/array-coor-op.mlir (+47) 
- (added) flang/test/Fir/FIRToMemRef/complex.mlir (+18) 
- (added) flang/test/Fir/FIRToMemRef/cuda-alloca.mlir (+14) 
- (added) flang/test/Fir/FIRToMemRef/derived-types.mlir (+31) 
- (added) flang/test/Fir/FIRToMemRef/index.mlir (+31) 
- (added) flang/test/Fir/FIRToMemRef/load-dynamic-shape.mlir (+130) 
- (added) flang/test/Fir/FIRToMemRef/load-shift-dynamic.mlir (+169) 
- (added) flang/test/Fir/FIRToMemRef/load-shift-static.mlir (+114) 
- (added) flang/test/Fir/FIRToMemRef/load-static-shape.mlir (+70) 
- (added) flang/test/Fir/FIRToMemRef/logical.mlir (+30) 
- (added) flang/test/Fir/FIRToMemRef/no-declare.mlir (+51) 
- (added) flang/test/Fir/FIRToMemRef/reject-conversions.mlir (+29) 
- (added) flang/test/Fir/FIRToMemRef/replace.mlir (+29) 
- (added) flang/test/Fir/FIRToMemRef/slice.mlir (+372) 
- (added) flang/test/Fir/FIRToMemRef/store-dynamic-shape.mlir (+129) 
- (added) flang/test/Fir/FIRToMemRef/store-shift-static.mlir (+118) 
- (added) flang/test/Fir/FIRToMemRef/store-static-shape.mlir (+75) 
- (added) flang/test/Fir/FIRToMemRef/tbaa-tag.mlir (+44) 
- (modified) flang/test/Fir/convert-memref-codegen.mlir (+25-4) 


``````````diff
diff --git a/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
new file mode 100644
index 0000000000000..d0907ecdd6160
--- /dev/null
+++ b/flang/include/flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h
@@ -0,0 +1,226 @@
+//===- FIRToMemRefTypeConverter.h - FIR type conversion to MemRef -*- C++
+//-*-==//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines `FIRToMemRefTypeConverter`, a helper used by the
+// FIR-to-MemRef conversion pass to convert FIR types (scalars, arrays,
+// descriptors) into MemRef types suitable for the MemRef dialect.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef FORTRAN_OPTIMIZER_TRANSFORMS_FIRTOMEMREFTYPECONVERTER_H
+#define FORTRAN_OPTIMIZER_TRANSFORMS_FIRTOMEMREFTYPECONVERTER_H
+
+#include "flang/Optimizer/Dialect/FIRDialect.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+namespace fir {
+
+class FIRToMemRefTypeConverter : public mlir::TypeConverter {
+private:
+  KindMapping kindMapping;
+  bool convertComplexTypes = false;
+  bool convertScalarTypesOnly = false;
+
+public:
+  explicit FIRToMemRefTypeConverter(mlir::ModuleOp mod)
+      : kindMapping(fir::getKindMapping(mod)) {
+    addConversion([](mlir::Type type) { return type; });
+
+    addConversion([&](fir::LogicalType type) -> mlir::Type {
+      return mlir::IntegerType::get(
+          type.getContext(), kindMapping.getLogicalBitsize(type.getFKind()));
+    });
+
+    addSourceMaterialization([](mlir::OpBuilder &builder, mlir::Type type,
+                                mlir::ValueRange inputs,
+                                mlir::Location loc) -> mlir::Value {
+      assert(!inputs.empty() && "expected a single input for materialization");
+      builder.setInsertionPointAfter(inputs[0].getDefiningOp());
+      return fir::ConvertOp::create(builder, loc, type, inputs[0]);
+    });
+
+    addTargetMaterialization([](mlir::OpBuilder &builder, mlir::Type type,
+                                mlir::ValueRange inputs,
+                                mlir::Location loc) -> mlir::Value {
+      return fir::ConvertOp::create(builder, loc, type, inputs[0]);
+    });
+  }
+
+  /// Control whether complex types are considered convertible.
+  void setConvertComplexTypes(bool value) { convertComplexTypes = value; }
+
+  /// Control whether only scalar types are considered during convertibleType.
+  void setConvertScalarTypesOnly(bool value) { convertScalarTypesOnly = value; }
+
+  /// Return true if the given FIR type can be converted to a MemRef-typed
+  /// descriptor (i.e. is a supported base element for MemRef marshaling).
+  bool convertibleMemrefType(mlir::Type ty) {
+    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(ty)) {
+      auto elTy = refTy.getElementType();
+      return convertibleMemrefType(elTy);
+    } else if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty)) {
+      auto elTy = pointerTy.getElementType();
+      return convertibleMemrefType(elTy);
+    } else if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty)) {
+      auto elTy = heapTy.getElementType();
+      return convertibleMemrefType(elTy);
+    } else if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) {
+      auto elTy = seqTy.getElementType();
+      return convertibleMemrefType(elTy);
+    } else if (auto boxTy = mlir::dyn_cast<fir::BoxType>(ty)) {
+      auto elTy = boxTy.getElementType();
+      return convertibleMemrefType(elTy);
+    }
+
+    setConvertScalarTypesOnly(true);
+    bool result = convertibleType(ty);
+    setConvertScalarTypesOnly(false);
+    return result;
+  }
+
+  /// Return true if the given FIR type represents an empty array (has a zero
+  /// extent in its shape).
+  bool isEmptyArray(mlir::Type ty) const {
+    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(ty)) {
+      auto elTy = refTy.getElementType();
+      return isEmptyArray(elTy);
+    } else if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(ty)) {
+      auto elTy = pointerTy.getElementType();
+      return isEmptyArray(elTy);
+    } else if (auto heapTy = mlir::dyn_cast<fir::HeapType>(ty)) {
+      auto elTy = heapTy.getElementType();
+      return isEmptyArray(elTy);
+    } else if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(ty)) {
+      llvm::ArrayRef<int64_t> firShape = seqTy.getShape();
+      for (auto shape : firShape) {
+        if (shape == 0)
+          return true;
+      }
+      return false;
+    }
+    return false;
+  }
+
+  /// Returns true if the given type can be converted according to the current
+  /// converter settings (scalar-only or full).
+  bool convertibleType(mlir::Type type) const {
+    if (!convertScalarTypesOnly) {
+      if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(type)) {
+        auto elTy = refTy.getElementType();
+        if (mlir::isa<fir::SequenceType>(elTy))
+          return false;
+        return convertibleType(elTy);
+      }
+
+      if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(type)) {
+        auto elTy = seqTy.getElementType();
+        return convertibleType(elTy);
+      }
+    }
+
+    if (fir::isa_fir_type(type)) {
+      if (mlir::isa<fir::LogicalType>(type))
+        return true;
+      return false;
+    }
+
+    if (type.isUnsignedInteger())
+      return false;
+
+    if (mlir::isa<mlir::ComplexType>(type))
+      return convertComplexTypes;
+
+    if (mlir::isa<mlir::FunctionType>(type))
+      return false;
+
+    if (mlir::isa<mlir::TupleType>(type))
+      return false;
+
+    return true;
+  }
+
+  /// Convert a FIR element / aggregate type to a MemRef descriptor type.
+  mlir::MemRefType convertMemrefType(mlir::Type firTy) const {
+    auto convertBaseType = [&](mlir::Type firTy) -> mlir::MemRefType {
+      if (auto charTy = mlir::dyn_cast<fir::CharacterType>(firTy)) {
+        unsigned kind = charTy.getFKind();
+        unsigned bitWidth = kindMapping.getCharacterBitsize(kind);
+        mlir::Type elTy = mlir::IntegerType::get(charTy.getContext(), bitWidth);
+
+        if (charTy.hasConstantLen() && charTy.getLen() == 1) {
+          return mlir::MemRefType::get({}, elTy);
+        } else if (charTy.hasConstantLen()) {
+          int64_t len = charTy.getLen();
+          return mlir::MemRefType::get({len}, elTy);
+        } else {
+          return mlir::MemRefType::get({mlir::ShapedType::kDynamic}, elTy);
+        }
+      }
+
+      if (auto seqTy = mlir::dyn_cast<fir::SequenceType>(firTy)) {
+        auto elTy = seqTy.getElementType();
+        mlir::Type ty = convertType(elTy);
+
+        llvm::ArrayRef<int64_t> firShape = seqTy.getShape();
+        llvm::SmallVector<int64_t> shape;
+        for (auto it = firShape.rbegin(); it != firShape.rend(); ++it)
+          shape.push_back(*it);
+
+        assert(mlir::BaseMemRefType::isValidElementType(ty) &&
+               "got invalid memref element type from array fir type");
+        return mlir::MemRefType::get(shape, ty);
+      }
+
+      mlir::Type ty = convertType(firTy);
+      assert(mlir::BaseMemRefType::isValidElementType(ty) &&
+             "got invalid memref element type from scalar fir type");
+      return mlir::MemRefType::get({}, ty);
+    };
+
+    if (auto refTy = mlir::dyn_cast<fir::ReferenceType>(firTy)) {
+      auto elTy = refTy.getElementType();
+      return convertBaseType(elTy);
+    }
+
+    if (auto pointerTy = mlir::dyn_cast<fir::PointerType>(firTy)) {
+      auto elTy = pointerTy.getElementType();
+      return convertBaseType(elTy);
+    }
+
+    if (auto heapTy = mlir::dyn_cast<fir::HeapType>(firTy)) {
+      auto elTy = heapTy.getElementType();
+      return convertBaseType(elTy);
+    }
+
+    if (auto boxTy = mlir::dyn_cast<fir::BoxType>(firTy)) {
+      auto elTy = boxTy.getElementType();
+
+      auto memRefTy = convertMemrefType(elTy);
+      mlir::MemRefType dynTy = mlir::MemRefType::Builder(memRefTy).setLayout(
+          mlir::StridedLayoutAttr::get(
+              memRefTy.getContext(), mlir::ShapedType::kDynamic,
+              llvm::SmallVector<int64_t>(memRefTy.getRank(),
+                                         mlir::ShapedType::kDynamic)));
+      return dynTy;
+    }
+
+    return convertBaseType(firTy);
+  }
+};
+
+} // namespace fir
+
+#endif // FORTRAN_OPTIMIZER_TRANSFORMS_FIRTOMEMREFTYPECONVERTER_H
diff --git a/flang/include/flang/Optimizer/Transforms/Passes.td b/flang/include/flang/Optimizer/Transforms/Passes.td
index f50202784e2dc..f52dae511ada1 100644
--- a/flang/include/flang/Optimizer/Transforms/Passes.td
+++ b/flang/include/flang/Optimizer/Transforms/Passes.td
@@ -215,6 +215,18 @@ def MemRefDataFlowOpt : Pass<"fir-memref-dataflow-opt", "::mlir::func::FuncOp">
   ];
 }
 
+def FIRToMemRef : Pass<"fir-to-memref", "::mlir::func::FuncOp"> {
+  let summary = "Convert FIR loads, stores, and descriptors to MemRef dialect";
+  let description = [{
+    Lower FIR memory operations (`fir.alloca`, `fir.load`, `fir.store`, 'fir.array_coor') to MLIR's MemRef core dialect.
+  }];
+  let dependentDialects = ["fir::FIROpsDialect", "mlir::arith::ArithDialect",
+                           "mlir::func::FuncDialect",
+                           "mlir::memref::MemRefDialect",
+                           "mlir::scf::SCFDialect", "mlir::omp::OpenMPDialect",
+                           "mlir::acc::OpenACCDialect"];
+}
+
 // This needs to be a "mlir::ModuleOp" pass, because we are creating debug for
 // the module in this pass.
 def AddDebugInfo : Pass<"add-debug-info", "mlir::ModuleOp"> {
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 55e885d46d351..c5aadb4beac55 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -39,6 +39,7 @@
 #include "mlir/Conversion/ControlFlowToLLVM/ControlFlowToLLVM.h"
 #include "mlir/Conversion/FuncToLLVM/ConvertFuncToLLVM.h"
 #include "mlir/Conversion/IndexToLLVM/IndexToLLVM.h"
+#include "mlir/Conversion/LLVMCommon/MemRefBuilder.h"
 #include "mlir/Conversion/LLVMCommon/Pattern.h"
 #include "mlir/Conversion/MathToFuncs/MathToFuncs.h"
 #include "mlir/Conversion/MathToLLVM/MathToLLVM.h"
@@ -817,13 +818,58 @@ struct ConvertOpConversion : public fir::FIROpConversion<fir::ConvertOp> {
     auto fromFirTy = convert.getValue().getType();
     auto toFirTy = convert.getRes().getType();
 
-    // Let more specialized conversions (e.g. FIR to memref
-    // converters) handle fir.convert when either side is a memref. This
-    // avoids interfering with descriptor-based flows such as fir.box /
-    // fir.box_addr and keeps this pattern focused on value conversions.
-    if (mlir::isa<mlir::MemRefType>(fromFirTy) ||
-        mlir::isa<mlir::MemRefType>(toFirTy))
-      return mlir::failure();
+    // Handle conversions between pointer-like values and memref descriptors.
+    // These are produced by FIR-to-MemRef lowering and represent descriptor
+    // marshaling rather than pure value conversions.
+    if (auto memRefTy = mlir::dyn_cast<mlir::MemRefType>(toFirTy)) {
+      mlir::Location loc = convert.getLoc();
+      mlir::Value basePtr = adaptor.getValue();
+      assert(basePtr && "null base pointer");
+
+      auto [strides, offset] = memRefTy.getStridesAndOffset();
+      bool hasStaticLayout =
+          mlir::ShapedType::isStatic(offset) &&
+          llvm::none_of(strides, mlir::ShapedType::isDynamic);
+
+      auto *firConv =
+          static_cast<const fir::LLVMTypeConverter *>(this->getTypeConverter());
+      assert(firConv && "expected non-null LLVMTypeConverter");
+
+      if (memRefTy.hasStaticShape() && hasStaticLayout) {
+        // Static shape and layout: build a fully-populated descriptor.
+        mlir::Value memrefDesc = mlir::MemRefDescriptor::fromStaticShape(
+            rewriter, loc, *firConv, memRefTy, basePtr);
+        rewriter.replaceOp(convert, memrefDesc);
+        return mlir::success();
+      }
+
+      // Dynamic shape or layout: create an LLVM memref descriptor and insert
+      // the base pointer field, letting the rest of the fields be populated
+      // by subsequent lowering.
+      mlir::Type llvmMemRefTy = firConv->convertType(memRefTy);
+      auto undef = mlir::LLVM::UndefOp::create(rewriter, loc, llvmMemRefTy);
+      auto insert =
+          mlir::LLVM::InsertValueOp::create(rewriter, loc, undef, basePtr, 1);
+      rewriter.replaceOp(convert, insert);
+      return mlir::success();
+    }
+
+    if (auto memRefTy = mlir::dyn_cast<mlir::MemRefType>(fromFirTy)) {
+      // Legalize conversions *from* memref descriptors to pointer-like values
+      // by extracting the underlying buffer pointer from the descriptor.
+      mlir::Location loc = convert.getLoc();
+      mlir::Value base = adaptor.getValue();
+      auto alignedPtr =
+          mlir::LLVM::ExtractValueOp::create(rewriter, loc, base, 1);
+      auto offset = mlir::LLVM::ExtractValueOp::create(rewriter, loc, base, 2);
+      mlir::Type elementType =
+          this->getTypeConverter()->convertType(memRefTy.getElementType());
+      auto gepOp = mlir::LLVM::GEPOp::create(rewriter, loc,
+                                             alignedPtr.getType(), elementType,
+                                             alignedPtr, offset.getResult());
+      rewriter.replaceOp(convert, gepOp);
+      return mlir::success();
+    }
 
     auto fromTy = convertType(fromFirTy);
     auto toTy = convertType(toFirTy);
diff --git a/flang/lib/Optimizer/Transforms/CMakeLists.txt b/flang/lib/Optimizer/Transforms/CMakeLists.txt
index 619f3adc67c85..b8bab68328555 100644
--- a/flang/lib/Optimizer/Transforms/CMakeLists.txt
+++ b/flang/lib/Optimizer/Transforms/CMakeLists.txt
@@ -18,6 +18,7 @@ add_flang_library(FIRTransforms
   ArrayValueCopy.cpp
   ExternalNameConversion.cpp
   FIRToSCF.cpp
+  FIRToMemRef.cpp
   MemoryUtils.cpp
   MemoryAllocation.cpp
   StackArrays.cpp
diff --git a/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
new file mode 100644
index 0000000000000..c79425c8a21d2
--- /dev/null
+++ b/flang/lib/Optimizer/Transforms/FIRToMemRef.cpp
@@ -0,0 +1,1171 @@
+//===-- FIRToMemRef.cpp - Convert FIR loads and stores to MemRef ---------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This pass lowers FIR dialect memory operations to the MemRef dialect.
+// It is adapted from the NVHPC FIRToMemRef implementation so that it can
+// be used as a regular flang/MLIR transform pass.
+//
+// In particular it:
+//
+//  - Rewrites `fir.alloca` to `memref.alloca`.
+//
+//  - Rewrites `fir.load` / `fir.store` to `memref.load` / `memref.store`.
+//
+//  - Marshals FIR reference-like values (boxes, array coordinates,
+//    embox/rebox, and optionals) into MemRef descriptors by introducing
+//    `fir.convert` at use sites. For example:
+//
+//        %fir_ref = ... : !fir.ref<!fir.array<...>>
+//        %memref = fir.convert %fir_ref : !fir.ref<!fir.array<...>> ->
+//        memref<...> %val = memref.load %memref[...] : memref<...> fir.call
+//        @callee(%fir_ref) : (!fir.ref<!fir.array<...>>) -> ()
+//
+//    Here the MemRef-typed value is used for `memref.load`, while the original
+//    FIR-typed value is preserved for `fir.call`.
+//
+//  - Computes shapes, strides, and indices as needed for slices and shifts
+//    and emits `memref.reinterpret_cast` when dynamic layout is required.
+//
+//===----------------------------------------------------------------------===//
+
+#include "flang/Optimizer/Transforms/FIRToMemRefTypeConverter.h"
+#include "flang/Optimizer/Transforms/Passes.h"
+
+#include "flang/Optimizer/Builder/CUFCommon.h"
+#include "flang/Optimizer/Dialect/FIROps.h"
+#include "flang/Optimizer/Dialect/FIROpsSupport.h"
+#include "flang/Optimizer/Dialect/FIRType.h"
+#include "flang/Optimizer/Dialect/Support/FIRContext.h"
+#include "flang/Optimizer/Dialect/Support/KindMapping.h"
+
+#include "mlir/Dialect/Arith/IR/Arith.h"
+#include "mlir/Dialect/Func/IR/FuncOps.h"
+#include "mlir/Dialect/MemRef/IR/MemRef.h"
+#include "mlir/Dialect/OpenACC/OpenACC.h"
+#include "mlir/Dialect/OpenMP/OpenMPDialect.h"
+#include "mlir/Dialect/SCF/IR/SCF.h"
+#include "mlir/IR/Block.h"
+#include "mlir/IR/Builders.h"
+#include "mlir/IR/BuiltinAttributes.h"
+#include "mlir/IR/BuiltinTypes.h"
+#include "mlir/IR/Dominance.h"
+#include "mlir/IR/Location.h"
+#include "mlir/IR/MLIRContext.h"
+#include "mlir/IR/Operation.h"
+#include "mlir/IR/PatternMatch.h"
+#include "mlir/IR/Region.h"
+#include "mlir/IR/Value.h"
+#include "mlir/IR/ValueRange.h"
+#include "mlir/IR/Verifier.h"
+#include "mlir/Pass/Pass.h"
+#include "mlir/Support/LLVM.h"
+#include "mlir/Transforms/DialectConversion.h"
+
+#include "llvm/ADT/SetVector.h"
+#include "llvm/ADT/SmallPtrSet.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/CommandLine.h"
+#include "llvm/Support/Debug.h"
+#include "llvm/Support/ErrorHandling.h"
+
+#define DEBUG_TYPE "fir-to-memref"
+
+using namespace mlir;
+
+namespace fir {
+
+#define GEN_PASS_DEF_FIRTOMEMREF
+#include "flang/Optimizer/Transforms/Passes.h.inc"
+
+static bool isMarshalLike(Operation *op) {
+  if (!op)
+    return false;
+
+  auto convert = dyn_cast<fir::ConvertOp>(op);
+  if (!convert)
+    return false;
+
+  bool resIsMemRef = isa<MemRefType>(convert.getType());
+  bool argIsMemRef = isa<MemRefType>(convert.getValue().getType());
+
+  assert(!(resIsMemRef && argIsMemRef) &&
+         "unexpected fir.convert memref -> memref in isMarshalLike");
+
+  return resIsMemRef || argIsMemRef;
+}
+
+using MemRefInfo = FailureOr<std::pair<Value, SmallVector<Value>>>;
+
+static llvm::cl::opt<bool> enableFIRConvertOptimizations(
+    "enable-fir-convert-opts",
+    llvm::cl::desc("enable emilinating redundant fir.convert in FIR-to-MemRef"),
+    llvm::cl::init(false), llvm::cl::Hidden);
+
+class FIRToMemRef : public fir::impl::FIRToMemRefBase<FIRToMemRef> {
+public:
+  void runOnOperation() override;
+
+private:
+  llvm::SmallSetVector<Operation *, 32> eraseOps;
+
+  DominanceInfo *domInfo = nullptr;
+
+  void rewriteAlloca(fir::AllocaOp, PatternRewriter &,
+                     FIRToMemRefTypeConverter &);
+
+  void rewriteLoadOp(fir::LoadOp, PatternRewriter &,
+                     FIRToMemRefTypeConverter &);
+
+  void rewriteStoreOp(fir::StoreOp, PatternRewriter &,
+                      FIRToMemRefTypeConverter &);
+
+  MemRefInfo getMemRefInfo(Value, PatternRewriter &, FIRToMemRefTypeConverter &,
+                           Operation *);
+
+  MemRefInfo marshalArrayCoorOp(Operation *memOp, fir::ArrayCoorOp,
+                                PatternRewriter &, FIRToMemRefTypeConverter &);
+
+  void replaceFIRMemrefs(Value, Value, PatternRewriter &) const;
+
+  FailureOr<Value> getFIRMarshal(Operation *memOp, Operation *memref,
+                                 PatternRewriter &, FIRToMemRefTypeConverter &);
+
+  FailureOr<SmallVector<Value>> getMemrefIndices(fir::ArrayCoorOp, Operation *,
+                                                 PatternRewriter &, Value,
+                                                 Value) const;
+
+  bool memrefIsOptional(Operation *) const;
+
+  Value canonicalizeIndex(Value, PatternRewriter &) const;
+
+  template <typename OpTy>
+  void getShapeFrom(OpTy op, SmallVector<Value> &shapeVec,
+                    SmallVector<Value> &shiftVec,
+                    SmallVector<Value> &sliceVec) const;
+
+  void populateShapeAndShift(SmallVectorImpl<Value> &shapeVec,
+                             SmallVectorImpl<Value> &shiftVec,
+                             fir::Sha...
[truncated]

``````````

</details>


https://github.com/llvm/llvm-project/pull/173507


More information about the flang-commits mailing list