Skip to content

Conversation

@razvanlupusoru
Copy link
Contributor

This patch extends the OpenACC PointerLikeType interface with two new methods for generating load and store operations, enabling dialect-agnostic memory access patterns.

New Interface Methods:

  • genLoad(builder, loc, srcPtr, valueType): Generates a load operation from a pointer-like value. Returns the loaded value.

  • genStore(builder, loc, valueToStore, destPtr): Generates a store operation to a pointer-like value.

Implementations provided for FIR pointer-like types, memref type (rank-0 only), and LLVM pointer types.

Extended TestPointerLikeTypeInterface.cpp with 'load' and 'store' test modes.

This patch extends the OpenACC PointerLikeType interface with
two new methods for generating load and store operations,
enabling dialect-agnostic memory access patterns.

New Interface Methods:
- genLoad(builder, loc, srcPtr, valueType): Generates a load
  operation from a pointer-like value. Returns the loaded
  value.

- genStore(builder, loc, valueToStore, destPtr): Generates a
  store operation to a pointer-like value.

Implementations provided for FIR pointer-like types, memref
type (rank-0 only), and LLVM pointer types.

Extended TestPointerLikeTypeInterface.cpp with 'load' and
'store' test modes.
@llvmbot
Copy link
Member

llvmbot commented Dec 2, 2025

@llvm/pr-subscribers-mlir
@llvm/pr-subscribers-openacc

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

Author: Razvan Lupusoru (razvanlupusoru)

Changes

This patch extends the OpenACC PointerLikeType interface with two new methods for generating load and store operations, enabling dialect-agnostic memory access patterns.

New Interface Methods:

  • genLoad(builder, loc, srcPtr, valueType): Generates a load operation from a pointer-like value. Returns the loaded value.

  • genStore(builder, loc, valueToStore, destPtr): Generates a store operation to a pointer-like value.

Implementations provided for FIR pointer-like types, memref type (rank-0 only), and LLVM pointer types.

Extended TestPointerLikeTypeInterface.cpp with 'load' and 'store' test modes.


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

9 Files Affected:

  • (modified) flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h (+9)
  • (modified) flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp (+112)
  • (added) flang/test/Fir/OpenACC/pointer-like-interface-load.mlir (+85)
  • (added) flang/test/Fir/OpenACC/pointer-like-interface-store.mlir (+75)
  • (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td (+44)
  • (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+56)
  • (added) mlir/test/Dialect/OpenACC/pointer-like-interface-load.mlir (+29)
  • (added) mlir/test/Dialect/OpenACC/pointer-like-interface-store.mlir (+39)
  • (modified) mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp (+107-2)
diff --git a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
index 3167c554abbdd..38150b294f4e1 100644
--- a/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
+++ b/flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h
@@ -43,6 +43,15 @@ struct OpenACCPointerLikeModel
                mlir::TypedValue<mlir::acc::PointerLikeType> destination,
                mlir::TypedValue<mlir::acc::PointerLikeType> source,
                mlir::Type varType) const;
+
+  mlir::Value genLoad(mlir::Type pointer, mlir::OpBuilder &builder,
+                      mlir::Location loc,
+                      mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+                      mlir::Type valueType) const;
+
+  bool genStore(mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+                mlir::Value valueToStore,
+                mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
 };
 
 template <typename T>
diff --git a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
index ae0f5fb8197fa..a6109c3a04010 100644
--- a/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
+++ b/flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
@@ -1014,4 +1014,116 @@ template bool OpenACCPointerLikeModel<fir::LLVMPointerType>::genCopy(
     mlir::TypedValue<mlir::acc::PointerLikeType> source,
     mlir::Type varType) const;
 
