Skip to content
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -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>
Expand Down
112 changes: 112 additions & 0 deletions flang/lib/Optimizer/OpenACC/Support/FIROpenACCTypeInterfaces.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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
85 changes: 85 additions & 0 deletions flang/test/Fir/OpenACC/pointer-like-interface-load.mlir
Original file line number Diff line number Diff line change
@@ -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
}

75 changes: 75 additions & 0 deletions flang/test/Fir/OpenACC/pointer-like-interface-store.mlir
Original file line number Diff line number Diff line change
@@ -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
}

44 changes: 44 additions & 0 deletions mlir/include/mlir/Dialect/OpenACC/OpenACCTypeInterfaces.td
Original file line number Diff line number Diff line change
Expand Up @@ -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;
}]
>,
];
}

Expand Down
Loading