[flang] Allow conversion from boxed derived type to fir.class

This patch updates the fir.convert operation's verifier to allow
conversion from !fir.box<!fir.type<T>> to !fir.class<!fir.type<T>>.

Other conversion involving fir.class are likely needed but will
be added when lowering needs them.

Reviewed By: PeteSteinfeld

Differential Revision: https://reviews.llvm.org/D135445
This commit is contained in:
Valentin Clement 2022-10-10 08:58:20 +02:00
parent a835b92e6c
commit 0cf70a33f2
No known key found for this signature in database
GPG Key ID: 086D54783C928776
5 changed files with 86 additions and 12 deletions

View File

@ -38,6 +38,9 @@ public:
/// Returns the element type of this box type.
mlir::Type getEleTy() const;
/// Unwrap element type from fir.heap, fir.ptr and fir.array.
mlir::Type unwrapInnerType() const;
/// Methods for support type inquiry through isa, cast, and dyn_cast.
static bool classof(mlir::Type type);
};
@ -273,6 +276,10 @@ 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 the type of a boxed record type.
/// e.g. !fir.box<!fir.type<derived>>
bool isBoxedRecordType(mlir::Type ty);
/// Return true iff `ty` is the type of an polymorphic entity or
/// value.
bool isPolymorphicType(mlir::Type ty);

View File

@ -916,7 +916,8 @@ mlir::LogicalResult fir::ConvertOp::verify() {
(isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
(inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
(inType.isa<fir::BoxProcType>() && outType.isa<fir::BoxProcType>()) ||
(fir::isa_complex(inType) && fir::isa_complex(outType)))
(fir::isa_complex(inType) && fir::isa_complex(outType)) ||
(fir::isBoxedRecordType(inType) && fir::isPolymorphicType(outType)))
return mlir::success();
return emitOpError("invalid type conversion");
}

View File

