From 839591289592ea79be035f814ac75ba6c6b0fba4 Mon Sep 17 00:00:00 2001 From: Pranav Bhandarkar Date: Fri, 6 Jun 2025 10:48:07 -0500 Subject: [PATCH] [Flang] - Handle `BoxCharType` in `fir.box_offset` op (#141713) 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>`) 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. --- .../include/flang/Optimizer/Dialect/FIROps.td | 6 +++++ flang/lib/Optimizer/CodeGen/CodeGen.cpp | 25 ++++++++++++++----- flang/lib/Optimizer/Dialect/FIROps.cpp | 15 ++++++++--- flang/lib/Optimizer/Dialect/FIRType.cpp | 2 +- flang/test/Fir/box-offset-codegen.fir | 10 ++++++++ flang/test/Fir/box-offset.fir | 5 ++++ flang/test/Fir/invalid.fir | 10 +++++++- 7 files changed, 62 insertions(+), 11 deletions(-) diff --git a/flang/include/flang/Optimizer/Dialect/FIROps.td b/flang/include/flang/Optimizer/Dialect/FIROps.td index f4b17ef7eed0..90e05ce3d5ca 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.llvm_ptr>> %tdesc = fir.box_offset %box derived_type : (!fir.ref>>) -> !fir.llvm_ptr>> + %addr1 = fir.box_offset %boxchar base_addr : (!fir.ref>) -> !fir.llvm_ptr>> ``` + + 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/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index 205807eab403..82d960a6fc61 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -3930,12 +3930,25 @@ struct BoxOffsetOpConversion : public fir::FIROpConversion { 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(boxType)); - int fieldId = boxOffset.getField() == fir::BoxFieldAttr::derived_type - ? getTypeDescFieldId(boxType) - : kAddrPosInBox; + mlir::Type boxRefType = fir::unwrapRefType(boxOffset.getBoxRef().getType()); + + assert((mlir::isa(boxRefType) || + mlir::isa(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(boxRefType)) { + llvmBoxTy = lowerTy().convertBoxTypeAsStruct( + mlir::cast(boxType)); + fieldId = boxOffset.getField() == fir::BoxFieldAttr::derived_type + ? getTypeDescFieldId(boxType) + : kAddrPosInBox; + } else { + auto boxCharType = mlir::cast(boxRefType); + llvmBoxTy = lowerTy().convertType(boxCharType); + fieldId = kAddrPosInBox; + } rewriter.replaceOpWithNewOp( boxOffset, pty, llvmBoxTy, adaptor.getBoxRef(), llvm::ArrayRef{0, fieldId}); diff --git a/flang/lib/Optimizer/Dialect/FIROps.cpp b/flang/lib/Optimizer/Dialect/FIROps.cpp index cbe93907265f..6181e1fad424 100644 --- a/flang/lib/Optimizer/Dialect/FIROps.cpp +++ b/flang/lib/Optimizer/Dialect/FIROps.cpp @@ -4484,15 +4484,24 @@ void fir::IfOp::resultToSourceOps(llvm::SmallVectorImpl &results, llvm::LogicalResult fir::BoxOffsetOp::verify() { auto boxType = mlir::dyn_cast_or_null( fir::dyn_cast_ptrEleTy(getBoxRef().getType())); - if (!boxType) - return emitOpError("box_ref operand must have !fir.ref> type"); + mlir::Type boxCharType; + if (!boxType) { + boxCharType = mlir::dyn_cast_or_null( + fir::dyn_cast_ptrEleTy(getBoxRef().getType())); + if (!boxCharType) + return emitOpError("box_ref operand must have !fir.ref> or " + "!fir.ref> type"); + if (getField() == fir::BoxFieldAttr::derived_type) + return emitOpError("cannot address derived_type field of a fir.boxchar"); + } 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 (!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 e65faf3a7396..e281a8b6fa38 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(t) .Case([](auto p) { return p.getEleTy(); }) - .Case( + .Case( [](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 11d5750ffc38..9af92a48959d 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.llvm_ptr>> { + %addr = fir.box_offset %boxchar base_addr : (!fir.ref>) -> !fir.llvm_ptr>> + return %addr : !fir.llvm_ptr>> +} + +// CHECK-LABEL: define ptr @boxchar_addr( +// CHECK-SAME: ptr {{.*}}%[[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 98c2eaefb8d6..181ad51a5dbe 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>, %type_star : %addr6 = fir.box_offset %type_star base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> %tdesc6 = fir.box_offset %type_star derived_type : (!fir.ref>>) -> !fir.llvm_ptr> + + %boxchar = fir.alloca !fir.boxchar<1> + %addr7 = fir.box_offset %boxchar base_addr : (!fir.ref>) -> !fir.llvm_ptr>> return } // CHECK-LABEL: func.func @test_box_offset( @@ -40,3 +43,5 @@ func.func @test_box_offset(%unlimited : !fir.ref>, %type_star : // CHECK: %[[VAL_13:.*]] = fir.box_offset %[[VAL_0]] derived_type : (!fir.ref>) -> !fir.llvm_ptr> // CHECK: %[[VAL_14:.*]] = fir.box_offset %[[VAL_1]] base_addr : (!fir.ref>>) -> !fir.llvm_ptr>> // CHECK: %[[VAL_15:.*]] = fir.box_offset %[[VAL_1]] derived_type : (!fir.ref>>) -> !fir.llvm_ptr> +// CHECK: %[[VAL_16:.*]] = fir.alloca !fir.boxchar<1> +// CHECK: %[[VAL_17:.*]] = fir.box_offset %[[VAL_16]] base_addr : (!fir.ref>) -> !fir.llvm_ptr>> diff --git a/flang/test/Fir/invalid.fir b/flang/test/Fir/invalid.fir index fd607fd9066f..45cae1f82cb8 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) -> !fir.type) { - // expected-error@+1{{'fir.box_offset' op box_ref operand must have !fir.ref> type}} + // expected-error@+1{{'fir.box_offset' op box_ref operand must have !fir.ref> or !fir.ref> type}} %addr1 = fir.box_offset %not_a_box base_addr : (!fir.ref) -> !fir.llvm_ptr> return } // ----- +func.func @bad_box_offset(%boxchar : !fir.ref>) { + // 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.llvm_ptr>> + return +} + +// ----- + func.func @bad_box_offset(%no_addendum : !fir.ref>) { // 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.llvm_ptr>>