[flang] Deal with NULL() passed as actual arg to unlimited polymorphic dummy

NULL() passed as actual argument to a procedure with an optional
dummy argument is represented with `fir.box<none>` type. When the dummy
argument is polymoprhic or unlimited polymorphic, the SelectOp will complain
if the types of the two arguments are not identical. Add a conversion from
`fir.box<none>` to `fir.class<none>` in that case.
Other situations with optional will require a fir.rebox and will be done in
a follow up patch.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D142203
This commit is contained in:
Valentin Clement 2023-01-23 09:44:12 +01:00
parent 4dbf3f2e8e
commit 262dad4a81
No known key found for this signature in database
GPG Key ID: 086D54783C928776
4 changed files with 42 additions and 0 deletions

View File

@ -276,6 +276,9 @@ bool isPointerType(mlir::Type ty);
/// Return true iff `ty` is the type of an ALLOCATABLE entity or value.
bool isAllocatableType(mlir::Type ty);
/// Return true iff `ty` is !fir.box<none>.
bool isBoxNone(mlir::Type ty);
/// Return true iff `ty` is the type of a boxed record type.
/// e.g. !fir.box<!fir.type<derived>>
bool isBoxedRecordType(mlir::Type ty);

View File

@ -2704,6 +2704,17 @@ public:
/// has the dummy attributes in BIND(C) contexts.
mlir::Value box = builder.createBox(
loc, fir::factory::genMutableBoxRead(builder, loc, mutableBox));
// NULL() passed as argument is passed as a !fir.box<none>. Since
// select op requires the same type for its two argument, convert
// !fir.box<none> to !fir.class<none> when the argument is
// polymorphic.
if (fir::isBoxNone(box.getType()) && fir::isPolymorphicType(argTy))
box = builder.createConvert(
loc,
fir::ClassType::get(mlir::NoneType::get(builder.getContext())),
box);
// Need the box types to be exactly similar for the selectOp.
mlir::Value convertedBox = builder.createConvert(loc, argTy, box);
caller.placeInput(arg, builder.create<mlir::arith::SelectOp>(

View File

@ -272,6 +272,12 @@ bool isAllocatableType(mlir::Type ty) {
return false;
}
bool isBoxNone(mlir::Type ty) {
if (auto box = ty.dyn_cast<fir::BoxType>())
return box.getEleTy().isa<mlir::NoneType>();
return false;
}
bool isBoxedRecordType(mlir::Type ty) {
if (auto refTy = fir::dyn_cast_ptrEleTy(ty))
ty = refTy;

View File

@ -767,6 +767,28 @@ module polymorphic_test
! CHECK: %[[REBOX:.*]] = fir.rebox %[[LOAD_P]](%{{.*}}) : (!fir.class<!fir.heap<!fir.array<?x?xnone>>>, !fir.shift<2>) -> !fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QMpolymorphic_testTnon_extensible{d:i32}>>>>
! CHECK: fir.store %[[REBOX]] to %[[T]] : !fir.ref<!fir.box<!fir.ptr<!fir.array<?x?x!fir.type<_QMpolymorphic_testTnon_extensible{d:i32}>>>>>
subroutine sub_with_poly_optional(a)
class(*), optional :: a
end subroutine
subroutine test_call_with_null()
call sub_with_poly_optional(null())
end subroutine
! CHECK-LABEL: func.func @_QMpolymorphic_testPtest_call_with_null() {
! CHECK: %[[NULL_LLVM_PTR:.*]] = fir.alloca !fir.llvm_ptr<none>
! CHECK: %[[NULL_BOX_NONE:.*]] = fir.convert %[[NULL_LLVM_PTR]] : (!fir.ref<!fir.llvm_ptr<none>>) -> !fir.ref<!fir.box<none>>
! CHECK: %[[BOX_NONE:.*]] = fir.load %[[NULL_BOX_NONE]] : !fir.ref<!fir.box<none>>
! CHECK: %[[BOX_ADDR:.*]] = fir.box_addr %[[BOX_NONE]] : (!fir.box<none>) -> !fir.ref<none>
! CHECK: %[[BOX_ADDR_I64:.*]] = fir.convert %[[BOX_ADDR]] : (!fir.ref<none>) -> i64
! CHECK: %[[C0:.*]] = arith.constant 0 : i64
! CHECK: %[[IS_ALLOCATED_OR_ASSOCIATED:.*]] = arith.cmpi ne, %[[BOX_ADDR_I64]], %[[C0]] : i64
! CHECK: %[[ABSENT:.*]] = fir.absent !fir.class<none>
! CHECK: %[[BOX_NONE:.*]] = fir.load %[[NULL_BOX_NONE]] : !fir.ref<!fir.box<none>>
! CHECK: %[[CLASS_NONE:.*]] = fir.convert %[[BOX_NONE]] : (!fir.box<none>) -> !fir.class<none>
! CHECK: %[[ARG:.*]] = arith.select %[[IS_ALLOCATED_OR_ASSOCIATED]], %[[CLASS_NONE]], %[[ABSENT]] : !fir.class<none>
! CHECK: fir.call @_QMpolymorphic_testPsub_with_poly_optional(%[[ARG]]) {{.*}} : (!fir.class<none>) -> ()
end module
program test