[flang-commits] [flang] [flang] Register memref-to-llvm patterns in FIRToLLVMLowering (PR #234305)

via flang-commits flang-commits at lists.llvm.org
Thu Oct 22 11:54:37 PDT 2026


https://github.com/jon-gibney updated https://github.com/llvm/llvm-project/pull/234305

>From 558e75dd4b7572fa903ecd8927b19fdc2504f211 Mon Sep 17 00:00:00 2001
From: Jon Gibney <jonathon.gibney at hpe.com>
Date: Wed, 21 Oct 2026 13:09:39 -0500
Subject: [PATCH 1/3] [flang] Register memref-to-llvm patterns in
 FIRToLLVMLowering With   fir-opt --fir-to-scf --fir-to-memref   mlir-opt
 --raise-scf-to-affine --affine-raise-from-memref we can get from FIR to
 affine and do restructuring in that form. However, doing   fir-opt
 --lower-affine leaves memref ops that   fir-opt --fir-to-llvm-ir couldn't
 legalize, as mentioned in  
 https://discourse.llvm.org/t/flang-affine-linearized-array-access-in-promote-to-affine-causes-false-dependence-and-blocks-loop-tiling/89927/7

This adds the memref-to-llvm patterns to FIRToLLVMLowering to fix
that.
---
 flang/lib/Optimizer/CodeGen/CMakeLists.txt |  1 +
 flang/lib/Optimizer/CodeGen/CodeGen.cpp    |  3 ++
 flang/test/Fir/memref-ops-codegen.mlir     | 50 ++++++++++++++++++++++
 3 files changed, 54 insertions(+)
 create mode 100644 flang/test/Fir/memref-ops-codegen.mlir

diff --git a/flang/lib/Optimizer/CodeGen/CMakeLists.txt b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
index c3cb3ca4b3ebfd..0ed85c1cc79880 100644
--- a/flang/lib/Optimizer/CodeGen/CMakeLists.txt
+++ b/flang/lib/Optimizer/CodeGen/CMakeLists.txt
@@ -44,6 +44,7 @@ add_flang_library(FIRCodeGen
   MLIRMathToLibm
   MLIRMathToNVVM
   MLIRMathToROCDL
+  MLIRMemRefToLLVM
   MLIROpenMPToLLVMConversion
   MLIROpenACCDialect
   MLIRBuiltinToLLVMIRTranslation
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index d0f522a1754727..17816af26e4bd5 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -49,6 +49,7 @@
 #include "mlir/Conversion/MathToLibm/MathToLibm.h"
 #include "mlir/Conversion/MathToNVVM/MathToNVVM.h"
 #include "mlir/Conversion/MathToROCDL/MathToROCDL.h"
+#include "mlir/Conversion/MemRefToLLVM/MemRefToLLVM.h"
 #include "mlir/Conversion/OpenMPToLLVM/ConvertOpenMPToLLVM.h"
 #include "mlir/Conversion/UBToLLVM/UBToLLVM.h"
 #include "mlir/Conversion/VectorToLLVM/ConvertVectorToLLVM.h"
@@ -5278,6 +5279,8 @@ class FIRToLLVMLowering
     mlir::index::populateIndexToLLVMConversionPatterns(typeConverter, pattern);
     mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
     mlir::ub::populateUBToLLVMConversionPatterns(typeConverter, pattern);
+    mlir::populateFinalizeMemRefToLLVMConversionPatterns(typeConverter,
+                                                         pattern);
 
     // Flang specific overloads for OpenMP operations, to allow for special
     // handling of things like Box types.
diff --git a/flang/test/Fir/memref-ops-codegen.mlir b/flang/test/Fir/memref-ops-codegen.mlir
new file mode 100644
index 00000000000000..cd2367143ea7f2
--- /dev/null
+++ b/flang/test/Fir/memref-ops-codegen.mlir
@@ -0,0 +1,50 @@
+// RUN: fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" --split-input-file %s | FileCheck %s
+
+// Test that memref dialect operations, as produced by fir-to-memref and
+// lower-affine, are lowered together with the fir.convert ops that bridge
+// !fir.ref and memref values.
+
+// CHECK-LABEL: llvm.func @load_scalar(
+// CHECK-SAME:    %[[ARG0:.*]]: !llvm.ptr) -> i32 {
+// CHECK:         %[[ALIGNED:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64)>
+// CHECK:         %[[VAL:.*]] = llvm.load %[[ALIGNED]] : !llvm.ptr -> i32
+// CHECK:         llvm.return %[[VAL]] : i32
+// CHECK-NOT:     memref.
+func.func @load_scalar(%arg0: !fir.ref<i32>) -> i32 {
+  %0 = fir.convert %arg0 : (!fir.ref<i32>) -> memref<i32>
+  %1 = memref.load %0[] : memref<i32>
+  return %1 : i32
+}
+
+// -----
+
+// CHECK-LABEL: llvm.func @store_scalar(
+// CHECK-SAME:    %[[ARG0:.*]]: !llvm.ptr, %[[VAL:.*]]: f32) {
+// CHECK:         %[[ALIGNED:.*]] = llvm.extractvalue %{{.*}}[1] : !llvm.struct<(ptr, ptr, i64)>
+// CHECK:         llvm.store %[[VAL]], %[[ALIGNED]] : f32, !llvm.ptr
+// CHECK-NOT:     memref.
+func.func @store_scalar(%arg0: !fir.ref<f32>, %arg1: f32) {
+  %0 = fir.convert %arg0 : (!fir.ref<f32>) -> memref<f32>
+  memref.store %arg1, %0[] : memref<f32>
+  return
+}
+
+// -----
+
+// CHECK-LABEL: llvm.func @load_store_static_2d(
+// CHECK-SAME:    %[[ARG0:.*]]: !llvm.ptr, %[[I:.*]]: i64, %[[J:.*]]: i64) {
+// CHECK:         %[[MUL0:.*]] = llvm.mul %[[I]], %{{.*}}
+// CHECK:         %[[ADD0:.*]] = llvm.add %[[MUL0]], %[[J]]
+// CHECK:         %[[SRC:.*]] = llvm.getelementptr {{.*}}[%[[ADD0]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
+// CHECK:         %[[VAL:.*]] = llvm.load %[[SRC]] : !llvm.ptr -> f32
+// CHECK:         %[[MUL1:.*]] = llvm.mul %[[J]], %{{.*}}
+// CHECK:         %[[ADD1:.*]] = llvm.add %[[MUL1]], %[[I]]
+// CHECK:         %[[DST:.*]] = llvm.getelementptr {{.*}}[%[[ADD1]]] : (!llvm.ptr, i64) -> !llvm.ptr, f32
+// CHECK:         llvm.store %[[VAL]], %[[DST]] : f32, !llvm.ptr
+// CHECK-NOT:     memref.
+func.func @load_store_static_2d(%arg0: !fir.ref<!fir.array<4x8xf32>>, %i: index, %j: index) {
+  %0 = fir.convert %arg0 : (!fir.ref<!fir.array<4x8xf32>>) -> memref<4x8xf32>
+  %1 = memref.load %0[%i, %j] : memref<4x8xf32>
+  memref.store %1, %0[%j, %i] : memref<4x8xf32>
+  return
+}

>From 27802bfeca24f7e40a7e29146c9c751a5c07624f Mon Sep 17 00:00:00 2001
From: Jon Gibney <jonathon.gibney at hpe.com>
Date: Thu, 22 Oct 2026 13:28:16 -0500
Subject: [PATCH 2/3] Pass the symbol table

---
 flang/lib/Optimizer/CodeGen/CodeGen.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 17816af26e4bd5..3d1e7602537098 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -5279,8 +5279,8 @@ class FIRToLLVMLowering
     mlir::index::populateIndexToLLVMConversionPatterns(typeConverter, pattern);
     mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
     mlir::ub::populateUBToLLVMConversionPatterns(typeConverter, pattern);
-    mlir::populateFinalizeMemRefToLLVMConversionPatterns(typeConverter,
-                                                         pattern);
+    mlir::populateFinalizeMemRefToLLVMConversionPatterns(typeConverter, pattern,
+                                                         &symbolTables);
 
     // Flang specific overloads for OpenMP operations, to allow for special
     // handling of things like Box types.

>From c49e081aa54a64e3b37ddcd7444e2dba6e676c07 Mon Sep 17 00:00:00 2001
From: Jon Gibney <jonathon.gibney at hpe.com>
Date: Thu, 22 Oct 2026 13:53:17 -0500
Subject: [PATCH 3/3] Put under an option

---
 flang/include/flang/Optimizer/CodeGen/CGPasses.td | 4 +++-
 flang/lib/Optimizer/CodeGen/CodeGen.cpp           | 5 +++--
 flang/test/Fir/memref-ops-codegen.mlir            | 7 +++++--
 3 files changed, 11 insertions(+), 5 deletions(-)

diff --git a/flang/include/flang/Optimizer/CodeGen/CGPasses.td b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
index 6f0ae6588c2de4..ac16f4111630e2 100644
--- a/flang/include/flang/Optimizer/CodeGen/CGPasses.td
+++ b/flang/include/flang/Optimizer/CodeGen/CGPasses.td
@@ -51,7 +51,9 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> {
            "allocations marked with the unified heap allocation mode.">,
     Option<"managedHeapAllocSuffix", "managed-heap-alloc-suffix", "std::string",
            /*default=*/"", "Suffix of the allocator entry points used for "
-           "allocations marked with the managed heap allocation mode.">
+           "allocations marked with the managed heap allocation mode.">,
+    Option<"lowerMemRef", "lower-memref", "bool", /*default=*/"false",
+           "Also convert memref dialect operations.">
   ];
 }
 
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 3d1e7602537098..aab69a619d4cfe 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -5279,8 +5279,9 @@ class FIRToLLVMLowering
     mlir::index::populateIndexToLLVMConversionPatterns(typeConverter, pattern);
     mlir::populateVectorToLLVMConversionPatterns(typeConverter, pattern);
     mlir::ub::populateUBToLLVMConversionPatterns(typeConverter, pattern);
-    mlir::populateFinalizeMemRefToLLVMConversionPatterns(typeConverter, pattern,
-                                                         &symbolTables);
+    if (lowerMemRef)
+      mlir::populateFinalizeMemRefToLLVMConversionPatterns(
+          typeConverter, pattern, &symbolTables);
 
     // Flang specific overloads for OpenMP operations, to allow for special
     // handling of things like Box types.
diff --git a/flang/test/Fir/memref-ops-codegen.mlir b/flang/test/Fir/memref-ops-codegen.mlir
index cd2367143ea7f2..e4d803a8df3b02 100644
--- a/flang/test/Fir/memref-ops-codegen.mlir
+++ b/flang/test/Fir/memref-ops-codegen.mlir
@@ -1,8 +1,11 @@
-// RUN: fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" --split-input-file %s | FileCheck %s
+// RUN: fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu lower-memref=true" --split-input-file %s | FileCheck %s
+// RUN: not fir-opt --fir-to-llvm-ir="target=x86_64-unknown-linux-gnu" --split-input-file %s 2>&1 | FileCheck %s --check-prefix=DISABLED
 
 // Test that memref dialect operations, as produced by fir-to-memref and
 // lower-affine, are lowered together with the fir.convert ops that bridge
-// !fir.ref and memref values.
+// !fir.ref and memref values when lower-memref is enabled.
+
+// DISABLED: failed to legalize operation 'memref.load'
 
 // CHECK-LABEL: llvm.func @load_scalar(
 // CHECK-SAME:    %[[ARG0:.*]]: !llvm.ptr) -> i32 {



More information about the flang-commits mailing list