Skip to content

Commit 81a9d75

Browse files
[mlir][acc] Add mapping operation for firstprivate without counter (#164677)
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).
1 parent c1678e5 commit 81a9d75

File tree

4 files changed

+76
-4
lines changed

4 files changed

+76
-4
lines changed

mlir/include/mlir/Dialect/OpenACC/OpenACC.h

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -46,10 +46,10 @@
4646
mlir::acc::CopyinOp, mlir::acc::CreateOp, mlir::acc::PresentOp, \
4747
mlir::acc::NoCreateOp, mlir::acc::AttachOp, mlir::acc::DevicePtrOp, \
4848
mlir::acc::GetDevicePtrOp, mlir::acc::PrivateOp, \
49-
mlir::acc::FirstprivateOp, mlir::acc::UpdateDeviceOp, \
50-
mlir::acc::UseDeviceOp, mlir::acc::ReductionOp, \
51-
mlir::acc::DeclareDeviceResidentOp, mlir::acc::DeclareLinkOp, \
52-
mlir::acc::CacheOp
49+
mlir::acc::FirstprivateOp, mlir::acc::FirstprivateMapInitialOp, \
50+
mlir::acc::UpdateDeviceOp, mlir::acc::UseDeviceOp, \
51+
mlir::acc::ReductionOp, mlir::acc::DeclareDeviceResidentOp, \
52+
mlir::acc::DeclareLinkOp, mlir::acc::CacheOp
5353
#define ACC_DATA_EXIT_OPS \
5454
mlir::acc::CopyoutOp, mlir::acc::DeleteOp, mlir::acc::DetachOp, \
5555
mlir::acc::UpdateHostOp

mlir/include/mlir/Dialect/OpenACC/OpenACCOps.td

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -787,6 +787,21 @@ def OpenACC_FirstprivateOp : OpenACC_DataEntryOp<"firstprivate",
787787
let extraClassDeclaration = extraClassDeclarationBase;
788788
}
789789

790+
// The mapping of firstprivate cannot be represented through an `acc.copyin`
791+
// since that operation includes present counter updates (and private variables
792+
// do not impact counters). Instead, the below operation is used to represent
793+
// the mapping of that initial value which can be used to initialize the private
794+
// copies.
795+
def OpenACC_FirstprivateMapInitialOp : OpenACC_DataEntryOp<"firstprivate_map",
796+
"mlir::acc::DataClause::acc_firstprivate", "", [],
797+
(ins Arg<OpenACC_AnyPointerOrMappableType,"Host variable",[MemRead]>:$var)> {
798+
let summary = "Used to decompose firstprivate semantics and represents the "
799+
"mapping of the initial value.";
800+
let results = (outs Arg<OpenACC_AnyPointerOrMappableType,
801+
"Accelerator mapped variable",[MemWrite]>:$accVar);
802+
let extraClassDeclaration = extraClassDeclarationBase;
803+
}
804+
790805
//===----------------------------------------------------------------------===//
791806
// 2.5.15 reduction clause
792807
//===----------------------------------------------------------------------===//

mlir/lib/Dialect/OpenACC/IR/OpenACC.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -609,6 +609,20 @@ LogicalResult acc::FirstprivateOp::verify() {
609609
return success();
610610
}
611611

612+
//===----------------------------------------------------------------------===//
613+
// FirstprivateMapInitialOp
614+
//===----------------------------------------------------------------------===//
615+
LogicalResult acc::FirstprivateMapInitialOp::verify() {
616+
if (getDataClause() != acc::DataClause::acc_firstprivate)
617+
return emitError("data clause associated with firstprivate operation must "
618+
"match its intent");
619+
if (failed(checkVarAndVarType(*this)))
620+
return failure();
621+
if (failed(checkNoModifier(*this)))
622+
return failure();
623+
return success();
624+
}
625+
612626
//===----------------------------------------------------------------------===//
613627
// ReductionOp
614628
//===----------------------------------------------------------------------===//

mlir/test/Dialect/OpenACC/ops.mlir

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2200,3 +2200,46 @@ acc.private.recipe @privatization_memref_slice : memref<10x10xf32> init {
22002200

22012201
acc.yield %result : memref<10x10xf32>
22022202
}
2203+
2204+
// -----
2205+
2206+
func.func @test_firstprivate_map(%arg0: memref<10xf32>) {
2207+
// Map the function argument using firstprivate_map to enable
2208+
// moving to accelerator but prevent any present counter updates.
2209+
%mapped = acc.firstprivate_map varPtr(%arg0 : memref<10xf32>) varType(tensor<10xf32>) -> memref<10xf32>
2210+
2211+
acc.parallel {
2212+
// Allocate a local variable inside the parallel region to represent
2213+
// materialized privatization.
2214+
%local = memref.alloca() : memref<10xf32>
2215+
2216+
// Initialize the local variable with the mapped firstprivate value
2217+
%c0 = arith.constant 0 : index
2218+
%c10 = arith.constant 10 : index
2219+
%c1 = arith.constant 1 : index
2220+
2221+
scf.for %i = %c0 to %c10 step %c1 {
2222+
%val = memref.load %mapped[%i] : memref<10xf32>
2223+
memref.store %val, %local[%i] : memref<10xf32>
2224+
}
2225+
2226+
acc.yield
2227+
}
2228+
2229+
return
2230+
}
2231+
2232+
// CHECK-LABEL: func @test_firstprivate_map
2233+
// CHECK-NEXT: %[[MAPPED:.*]] = acc.firstprivate_map varPtr(%{{.*}} : memref<10xf32>) varType(tensor<10xf32>) -> memref<10xf32>
2234+
// CHECK-NEXT: acc.parallel {
2235+
// CHECK-NEXT: %[[LOCAL:.*]] = memref.alloca() : memref<10xf32>
2236+
// CHECK-NEXT: %[[C0:.*]] = arith.constant 0 : index
2237+
// CHECK-NEXT: %[[C10:.*]] = arith.constant 10 : index
2238+
// CHECK-NEXT: %[[C1:.*]] = arith.constant 1 : index
2239+
// CHECK-NEXT: scf.for %{{.*}} = %[[C0]] to %[[C10]] step %[[C1]] {
2240+
// CHECK-NEXT: %{{.*}} = memref.load %[[MAPPED]][%{{.*}}] : memref<10xf32>
2241+
// CHECK-NEXT: memref.store %{{.*}}, %[[LOCAL]][%{{.*}}] : memref<10xf32>
2242+
// CHECK-NEXT: }
2243+
// CHECK-NEXT: acc.yield
2244+
// CHECK-NEXT: }
2245+
// CHECK-NEXT: return

0 commit comments

Comments
 (0)