Skip to content

Commit b50a590

Browse files
[acc][flang] Add genLoad and genStore to PointerLikeType (#170348)
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.
1 parent 6dd639e commit b50a590

File tree

9 files changed

+586
-2
lines changed

9 files changed

+586
-2
lines changed

flang/include/flang/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,15 @@ struct OpenACCPointerLikeModel
4343
mlir::TypedValue<mlir::acc::PointerLikeType> destination,
4444
mlir::TypedValue<mlir::acc::PointerLikeType> source,
4545
mlir::Type varType) const;
46+
47+
mlir::Value genLoad(mlir::Type pointer, mlir::OpBuilder &builder,
48+
mlir::Location loc,
49+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
50+
mlir::Type valueType) const;
51+
52+
bool genStore(mlir::Type pointer, mlir::OpBuilder &builder,
53+
mlir::Location loc, mlir::Value valueToStore,
54+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
4655
};
4756

4857
template <typename T>

flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp

Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1014,4 +1014,114 @@ template bool OpenACCPointerLikeModel<fir::LLVMPointerType>::genCopy(
10141014
mlir::TypedValue<mlir::acc::PointerLikeType> source,
10151015
mlir::Type varType) const;
10161016

1017+
template <typename Ty>
1018+
mlir::Value OpenACCPointerLikeModel<Ty>::genLoad(
1019+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1020+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
1021+
mlir::Type valueType) const {
1022+
1023+
// Unwrap to get the pointee type.
1024+
mlir::Type pointeeTy = fir::dyn_cast_ptrEleTy(pointer);
1025+
assert(pointeeTy && "expected pointee type to be extractable");
1026+
1027+
// Box types contain both a descriptor and referenced data. The genLoad API
1028+
// handles simple loads and cannot properly manage both parts.
1029+
if (fir::isa_box_type(pointeeTy))
1030+
return {};
1031+
1032+
// Unlimited polymorphic (class(*)) cannot be handled because type is unknown.
1033+
if (fir::isUnlimitedPolymorphicType(pointeeTy))
1034+
return {};
1035+
1036+
// Return empty for dynamic size types because the load logic
1037+
// cannot be determined simply from the type.
1038+
if (fir::hasDynamicSize(pointeeTy))
1039+
return {};
1040+
1041+
mlir::Value loadedValue = fir::LoadOp::create(builder, loc, srcPtr);
1042+
1043+
// If valueType is provided and differs from the loaded type, insert a convert
1044+
if (valueType && loadedValue.getType() != valueType)
1045+
return fir::ConvertOp::create(builder, loc, valueType, loadedValue);
1046+
1047+
return loadedValue;
1048+
}
1049+
1050+
template mlir::Value OpenACCPointerLikeModel<fir::ReferenceType>::genLoad(
1051+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1052+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
1053+
mlir::Type valueType) const;
1054+
1055+
template mlir::Value OpenACCPointerLikeModel<fir::PointerType>::genLoad(
1056+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1057+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
1058+
mlir::Type valueType) const;
1059+
1060+
template mlir::Value OpenACCPointerLikeModel<fir::HeapType>::genLoad(
1061+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1062+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
1063+
mlir::Type valueType) const;
1064+
1065+
template mlir::Value OpenACCPointerLikeModel<fir::LLVMPointerType>::genLoad(
1066+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1067+
mlir::TypedValue<mlir::acc::PointerLikeType> srcPtr,
1068+
mlir::Type valueType) const;
1069+
1070+
template <typename Ty>
1071+
bool OpenACCPointerLikeModel<Ty>::genStore(
1072+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1073+
mlir::Value valueToStore,
1074+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const {
1075+
1076+
// Unwrap to get the pointee type.
1077+
mlir::Type pointeeTy = fir::dyn_cast_ptrEleTy(pointer);
1078+
assert(pointeeTy && "expected pointee type to be extractable");
1079+
1080+
// Box types contain both a descriptor and referenced data. The genStore API
1081+
// handles simple stores and cannot properly manage both parts.
1082+
if (fir::isa_box_type(pointeeTy))
1083+
return false;
1084+
1085+
// Unlimited polymorphic (class(*)) cannot be handled because type is unknown.
1086+
if (fir::isUnlimitedPolymorphicType(pointeeTy))
1087+
return false;
1088+
1089+
// Return false for dynamic size types because the store logic
1090+
// cannot be determined simply from the type.
1091+
if (fir::hasDynamicSize(pointeeTy))
1092+
return false;
1093+
1094+
// Get the type from the value being stored
1095+
mlir::Type valueType = valueToStore.getType();
1096+
mlir::Value convertedValue = valueToStore;
1097+
1098+
// If the value type differs from the pointee type, insert a convert
1099+
if (valueType != pointeeTy)
1100+
convertedValue =
1101+
fir::ConvertOp::create(builder, loc, pointeeTy, valueToStore);
1102+
1103+
fir::StoreOp::create(builder, loc, convertedValue, destPtr);
1104+
return true;
1105+
}
1106+
1107+
template bool OpenACCPointerLikeModel<fir::ReferenceType>::genStore(
1108+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1109+
mlir::Value valueToStore,
1110+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
1111+
1112+
template bool OpenACCPointerLikeModel<fir::PointerType>::genStore(
1113+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1114+
mlir::Value valueToStore,
1115+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
1116+
1117+
template bool OpenACCPointerLikeModel<fir::HeapType>::genStore(
1118+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1119+
mlir::Value valueToStore,
1120+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
1121+
1122+
template bool OpenACCPointerLikeModel<fir::LLVMPointerType>::genStore(
1123+
mlir::Type pointer, mlir::OpBuilder &builder, mlir::Location loc,
1124+
mlir::Value valueToStore,
1125+
mlir::TypedValue<mlir::acc::PointerLikeType> destPtr) const;
1126+
10171127
} // namespace fir::acc
Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
// 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
2+
3+
func.func @test_load_scalar_f32() {
4+
%ptr = fir.alloca f32 {test.ptr}
5+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca f32 {test.ptr}
6+
// CHECK: Loaded value type: f32
7+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<f32>
8+
return
9+
}
10+
11+
// -----
12+
13+
func.func @test_load_scalar_i32() {
14+
%ptr = fir.alloca i32 {test.ptr}
15+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca i32 {test.ptr}
16+
// CHECK: Loaded value type: i32
17+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<i32>
18+
return
19+
}
20+
21+
// -----
22+
23+
func.func @test_load_scalar_i64() {
24+
%ptr = fir.alloca i64 {test.ptr}
25+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca i64 {test.ptr}
26+
// CHECK: Loaded value type: i64
27+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<i64>
28+
return
29+
}
30+
31+
// -----
32+
33+
func.func @test_load_heap_scalar() {
34+
%ptr = fir.allocmem f64 {test.ptr}
35+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.allocmem f64 {test.ptr}
36+
// CHECK: Loaded value type: f64
37+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.heap<f64>
38+
return
39+
}
40+
41+
// -----
42+
43+
func.func @test_load_logical() {
44+
%ptr = fir.alloca !fir.logical<4> {test.ptr}
45+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca !fir.logical<4> {test.ptr}
46+
// CHECK: Loaded value type: !fir.logical<4>
47+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<!fir.logical<4>>
48+
return
49+
}
50+
51+
// -----
52+
53+
func.func @test_load_derived_type() {
54+
%ptr = fir.alloca !fir.type<_QTt{i:i32}> {test.ptr}
55+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca !fir.type<_QTt{i:i32}> {test.ptr}
56+
// CHECK: Loaded value type: !fir.type<_QTt{i:i32}>
57+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<!fir.type<_QTt{i:i32}>>
58+
return
59+
}
60+
61+
// -----
62+
63+
func.func @test_load_constant_array() {
64+
%ptr = fir.alloca !fir.array<10xf32> {test.ptr}
65+
// CHECK: Successfully generated load for operation: %{{.*}} = fir.alloca !fir.array<10xf32> {test.ptr}
66+
// CHECK: Loaded value type: !fir.array<10xf32>
67+
// CHECK: Generated: %{{.*}} = fir.load %{{.*}} : !fir.ref<!fir.array<10xf32>>
68+
return
69+
}
70+
71+
// -----
72+
73+
func.func @test_load_dynamic_array_fails() {
74+
%c10 = arith.constant 10 : index
75+
%ptr = fir.alloca !fir.array<?xf32>, %c10 {test.ptr}
76+
// CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.array<?xf32>
77+
return
78+
}
79+
80+
// -----
81+
82+
func.func @test_load_box_fails() {
83+
%ptr = fir.alloca !fir.box<!fir.ptr<f32>> {test.ptr}
84+
// CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.box<!fir.ptr<f32>>
85+
return
86+
}
87+
88+
// -----
89+
90+
func.func @test_load_unlimited_polymorphic_fails() {
91+
%ptr = fir.alloca !fir.class<none> {test.ptr}
92+
// CHECK: Failed to generate load for operation: %{{.*}} = fir.alloca !fir.class<none>
93+
return
94+
}
95+
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
// 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
2+
3+
func.func @test_store_scalar_f32() {
4+
%ptr = fir.alloca f32 {test.ptr}
5+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca f32 {test.ptr}
6+
// CHECK: Generated: %[[VAL:.*]] = arith.constant 4.200000e+01 : f32
7+
// CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<f32>
8+
return
9+
}
10+
11+
// -----
12+
13+
func.func @test_store_scalar_i32() {
14+
%ptr = fir.alloca i32 {test.ptr}
15+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i32 {test.ptr}
16+
// CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i32
17+
// CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i32>
18+
return
19+
}
20+
21+
// -----
22+
23+
func.func @test_store_scalar_i64() {
24+
%ptr = fir.alloca i64 {test.ptr}
25+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i64 {test.ptr}
26+
// CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i64
27+
// CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i64>
28+
return
29+
}
30+
31+
// -----
32+
33+
func.func @test_store_heap_scalar() {
34+
%ptr = fir.allocmem f64 {test.ptr}
35+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.allocmem f64 {test.ptr}
36+
// CHECK: Generated: %[[VAL:.*]] = arith.constant 4.200000e+01 : f64
37+
// CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.heap<f64>
38+
return
39+
}
40+
41+
// -----
42+
43+
func.func @test_store_with_type_conversion() {
44+
%ptr = fir.alloca i32 {test.ptr}
45+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca i32 {test.ptr}
46+
// CHECK: Generated: %[[VAL:.*]] = arith.constant 42 : i32
47+
// CHECK: Generated: fir.store %[[VAL]] to %{{.*}} : !fir.ref<i32>
48+
return
49+
}
50+
51+
// -----
52+
53+
func.func @test_store_constant_array() {
54+
%val = fir.undefined !fir.array<10xf32> {test.value}
55+
%ptr = fir.alloca !fir.array<10xf32> {test.ptr}
56+
// CHECK: Successfully generated store for operation: %{{.*}} = fir.alloca !fir.array<10xf32> {test.ptr}
57+
// CHECK: Generated: fir.store %{{.*}} to %{{.*}} : !fir.ref<!fir.array<10xf32>>
58+
return
59+
}
60+
61+
// -----
62+
63+
func.func @test_store_dynamic_array_fails() {
64+
%c10 = arith.constant 10 : index
65+
%ptr = fir.alloca !fir.array<?xf32>, %c10 {test.ptr}
66+
// CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.array<?xf32>
67+
return
68+
}
69+
70+
// -----
71+
72+
func.func @test_store_box_fails() {
73+
%ptr = fir.alloca !fir.box<!fir.ptr<f32>> {test.ptr}
74+
// CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.box<!fir.ptr<f32>>
75+
return
76+
}
77+
78+
// -----
79+
80+
func.func @test_store_unlimited_polymorphic_fails() {
81+
%ptr = fir.alloca !fir.class<none> {test.ptr}
82+
// CHECK: Failed to generate store for operation: %{{.*}} = fir.alloca !fir.class<none>
83+
return
84+
}
85+

mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -176,6 +176,50 @@ def OpenACC_PointerLikeTypeInterface : TypeInterface<"PointerLikeType"> {
176176
return false;
177177
}]
178178
>,
179+
InterfaceMethod<
180+
/*description=*/[{
181+
Generates a load operation from the pointer-like type. This dereferences
182+
the pointer and returns the loaded value.
183+
184+
The `srcPtr` parameter is the pointer to load from. If the current type is
185+
represented in a way that it does not capture the pointee type, `valueType`
186+
must be passed in to provide the necessary type information.
187+
188+
Returns the loaded value, or an empty Value if load generation failed.
189+
}],
190+
/*retTy=*/"::mlir::Value",
191+
/*methodName=*/"genLoad",
192+
/*args=*/(ins "::mlir::OpBuilder &":$builder,
193+
"::mlir::Location":$loc,
194+
"::mlir::TypedValue<::mlir::acc::PointerLikeType>":$srcPtr,
195+
"::mlir::Type":$valueType),
196+
/*methodBody=*/"",
197+
/*defaultImplementation=*/[{
198+
return {};
199+
}]
200+
>,
201+
InterfaceMethod<
202+
/*description=*/[{
203+
Generates a store operation to the pointer-like type. This stores a value
204+
to the memory location pointed to by the pointer.
205+
206+
The `destPtr` parameter is the pointer to store to. The `valueToStore`
207+
parameter is the value to be stored. The type information is derived from
208+
the valueToStore parameter itself.
209+
210+
Returns true if store was successfully generated, false otherwise.
211+
}],
212+
/*retTy=*/"bool",
213+
/*methodName=*/"genStore",
214+
/*args=*/(ins "::mlir::OpBuilder &":$builder,
215+
"::mlir::Location":$loc,
216+
"::mlir::Value":$valueToStore,
217+
"::mlir::TypedValue<::mlir::acc::PointerLikeType>":$destPtr),
218+
/*methodBody=*/"",
219+
/*defaultImplementation=*/[{
220+
return false;
221+
}]
222+
>,
179223
];
180224
}
181225

0 commit comments

Comments
 (0)