[Mlir-commits] [mlir] [mlir][acc] Add mapping operation for firstprivate without counter (PR #164677)
llvmlistbot at llvm.org
llvmlistbot at llvm.org
Wed Oct 22 11:01:14 PDT 2025
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-openacc
Author: Razvan Lupusoru (razvanlupusoru)
<details>
<summary>Changes</summary>
The OpenACC data clause operation `acc.copyin` used for mapping variables to device memory includes bookkeeping required by the OpenACC spec for updating present counters. However, for firstprivate variables, no counters should be updated since this clause creates a private copy on the device initialized with the original value from the host (as described in OpenACC 3.4 section 2.5.14: "the copy will be initialized with the value of that item on the local thread").
This PR introduces the `acc.firstprivate_map` operation to capture these mapping semantics without counter updates. A test is included demonstrating how this operation can be used to initialize a materialized private variable (represented by `memref.alloca` inside an `acc.parallel` region).
---
Full diff: https://github.com/llvm/llvm-project/pull/164677.diff
4 Files Affected:
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACC.h (+4-4)
- (modified) mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td (+15)
- (modified) mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp (+14)
- (modified) mlir/test/Dialect/OpenACC/ops.mlir (+43)
``````````diff
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
index e2a60f57940f6..05d2316711c8a 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACC.h
@@ -46,10 +46,10 @@
mlir::acc::CopyinOp, mlir::acc::CreateOp, mlir::acc::PresentOp, \
mlir::acc::NoCreateOp, mlir::acc::AttachOp, mlir::acc::DevicePtrOp, \
mlir::acc::GetDevicePtrOp, mlir::acc::PrivateOp, \
- mlir::acc::FirstprivateOp, mlir::acc::UpdateDeviceOp, \
- mlir::acc::UseDeviceOp, mlir::acc::ReductionOp, \
- mlir::acc::DeclareDeviceResidentOp, mlir::acc::DeclareLinkOp, \
- mlir::acc::CacheOp
+ mlir::acc::FirstprivateOp, mlir::acc::FirstprivateMapInitialOp, \
+ mlir::acc::UpdateDeviceOp, mlir::acc::UseDeviceOp, \
+ mlir::acc::ReductionOp, mlir::acc::DeclareDeviceResidentOp, \
+ mlir::acc::DeclareLinkOp, mlir::acc::CacheOp
#define ACC_DATA_EXIT_OPS \
mlir::acc::CopyoutOp, mlir::acc::DeleteOp, mlir::acc::DetachOp, \
mlir::acc::UpdateHostOp
diff --git a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
index e78cdbe3d3e64..2f87975ebaa04 100644
--- a/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
+++ b/mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td
@@ -787,6 +787,21 @@ def OpenACC_FirstprivateOp : OpenACC_DataEntryOp<"firstprivate",
let extraClassDeclaration = extraClassDeclarationBase;
}
+// The mapping of firstprivate cannot be represented through an `acc.copyin`
+// since that operation includes present counter updates (and private variables
+// do not impact counters). Instead, the below operation is used to represent
+// the mapping of that initial value which can be used to initialize the private
+// copies.
+def OpenACC_FirstprivateMapInitialOp : OpenACC_DataEntryOp<"firstprivate_map",
+ "mlir::acc::DataClause::acc_firstprivate", "", [],
+ (ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
+ let summary = "Used to decompose firstprivate semantics and represents the "
+ "mapping of the initial value.";
+ let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
+ "Accelerator mapped variable",[MemWrite]>:$accVar);
+ let extraClassDeclaration = extraClassDeclarationBase;
+}
+
//===----------------------------------------------------------------------===//
// 2.5.15 reduction clause
//===----------------------------------------------------------------------===//
diff --git a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
index 5ca0100debe55..ca46629919dba 100644
--- a/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
+++ b/mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp
@@ -609,6 +609,20 @@ LogicalResult acc::FirstprivateOp::verify() {
return success();
}
+//===----------------------------------------------------------------------===//
+// FirstprivateMapInitialOp
+//===----------------------------------------------------------------------===//
+LogicalResult acc::FirstprivateMapInitialOp::verify() {
+ if (getDataClause() != acc::DataClause::acc_firstprivate)
+ return emitError("data clause associated with firstprivate operation must "
+ "match its intent");
+ if (failed(checkVarAndVarType(*this)))
+ return failure();
+ if (failed(checkNoModifier(*this)))
+ return failure();
+ return success();
+}
+
//===----------------------------------------------------------------------===//
// ReductionOp
//===----------------------------------------------------------------------===//
diff --git a/mlir/test/Dialect/OpenACC/ops.mlir b/mlir/test/Dialect/OpenACC/ops.mlir
index 8713689ed5799..77d18da49276a 100644
--- a/mlir/test/Dialect/OpenACC/ops.mlir
+++ b/mlir/test/Dialect/OpenACC/ops.mlir
@@ -2200,3 +2200,46 @@ acc.private.recipe @privatization_memref_slice : memref<10x10xf32> init {
acc.yield %result : memref<10x10xf32>
}
+
+// -----
+
+func.func @test_firstprivate_map(%arg0: memref<10xf32>) {
+ // Map the function argument using firstprivate_map to enable
+ // moving to accelerator but prevent any present counter updates.
+ %mapped = acc.firstprivate_map varPtr(%arg0 : memref<10xf32>) varType(tensor<10xf32>) -> memref<10xf32>
+
+ acc.parallel {
+ // Allocate a local variable inside the parallel region to represent
+ // materialized privatization.
+ %local = memref.alloca() : memref<10xf32>
+
+ // Initialize the local variable with the mapped firstprivate value
+ %c0 = arith.constant 0 : index
+ %c10 = arith.constant 10 : index
+ %c1 = arith.constant 1 : index
+
+ scf.for %i = %c0 to %c10 step %c1 {
+ %val = memref.load %mapped[%i] : memref<10xf32>
+ memref.store %val, %local[%i] : memref<10xf32>
+ }
+
+ acc.yield
+ }
+
+ return
+}
+
+// CHECK-LABEL: func @test_firstprivate_map
+// CHECK-NEXT: %[[MAPPED:.*]] = acc.firstprivate_map varPtr(%{{.*}} : memref<10xf32>) varType(tensor<10xf32>) -> memref<10xf32>
+// CHECK-NEXT: acc.parallel {
+// CHECK-NEXT: %[[LOCAL:.*]] = memref.alloca() : memref<10xf32>
+// CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : index
+// CHECK-NEXT: %[[C10:.*]] = arith.constant 10 : index
+// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
+// CHECK-NEXT: scf.for %{{.*}} = %[[C0]] to %[[C10]] step %[[C1]] {
+// CHECK-NEXT: %{{.*}} = memref.load %[[MAPPED]][%{{.*}}] : memref<10xf32>
+// CHECK-NEXT: memref.store %{{.*}}, %[[LOCAL]][%{{.*}}] : memref<10xf32>
+// CHECK-NEXT: }
+// CHECK-NEXT: acc.yield
+// CHECK-NEXT: }
+// CHECK-NEXT: return
``````````
</details>
https://github.com/llvm/llvm-project/pull/164677
More information about the Mlir-commits
mailing list