-
Notifications
You must be signed in to change notification settings - Fork 14.5k
[Flang] - Handle BoxCharType
in fir.box_offset
op
#141713
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[Flang] - Handle BoxCharType
in fir.box_offset
op
#141713
Conversation
@llvm/pr-subscribers-flang-codegen @llvm/pr-subscribers-flang-fir-hlfir Author: Pranav Bhandarkar (bhandarkar-pranav) ChangesTo map Full diff: https://github.com/llvm/llvm-project/pull/141713.diff 8 Files Affected:
diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td
index dc66885f776f0..160de05a33b41 100644
--- a/flang/include/flang/Optimizer/Dialect/FIROps.td
+++ b/flang/include/flang/Optimizer/Dialect/FIROps.td
@@ -3240,11 +3240,17 @@ def fir_BoxOffsetOp : fir_Op<"box_offset", [NoMemoryEffect]> {
descriptor implementation must have, only the base_addr and derived_type
descriptor fields can be addressed.
+ It also accepts the address of a fir.boxchar and returns
+ address of the data pointer encapsulated by the fir.boxchar.
+
```
%addr = fir.box_offset %box base_addr : (!fir.ref<!fir.box<!fir.array<?xi32>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xi32>>>
%tdesc = fir.box_offset %box derived_type : (!fir.ref<!fir.box<!fir.type<t>>>) -> !fir.llvm_ptr<!fir.tdesc<!fir.type<t>>>
+ %addr1 = fir.box_offset %boxchar base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<fir.char<1,?>>>
```
+
+ The derived_type field cannot be used when the input to this op is a reference to a fir.boxchar.
}];
let arguments = (ins
diff --git a/flang/include/flang/Optimizer/Dialect/FIRType.h b/flang/include/flang/Optimizer/Dialect/FIRType.h
index 52b14f15f89bd..01878aa41005c 100644
--- a/flang/include/flang/Optimizer/Dialect/FIRType.h
+++ b/flang/include/flang/Optimizer/Dialect/FIRType.h
@@ -278,8 +278,9 @@ inline mlir::Type unwrapRefType(mlir::Type t) {
/// If `t` conforms with a pass-by-reference type (box, ref, ptr, etc.) then
/// return the element type of `t`. Otherwise, return `t`.
inline mlir::Type unwrapPassByRefType(mlir::Type t) {
- if (auto eleTy = dyn_cast_ptrOrBoxEleTy(t))
- return eleTy;
+ if (conformsWithPassByRef(t))
+ if (auto eleTy = dyn_cast_ptrOrBoxEleTy(t))
+ return eleTy;
return t;
}
diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
index 205807eab403a..e383c2e3e89ab 100644
--- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp
+++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp
@@ -3930,12 +3930,25 @@ struct BoxOffsetOpConversion : public fir::FIROpConversion<fir::BoxOffsetOp> {
mlir::ConversionPatternRewriter &rewriter) const override {
mlir::Type pty = ::getLlvmPtrType(boxOffset.getContext());
- mlir::Type boxType = fir::unwrapRefType(boxOffset.getBoxRef().getType());
- mlir::Type llvmBoxTy =
- lowerTy().convertBoxTypeAsStruct(mlir::cast<fir::BaseBoxType>(boxType));
- int fieldId = boxOffset.getField() == fir::BoxFieldAttr::derived_type
- ? getTypeDescFieldId(boxType)
- : kAddrPosInBox;
+ mlir::Type boxRefType = fir::unwrapRefType(boxOffset.getBoxRef().getType());
+
+ assert((mlir::isa<fir::BaseBoxType>(boxRefType) ||
+ mlir::isa<fir::BoxCharType>(boxRefType)) &&
+ "boxRef should be a reference to either fir.box or fir.boxchar");
+
+ mlir::Type llvmBoxTy;
+ int fieldId;
+ if (auto boxType = mlir::dyn_cast_or_null<fir::BaseBoxType>(boxRefType)) {
+ llvmBoxTy =
+ lowerTy().convertBoxTypeAsStruct(mlir::cast<fir::BaseBoxType>(boxType));
+ fieldId = boxOffset.getField() == fir::BoxFieldAttr::derived_type
+ ? getTypeDescFieldId(boxType)
+ : kAddrPosInBox;
+ } else {
+ auto boxCharType = mlir::cast<fir::BoxCharType>(boxRefType);
+ llvmBoxTy = lowerTy().convertType(boxCharType);
+ fieldId = kAddrPosInBox;
+ }
rewriter.replaceOpWithNewOp<mlir::LLVM::GEPOp>(
boxOffset, pty, llvmBoxTy, adaptor.getBoxRef(),
llvm::ArrayRef<mlir::LLVM::GEPArg>{0, fieldId});
diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp
index cbe93907265f6..6435886d73081 100644
--- a/flang/lib/Optimizer/Dialect/FIROps.cpp
+++ b/flang/lib/Optimizer/Dialect/FIROps.cpp
@@ -4484,15 +4484,25 @@ void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl<mlir::Value> &results,
llvm::LogicalResult fir::BoxOffsetOp::verify() {
auto boxType = mlir::dyn_cast_or_null<fir::BaseBoxType>(
fir::dyn_cast_ptrEleTy(getBoxRef().getType()));
- if (!boxType)
- return emitOpError("box_ref operand must have !fir.ref<!fir.box<T>> type");
+ mlir::Type boxCharType;
+ bool isBoxChar = false;
+ if (!boxType) {
+ boxCharType = mlir::dyn_cast_or_null<fir::BoxCharType>(
+ fir::dyn_cast_ptrEleTy(getBoxRef().getType()));
+ if (!boxCharType)
+ return emitOpError("box_ref operand must have !fir.ref<!fir.box<T>> or !fir.ref<!fir.boxchar<k>> type");
+ isBoxChar = true;
+ }
if (getField() != fir::BoxFieldAttr::base_addr &&
getField() != fir::BoxFieldAttr::derived_type)
return emitOpError("cannot address provided field");
- if (getField() == fir::BoxFieldAttr::derived_type)
+ if (getField() == fir::BoxFieldAttr::derived_type) {
+ if (isBoxChar)
+ return emitOpError("cannot address derived_type field of a fir.boxchar");
if (!fir::boxHasAddendum(boxType))
return emitOpError("can only address derived_type field of derived type "
"or unlimited polymorphic fir.box");
+ }
return mlir::success();
}
diff --git a/flang/lib/Optimizer/Dialect/FIRType.cpp b/flang/lib/Optimizer/Dialect/FIRType.cpp
index 1e6e95393c2f7..da7aa17445404 100644
--- a/flang/lib/Optimizer/Dialect/FIRType.cpp
+++ b/flang/lib/Optimizer/Dialect/FIRType.cpp
@@ -255,7 +255,7 @@ mlir::Type dyn_cast_ptrOrBoxEleTy(mlir::Type t) {
return llvm::TypeSwitch<mlir::Type, mlir::Type>(t)
.Case<fir::ReferenceType, fir::PointerType, fir::HeapType,
fir::LLVMPointerType>([](auto p) { return p.getEleTy(); })
- .Case<fir::BaseBoxType>(
+ .Case<fir::BaseBoxType, fir::BoxCharType>(
[](auto p) { return unwrapRefType(p.getEleTy()); })
.Default([](mlir::Type) { return mlir::Type{}; });
}
diff --git a/flang/test/Fir/box-offset-codegen.fir b/flang/test/Fir/box-offset-codegen.fir
index 15c9a11e5aefe..59cfda8523061 100644
--- a/flang/test/Fir/box-offset-codegen.fir
+++ b/flang/test/Fir/box-offset-codegen.fir
@@ -37,3 +37,13 @@ func.func @array_tdesc(%array : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.t
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 8
// CHECK: ret ptr %[[VAL_0]]
+
+func.func @boxchar_addr(%boxchar : !fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>> {
+ %addr = fir.box_offset %boxchar base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
+ return %addr : !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
+}
+
+// CHECK-LABEL: define ptr @boxchar_addr(
+// CHECK-SAME: ptr captures(none) %[[BOXCHAR:.*]]){{.*}} {
+// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64 }, ptr %[[BOXCHAR]], i32 0, i32 0
+// CHECK: ret ptr %[[VAL_0]]
diff --git a/flang/test/Fir/box-offset.fir b/flang/test/Fir/box-offset.fir
index 98c2eaefb8d6b..181ad51a5dbe1 100644
--- a/flang/test/Fir/box-offset.fir
+++ b/flang/test/Fir/box-offset.fir
@@ -21,6 +21,9 @@ func.func @test_box_offset(%unlimited : !fir.ref<!fir.class<none>>, %type_star :
%addr6 = fir.box_offset %type_star base_addr : (!fir.ref<!fir.box<!fir.array<?xnone>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xnone>>>
%tdesc6 = fir.box_offset %type_star derived_type : (!fir.ref<!fir.box<!fir.array<?xnone>>>) -> !fir.llvm_ptr<!fir.tdesc<none>>
+
+ %boxchar = fir.alloca !fir.boxchar<1>
+ %addr7 = fir.box_offset %boxchar base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
return
}
// CHECK-LABEL: func.func @test_box_offset(
@@ -40,3 +43,5 @@ func.func @test_box_offset(%unlimited : !fir.ref<!fir.class<none>>, %type_star :
// CHECK: %[[VAL_13:.*]] = fir.box_offset %[[VAL_0]] derived_type : (!fir.ref<!fir.class<none>>) -> !fir.llvm_ptr<!fir.tdesc<none>>
// CHECK: %[[VAL_14:.*]] = fir.box_offset %[[VAL_1]] base_addr : (!fir.ref<!fir.box<!fir.array<?xnone>>>) -> !fir.llvm_ptr<!fir.ref<!fir.array<?xnone>>>
// CHECK: %[[VAL_15:.*]] = fir.box_offset %[[VAL_1]] derived_type : (!fir.ref<!fir.box<!fir.array<?xnone>>>) -> !fir.llvm_ptr<!fir.tdesc<none>>
+// CHECK: %[[VAL_16:.*]] = fir.alloca !fir.boxchar<1>
+// CHECK: %[[VAL_17:.*]] = fir.box_offset %[[VAL_16]] base_addr : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir
index fd607fd9066f7..45cae1f82cb8e 100644
--- a/flang/test/Fir/invalid.fir
+++ b/flang/test/Fir/invalid.fir
@@ -972,13 +972,21 @@ func.func @rec_to_rec(%arg0: !fir.type<t1{i:i32, f:f32}>) -> !fir.type<t2{f:f32,
// -----
func.func @bad_box_offset(%not_a_box : !fir.ref<i32>) {
- // expected-error@+1{{'fir.box_offset' op box_ref operand must have !fir.ref<!fir.box<T>> type}}
+ // expected-error@+1{{'fir.box_offset' op box_ref operand must have !fir.ref<!fir.box<T>> or !fir.ref<!fir.boxchar<k>> type}}
%addr1 = fir.box_offset %not_a_box base_addr : (!fir.ref<i32>) -> !fir.llvm_ptr<!fir.ref<i32>>
return
}
// -----
+func.func @bad_box_offset(%boxchar : !fir.ref<!fir.boxchar<1>>) {
+ // expected-error@+1{{'fir.box_offset' op cannot address derived_type field of a fir.boxchar}}
+ %addr1 = fir.box_offset %boxchar derived_type : (!fir.ref<!fir.boxchar<1>>) -> !fir.llvm_ptr<!fir.ref<!fir.char<1,?>>>
+ return
+}
+
+// -----
+
func.func @bad_box_offset(%no_addendum : !fir.ref<!fir.box<i32>>) {
// expected-error@+1{{'fir.box_offset' op can only address derived_type field of derived type or unlimited polymorphic fir.box}}
%addr1 = fir.box_offset %no_addendum derived_type : (!fir.ref<!fir.box<i32>>) -> !fir.llvm_ptr<!fir.tdesc<!fir.type<none>>>
|
✅ With the latest revision this PR passed the C/C++ code formatter. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM with one minor comment
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM outside of the unwrapPassByRefType
change.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM based on my understanding, but I'll leave final approval up to the other reviewers!
@@ -37,3 +37,13 @@ func.func @array_tdesc(%array : !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.t | |||
// CHECK-SAME: ptr captures(none) %[[BOX:.*]]){{.*}}{ | |||
// CHECK: %[[VAL_0:.*]] = getelementptr { ptr, i64, i32, i8, i8, i8, i8, [1 x [3 x i64]], ptr, [1 x i64] }, ptr %[[BOX]], i32 0, i32 8 | |||
// CHECK: ret ptr %[[VAL_0]] | |||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Beware the github CI indicates this test is failing.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thank you for you review. I noticed. I'll take care of it.
Merging this because failing testcase (Flang.lower/namelist.f90) is a testcase problem fixed by #142363. |
LLVM Buildbot has detected a new failure on builder Full details are available at: https://lab.llvm.org/buildbot/#/builders/204/builds/11557 Here is the relevant piece of the build log for the reference
|
To map `fir.boxchar` types reliably onto an offload target, such as a GPU, the `omp.map.info` operation is used to map the underlying data pointer (`fir.ref<fir.char<k, ?>>`) wrapped by the `fir.boxchar` MLIR value. The `omp.map.info` operation needs a pointer to the underlying data pointer. Given a reference to a descriptor (`fir.box`), the `fir.box_offset` is used to obtain the address of the underlying data pointer. This PR extends `fir.box_offset` to provide the same functionality for `fir.boxchar` as well.
To map `fir.boxchar` types reliably onto an offload target, such as a GPU, the `omp.map.info` operation is used to map the underlying data pointer (`fir.ref<fir.char<k, ?>>`) wrapped by the `fir.boxchar` MLIR value. The `omp.map.info` operation needs a pointer to the underlying data pointer. Given a reference to a descriptor (`fir.box`), the `fir.box_offset` is used to obtain the address of the underlying data pointer. This PR extends `fir.box_offset` to provide the same functionality for `fir.boxchar` as well.
To map `fir.boxchar` types reliably onto an offload target, such as a GPU, the `omp.map.info` operation is used to map the underlying data pointer (`fir.ref<fir.char<k, ?>>`) wrapped by the `fir.boxchar` MLIR value. The `omp.map.info` operation needs a pointer to the underlying data pointer. Given a reference to a descriptor (`fir.box`), the `fir.box_offset` is used to obtain the address of the underlying data pointer. This PR extends `fir.box_offset` to provide the same functionality for `fir.boxchar` as well.
To map
fir.boxchar
types reliably onto an offload target, such as a GPU, theomp.map.info
operation is used to map the underlying data pointer (fir.ref<fir.char<k, ?>>
) wrapped by thefir.boxchar
MLIR value. Theomp.map.info
operation needs a pointer to the underlying data pointer.Given a reference to a descriptor (
fir.box
), thefir.box_offset
is used to obtain the address of the underlying data pointer. This PR extendsfir.box_offset
to provide the same functionality forfir.boxchar
as well.PR Stack
BoxCharType
infir.box_offset
op #141713 (This PR)fir.boxchar
, map the underlying data pointer as a member #141715