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.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 205807eab403a..82d960a6fc61e 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 cbe93907265f6..6181e1fad4240 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 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(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 15c9a11e5aefe..a7f52657d0f12 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 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>, %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 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) -> !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>>