@ -262,6 +262,18 @@ bool isAllocatableType(mlir::Type ty) {
return false;
}
bool isBoxedRecordType(mlir::Type ty) {
if (auto refTy = fir::dyn_cast_ptrEleTy(ty))
ty = refTy;
if (auto boxTy = ty.dyn_cast<fir::BoxType>()) {
if (boxTy.getEleTy().isa<fir::RecordType>())
return true;
mlir::Type innerType = boxTy.unwrapInnerType();
return innerType && innerType.isa<fir::RecordType>();
}
return false;
}
static bool isAssumedType(mlir::Type ty) {
if (auto boxTy = ty.dyn_cast<fir::BoxType>()) {
if (boxTy.getEleTy().isa<mlir::NoneType>())
@ -289,17 +301,8 @@ bool isUnlimitedPolymorphicType(mlir::Type ty) {
if (auto clTy = ty.dyn_cast<fir::ClassType>()) {
if (clTy.getEleTy().isa<mlir::NoneType>())
return true;
mlir::Type innerType =
llvm::TypeSwitch<mlir::Type, mlir::Type>(clTy.getEleTy())
.Case<fir::PointerType, fir::HeapType, fir::SequenceType>(
[](auto ty) {
mlir::Type eleTy = ty.getEleTy();
if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
return seqTy.getEleTy();
return eleTy;
})
.Default([](mlir::Type) { return mlir::Type{}; });
return innerType.isa<mlir::NoneType>();
mlir::Type innerType = clTy.unwrapInnerType();
return innerType && innerType.isa<mlir::NoneType>();
}
// TYPE(*)
return isAssumedType(ty);
@ -982,6 +985,17 @@ mlir::Type BaseBoxType::getEleTy() const {
[](auto type) { return type.getEleTy(); });
}
mlir::Type BaseBoxType::unwrapInnerType() const {
return llvm::TypeSwitch<mlir::Type, mlir::Type>(getEleTy())
.Case<fir::PointerType, fir::HeapType, fir::SequenceType>([](auto ty) {
mlir::Type eleTy = ty.getEleTy();
if (auto seqTy = eleTy.dyn_cast<fir::SequenceType>())
return seqTy.getEleTy();
return eleTy;
})
.Default([](mlir::Type) { return mlir::Type{}; });
}
//===----------------------------------------------------------------------===//
// FIROpsDialect
//===----------------------------------------------------------------------===//

View File

@ -6,6 +6,8 @@ module polymorphic_test
type p1
integer :: a
integer :: b
contains
procedure :: print
end type
type, extends(p1) :: p2
@ -27,4 +29,25 @@ module polymorphic_test
! CHECK: %[[LOAD:.*]] = fir.load %[[COORD]] : !fir.ref<i32>
! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[LOAD]]) : (!fir.ref<i8>, i32) -> i1
subroutine print(this)
class(p1) :: this
end subroutine
! Test passing fir.convert accept fir.box<DT> -> fir.class<DT>
subroutine check()
type(p1) :: t1
type(p2) :: t2
call t1%print()
call t2%print()
end subroutine
! CHECK-LABEL: func.func @_QMpolymorphic_testPcheck()
! CHECK: %[[DT1:.*]] = fir.alloca !fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}> {bindc_name = "t1", uniq_name = "_QMpolymorphic_testFcheckEt1"}
! CHECK: %[[DT2:.*]] = fir.alloca !fir.type<_QMpolymorphic_testTp2{a:i32,b:i32,c:f32}> {bindc_name = "t2", uniq_name = "_QMpolymorphic_testFcheckEt2"}
! CHECK: %[[BOX1:.*]] = fir.embox %[[DT1]] : (!fir.ref<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> !fir.box<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>
! CHECK: %[[CLASS1:.*]] = fir.convert %[[BOX1]] : (!fir.box<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>
! CHECK: fir.call @_QMpolymorphic_testPprint(%[[CLASS1]]) : (!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> ()
! CHECK: %[[BOX2:.*]] = fir.embox %[[DT2]] : (!fir.ref<!fir.type<_QMpolymorphic_testTp2{a:i32,b:i32,c:f32}>>) -> !fir.box<!fir.type<_QMpolymorphic_testTp2{a:i32,b:i32,c:f32}>>
! CHECK: %[[CLASS2:.*]] = fir.convert %[[BOX2]] : (!fir.box<!fir.type<_QMpolymorphic_testTp2{a:i32,b:i32,c:f32}>>) -> !fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>
! CHECK: fir.call @_QMpolymorphic_testPprint(%[[CLASS2]]) : (!fir.class<!fir.type<_QMpolymorphic_testTp1{a:i32,b:i32}>>) -> ()
end module

View File

@ -117,3 +117,32 @@ TEST_F(FIRTypesTest, isUnlimitedPolymorphicTypeTest) {
EXPECT_FALSE(fir::isUnlimitedPolymorphicType(noneTy));
EXPECT_FALSE(fir::isUnlimitedPolymorphicType(seqNoneTy));
}
// Test fir::isBoxedRecordType from flang/Optimizer/Dialect/FIRType.h.
TEST_F(FIRTypesTest, isBoxedRecordType) {
mlir::Type recTy = fir::RecordType::get(&context, "dt");
mlir::Type seqRecTy =
fir::SequenceType::get({fir::SequenceType::getUnknownExtent()}, recTy);
mlir::Type ty = fir::BoxType::get(recTy);
EXPECT_TRUE(fir::isBoxedRecordType(ty));
EXPECT_TRUE(fir::isBoxedRecordType(fir::ReferenceType::get(ty)));
// TYPE(T), ALLOCATABLE
ty = fir::BoxType::get(fir::HeapType::get(recTy));
EXPECT_TRUE(fir::isBoxedRecordType(ty));
// TYPE(T), POINTER
ty = fir::BoxType::get(fir::PointerType::get(recTy));
EXPECT_TRUE(fir::isBoxedRecordType(ty));
// TYPE(T), DIMENSION(10)
ty = fir::BoxType::get(fir::SequenceType::get({10}, recTy));
EXPECT_TRUE(fir::isBoxedRecordType(ty));
// TYPE(T), DIMENSION(:)
ty = fir::BoxType::get(seqRecTy);
EXPECT_TRUE(fir::isBoxedRecordType(ty));
EXPECT_FALSE(fir::isBoxedRecordType(fir::BoxType::get(
fir::ReferenceType::get(mlir::IntegerType::get(&context, 32)))));
}