+template <typename Ty>
+mlir::Value OpenACCPointerLikeModel<Ty>::genLoad(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+    mlir::Type valueType) const {
+
+  // Unwrap to get the pointee type.
+  mlir::Type pointeeTy = fir::dyn_cast_ptrEleTy(pointer);
+  assert(pointeeTy && "expected pointee type to be extractable");
+
+  // Box types contain both a descriptor and referenced data. The genLoad API
+  // handles simple loads and cannot properly manage both parts.
+  if (fir::isa_box_type(pointeeTy))
+    return {};
+
+  // Unlimited polymorphic (class(*)) cannot be handled because type is unknown.
+  if (fir::isUnlimitedPolymorphicType(pointeeTy))
+    return {};
+
+  // Return empty for dynamic size types because the load logic
+  // cannot be determined simply from the type.
+  if (fir::hasDynamicSize(pointeeTy))
+    return {};
+
+  mlir::Value loadedValue = fir::LoadOp::create(builder, loc, srcPtr);
+
+  // If valueType is provided and differs from the loaded type, insert a convert
+  if (valueType && loadedValue.getType() != valueType) {
+    return fir::ConvertOp::create(builder, loc, valueType, loadedValue);
+  }
+
+  return loadedValue;
+}
+
+template mlir::Value OpenACCPointerLikeModel<fir::ReferenceType>::genLoad(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+    mlir::Type valueType) const;
+
+template mlir::Value OpenACCPointerLikeModel<fir::PointerType>::genLoad(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+    mlir::Type valueType) const;
+
+template mlir::Value OpenACCPointerLikeModel<fir::HeapType>::genLoad(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+    mlir::Type valueType) const;
+
+template mlir::Value OpenACCPointerLikeModel<fir::LLVMPointerType>::genLoad(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
+    mlir::Type valueType) const;
+
+template <typename Ty>
+bool OpenACCPointerLikeModel<Ty>::genStore(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::Value valueToStore,
+    mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const {
+
+  // Unwrap to get the pointee type.
+  mlir::Type pointeeTy = fir::dyn_cast_ptrEleTy(pointer);
+  assert(pointeeTy && "expected pointee type to be extractable");
+
+  // Box types contain both a descriptor and referenced data. The genStore API
+  // handles simple stores and cannot properly manage both parts.
+  if (fir::isa_box_type(pointeeTy))
+    return false;
+
+  // Unlimited polymorphic (class(*)) cannot be handled because type is unknown.
+  if (fir::isUnlimitedPolymorphicType(pointeeTy))
+    return false;
+
+  // Return false for dynamic size types because the store logic
+  // cannot be determined simply from the type.
+  if (fir::hasDynamicSize(pointeeTy))
+    return false;
+
+  // Get the type from the value being stored
+  mlir::Type valueType = valueToStore.getType();
+  mlir::Value convertedValue = valueToStore;
+
+  // If the value type differs from the pointee type, insert a convert
+  if (valueType != pointeeTy) {
+    convertedValue =
+        fir::ConvertOp::create(builder, loc, pointeeTy, valueToStore);
+  }
+
+  fir::StoreOp::create(builder, loc, convertedValue, destPtr);
+  return true;
+}
+
+template bool OpenACCPointerLikeModel<fir::ReferenceType>::genStore(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::Value valueToStore,
+    mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
+
+template bool OpenACCPointerLikeModel<fir::PointerType>::genStore(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::Value valueToStore,
+    mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
+
+template bool OpenACCPointerLikeModel<fir::HeapType>::genStore(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::Value valueToStore,
+    mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
+
+template bool OpenACCPointerLikeModel<fir::LLVMPointerType>::genStore(
+    mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
+    mlir::Value valueToStore,
+    mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
+
 } // namespace fir::acc
diff --git a/flang/test/Fir/OpenACC/pointer-like-interface-load.mlir b/flang/test/Fir/OpenACC/pointer-like-interface-load.mlir
new file mode 100644
index 0000000000000..79a944280445f
--- /dev/null
+++ b/flang/test/Fir/OpenACC/pointer-like-interface-load.mlir
@@ -0,0 +1,85 @@
+// RUN: fir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=load}))" 2>&1 | FileCheck %s
+
+func.func @test_load_scalar_f32() {
+  %ptr = fir.alloca f32 {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca f32 {test.ptr}
+  // CHECK: Loaded value type: f32
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<f32>
+  return
+}
+
+// -----
+
+func.func @test_load_scalar_i32() {
+  %ptr = fir.alloca i32 {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca i32 {test.ptr}
+  // CHECK: Loaded value type: i32
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<i32>
+  return
+}
+
+// -----
+
+func.func @test_load_scalar_i64() {
+  %ptr = fir.alloca i64 {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca i64 {test.ptr}
+  // CHECK: Loaded value type: i64
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<i64>
+  return
+}
+
+// -----
+
+func.func @test_load_heap_scalar() {
+  %ptr = fir.allocmem f64 {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.allocmem f64 {test.ptr}
+  // CHECK: Loaded value type: f64
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.heap<f64>
+  return
+}
+
+// -----
+
+func.func @test_load_logical() {
+  %ptr = fir.alloca !fir.logical<4> {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca !fir.logical<4> {test.ptr}
+  // CHECK: Loaded value type: !fir.logical<4>
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<!fir.logical<4>>
+  return
+}
+
+// -----
+
+func.func @test_load_derived_type() {
+  %ptr = fir.alloca !fir.type<_QTt{i:i32}> {test.ptr}
+  // CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca !fir.type<_QTt{i:i32}> {test.ptr}
+  // CHECK: Loaded value type: !fir.type<_QTt{i:i32}>
+  // CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<!fir.type<_QTt{i:i32}>>
+  return
+}
+
+// -----
+
+func.func @test_load_dynamic_array_fails() {
+  %c10 = arith.constant 10 : index
+  %ptr = fir.alloca !fir.array<?xf32>, %c10 {test.ptr}
+  // CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.array<?xf32>
+  return
+}
+
+// -----
+
+func.func @test_load_box_fails() {
+  %ptr = fir.alloca !fir.box<!fir.ptr<f32>> {test.ptr}
+  // CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.box<!fir.ptr<f32>>
+  return
+}
+
+// -----
+
+func.func @test_load_unlimited_polymorphic_fails() {
+  %ptr = fir.alloca !fir.class<none> {test.ptr}
+  // CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.class<none>
+  return
+}
+
diff --git a/flang/test/Fir/OpenACC/pointer-like-interface-store.mlir b/flang/test/Fir/OpenACC/pointer-like-interface-store.mlir
new file mode 100644
index 0000000000000..6306bf1cf6cee
--- /dev/null
+++ b/flang/test/Fir/OpenACC/pointer-like-interface-store.mlir
@@ -0,0 +1,75 @@
+// RUN: fir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=store}))" 2>&1 | FileCheck %s
+
+func.func @test_store_scalar_f32() {
+  %ptr = fir.alloca f32 {test.ptr}
+  // CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca f32 {test.ptr}
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 4.200000e+01 : f32
+  // CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<f32>
+  return
+}
+
+// -----
+
+func.func @test_store_scalar_i32() {
+  %ptr = fir.alloca i32 {test.ptr}
+  // CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i32 {test.ptr}
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i32
+  // CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i32>
+  return
+}
+
+// -----
+
+func.func @test_store_scalar_i64() {
+  %ptr = fir.alloca i64 {test.ptr}
+  // CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i64 {test.ptr}
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i64
+  // CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i64>
+  return
+}
+
+// -----
+
+func.func @test_store_heap_scalar() {
+  %ptr = fir.allocmem f64 {test.ptr}
+  // CHECK: Successfully generated store for operation: %{{.*}} = fir.allocmem f64 {test.ptr}
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 4.200000e+01 : f64
+  // CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.heap<f64>
+  return
+}
+
+// -----
+
+func.func @test_store_with_type_conversion() {
+  %ptr = fir.alloca i32 {test.ptr}
+  // CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i32 {test.ptr}
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i32
+  // CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i32>
+  return
+}
+
+// -----
+
+func.func @test_store_dynamic_array_fails() {
+  %c10 = arith.constant 10 : index
+  %ptr = fir.alloca !fir.array<?xf32>, %c10 {test.ptr}
+  // CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.array<?xf32>
+  return
+}
+
+// -----
+
+func.func @test_store_box_fails() {
+  %ptr = fir.alloca !fir.box<!fir.ptr<f32>> {test.ptr}
+  // CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.box<!fir.ptr<f32>>
+  return
+}
+
+// -----
+
+func.func @test_store_unlimited_polymorphic_fails() {
+  %ptr = fir.alloca !fir.class<none> {test.ptr}
+  // CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.class<none>
+  return
+}
+
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
index d1bbc7f206ce6..3f11bf6fbfce3 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
@@ -176,6 +176,50 @@ def OpenACC_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> {
         return false;
       }]
     >,
+    InterfaceMethod<
+      /*description=*/[{
+        Generates a load operation from the pointer-like type. This dereferences
+        the pointer and returns the loaded value.
+
+        The `srcPtr` parameter is the pointer to load from. If the current type is
+        represented in a way that it does not capture the pointee type, `valueType`
+        must be passed in to provide the necessary type information.
+
+        Returns the loaded value, or an empty Value if load generation failed.
+      }],
+      /*retTy=*/"::mlir::Value",
+      /*methodName=*/"genLoad",
+      /*args=*/(ins "::mlir::OpBuilder &":$builder,
+                    "::mlir::Location":$loc,
+                    "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$srcPtr,
+                    "::mlir::Type":$valueType),
+      /*methodBody=*/"",
+      /*defaultImplementation=*/[{
+        return {};
+      }]
+    >,
+    InterfaceMethod<
+      /*description=*/[{
+        Generates a store operation to the pointer-like type. This stores a value
+        to the memory location pointed to by the pointer.
+
+        The `destPtr` parameter is the pointer to store to. The `valueToStore`
+        parameter is the value to be stored. The type information is derived from
+        the valueToStore parameter itself.
+
+        Returns true if store was successfully generated, false otherwise.
+      }],
+      /*retTy=*/"bool",
+      /*methodName=*/"genStore",
+      /*args=*/(ins "::mlir::OpBuilder &":$builder,
+                    "::mlir::Location":$loc,
+                    "::mlir::Value":$valueToStore,
+                    "::mlir::TypedValue<::mlir::acc::PointerLikeType>":$destPtr),
+      /*methodBody=*/"",
+      /*defaultImplementation=*/[{
+        return false;
+      }]
+    >,
   ];
 }
 
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index 841d1d781f1a1..3369cc7a3535b 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -203,12 +203,68 @@ struct MemRefPointerLikeModel
 
     return false;
   }
+
+  mlir::Value genLoad(Type pointer, OpBuilder &builder, Location loc,
+                      TypedValue<PointerLikeType> srcPtr,
+                      Type valueType) const {
+    // Load from a memref - only valid for scalar memrefs (rank 0).
+    // This is because the address computation for memrefs is part of the load
+    // (and not computed separately), but the API does not have arguments for
+    // indexing.
+    auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(srcPtr);
+    if (!memrefValue)
+      return {};
+
+    auto memrefTy = memrefValue.getType();
+
+    // Only load from scalar memrefs (rank 0)
+    if (memrefTy.getRank() != 0)
+      return {};
+
+    return memref::LoadOp::create(builder, loc, memrefValue);
+  }
+
+  bool genStore(Type pointer, OpBuilder &builder, Location loc,
+                Value valueToStore, TypedValue<PointerLikeType> destPtr) const {
+    // Store to a memref - only valid for scalar memrefs (rank 0)
+    // This is because the address computation for memrefs is part of the store
+    // (and not computed separately), but the API does not have arguments for
+    // indexing.
+    auto memrefValue = dyn_cast_if_present<TypedValue<MemRefType>>(destPtr);
+    if (!memrefValue)
+      return false;
+
+    auto memrefTy = memrefValue.getType();
+
+    // Only store to scalar memrefs (rank 0)
+    if (memrefTy.getRank() != 0)
+      return false;
+
+    memref::StoreOp::create(builder, loc, valueToStore, memrefValue);
+    return true;
+  }
 };
 
 struct LLVMPointerPointerLikeModel
     : public PointerLikeType::ExternalModel<LLVMPointerPointerLikeModel,
                                             LLVM::LLVMPointerType> {
   Type getElementType(Type pointer) const { return Type(); }
+
+  mlir::Value genLoad(Type pointer, OpBuilder &builder, Location loc,
+                      TypedValue<PointerLikeType> srcPtr,
+                      Type valueType) const {
+    // For LLVM pointers, we need the valueType to determine what to load
+    if (!valueType)
+      return {};
+
+    return LLVM::LoadOp::create(builder, loc, valueType, srcPtr);
+  }
+
+  bool genStore(Type pointer, OpBuilder &builder, Location loc,
+                Value valueToStore, TypedValue<PointerLikeType> destPtr) const {
+    LLVM::StoreOp::create(builder, loc, valueToStore, destPtr);
+    return true;
+  }
 };
 
 struct MemrefAddressOfGlobalModel
diff --git a/mlir/test/Dialect/OpenACC/pointer-like-interface-load.mlir b/mlir/test/Dialect/OpenACC/pointer-like-interface-load.mlir
new file mode 100644
index 0000000000000..36df6a1d1bbe3
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/pointer-like-interface-load.mlir
@@ -0,0 +1,29 @@
+// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=load}))" 2>&1 | FileCheck %s
+
+func.func @test_memref_load_scalar() {
+  %ptr = memref.alloca() {test.ptr} : memref<f32>
+  // CHECK: Successfully generated load for operation: %[[PTR:.*]] = memref.alloca() {test.ptr} : memref<f32>
+  // CHECK: Loaded value type: f32
+  // CHECK: Generated: %{{.*}} = memref.load %[[PTR]][] : memref<f32>
+  return
+}
+
+// -----
+
+func.func @test_memref_load_int() {
+  %ptr = memref.alloca() {test.ptr} : memref<i64>
+  // CHECK: Successfully generated load for operation: %[[PTR:.*]] = memref.alloca() {test.ptr} : memref<i64>
+  // CHECK: Loaded value type: i64
+  // CHECK: Generated: %{{.*}} = memref.load %[[PTR]][] : memref<i64>
+  return
+}
+
+// -----
+
+func.func @test_memref_load_dynamic() {
+  %c10 = arith.constant 10 : index
+  %ptr = memref.alloc(%c10) {test.ptr} : memref<?xf32>
+  // CHECK: Failed to generate load for operation: %[[PTR:.*]] = memref.alloc(%{{.*}}) {test.ptr} : memref<?xf32>
+  return
+}
+
diff --git a/mlir/test/Dialect/OpenACC/pointer-like-interface-store.mlir b/mlir/test/Dialect/OpenACC/pointer-like-interface-store.mlir
new file mode 100644
index 0000000000000..0fee43102d6d9
--- /dev/null
+++ b/mlir/test/Dialect/OpenACC/pointer-like-interface-store.mlir
@@ -0,0 +1,39 @@
+// RUN: mlir-opt %s --split-input-file --pass-pipeline="builtin.module(func.func(test-acc-pointer-like-interface{test-mode=store}))" 2>&1 | FileCheck %s
+
+func.func @test_memref_store_scalar() {
+  %ptr = memref.alloca() {test.ptr} : memref<f32>
+  // CHECK: Successfully generated store for operation: %[[PTR:.*]] = memref.alloca() {test.ptr} : memref<f32>
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 4.200000e+01 : f32
+  // CHECK: Generated: memref.store %[[VAL]], %[[PTR]][] : memref<f32>
+  return
+}
+
+// -----
+
+func.func @test_memref_store_int() {
+  %ptr = memref.alloca() {test.ptr} : memref<i32>
+  // CHECK: Successfully generated store for operation: %[[PTR:.*]] = memref.alloca() {test.ptr} : memref<i32>
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i32
+  // CHECK: Generated: memref.store %[[VAL]], %[[PTR]][] : memref<i32>
+  return
+}
+
+// -----
+
+func.func @test_memref_store_i64() {
+  %ptr = memref.alloca() {test.ptr} : memref<i64>
+  // CHECK: Successfully generated store for operation: %[[PTR:.*]] = memref.alloca() {test.ptr} : memref<i64>
+  // CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i64
+  // CHECK: Generated: memref.store %[[VAL]], %[[PTR]][] : memref<i64>
+  return
+}
+
+// -----
+
+func.func @test_memref_store_dynamic() {
+  %c10 = arith.constant 10 : index
+  %ptr = memref.alloc(%c10) {test.ptr} : memref<?xf32>
+  // CHECK: Failed to generate store for operation: %[[PTR:.*]] = memref.alloc(%{{.*}}) {test.ptr} : memref<?xf32>
+  return
+}
+
diff --git a/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp b/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp
index 027b0a1a8b80b..9e2db6ac64f60 100644
--- a/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp
+++ b/mlir/test/lib/Dialect/OpenACC/TestPointerLikeTypeInterface.cpp
@@ -46,7 +46,7 @@ struct TestPointerLikeTypeInterfacePass
 
...
[truncated]

@github-actions
Copy link

github-actions bot commented Dec 2, 2025

✅ With the latest revision this PR passed the C/C++ code formatter.

@razvanlupusoru razvanlupusoru merged commit b50a590 into llvm:main Dec 2, 2025
10 checks passed
kcloudy0717 pushed a commit to kcloudy0717/llvm-project that referenced this pull request Dec 4, 2025
This patch extends the OpenACC PointerLikeType interface with two new
methods for generating load and store operations, enabling
dialect-agnostic memory access patterns.

New Interface Methods:
- genLoad(builder, loc, srcPtr, valueType): Generates a load operation
from a pointer-like value. Returns the loaded value.

- genStore(builder, loc, valueToStore, destPtr): Generates a store
operation to a pointer-like value.

Implementations provided for FIR pointer-like types, memref type (rank-0
only), and LLVM pointer types.

Extended TestPointerLikeTypeInterface.cpp with 'load' and 'store' test
modes.
honeygoyal pushed a commit to honeygoyal/llvm-project that referenced this pull request Dec 9, 2025
This patch extends the OpenACC PointerLikeType interface with two new
methods for generating load and store operations, enabling
dialect-agnostic memory access patterns.

New Interface Methods:
- genLoad(builder, loc, srcPtr, valueType): Generates a load operation
from a pointer-like value. Returns the loaded value.

- genStore(builder, loc, valueToStore, destPtr): Generates a store
operation to a pointer-like value.

Implementations provided for FIR pointer-like types, memref type (rank-0
only), and LLVM pointer types.

Extended TestPointerLikeTypeInterface.cpp with 'load' and 'store' test
modes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

flang:fir-hlfir flang Flang issues not falling into any other category mlir:openacc mlir openacc

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants