forked from OSchip/llvm-project
[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:
parent
a835b92e6c
commit
0cf70a33f2
|
@ -38,6 +38,9 @@ public:
|
||||||
/// Returns the element type of this box type.
|
/// Returns the element type of this box type.
|
||||||
mlir::Type getEleTy() const;
|
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.
|
/// Methods for support type inquiry through isa, cast, and dyn_cast.
|
||||||
static bool classof(mlir::Type type);
|
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.
|
/// Return true iff `ty` is the type of an ALLOCATABLE entity or value.
|
||||||
bool isAllocatableType(mlir::Type ty);
|
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
|
/// Return true iff `ty` is the type of an polymorphic entity or
|
||||||
/// value.
|
/// value.
|
||||||
bool isPolymorphicType(mlir::Type ty);
|
bool isPolymorphicType(mlir::Type ty);
|
||||||
|
|
|
@ -916,7 +916,8 @@ mlir::LogicalResult fir::ConvertOp::verify() {
|
||||||
(isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
|
(isPointerCompatible(inType) && isIntegerCompatible(outType)) ||
|
||||||
(inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
|
(inType.isa<fir::BoxType>() && outType.isa<fir::BoxType>()) ||
|
||||||
(inType.isa<fir::BoxProcType>() && outType.isa<fir::BoxProcType>()) ||
|
(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 mlir::success();
|
||||||
return emitOpError("invalid type conversion");
|
return emitOpError("invalid type conversion");
|
||||||
}
|
}
|
||||||
|
|
|
@ -262,6 +262,18 @@ bool isAllocatableType(mlir::Type ty) {
|
||||||
return false;
|
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) {
|
static bool isAssumedType(mlir::Type ty) {
|
||||||
if (auto boxTy = ty.dyn_cast<fir::BoxType>()) {
|
if (auto boxTy = ty.dyn_cast<fir::BoxType>()) {
|
||||||
if (boxTy.getEleTy().isa<mlir::NoneType>())
|
if (boxTy.getEleTy().isa<mlir::NoneType>())
|
||||||
|
@ -289,17 +301,8 @@ bool isUnlimitedPolymorphicType(mlir::Type ty) {
|
||||||
if (auto clTy = ty.dyn_cast<fir::ClassType>()) {
|
if (auto clTy = ty.dyn_cast<fir::ClassType>()) {
|
||||||
if (clTy.getEleTy().isa<mlir::NoneType>())
|
if (clTy.getEleTy().isa<mlir::NoneType>())
|
||||||
return true;
|
return true;
|
||||||
mlir::Type innerType =
|
mlir::Type innerType = clTy.unwrapInnerType();
|
||||||
llvm::TypeSwitch<mlir::Type, mlir::Type>(clTy.getEleTy())
|
return innerType && innerType.isa<mlir::NoneType>();
|
||||||
.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>();
|
|
||||||
}
|
}
|
||||||
// TYPE(*)
|
// TYPE(*)
|
||||||
return isAssumedType(ty);
|
return isAssumedType(ty);
|
||||||
|
@ -982,6 +985,17 @@ mlir::Type BaseBoxType::getEleTy() const {
|
||||||
[](auto type) { return type.getEleTy(); });
|
[](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
|
// FIROpsDialect
|
||||||
//===----------------------------------------------------------------------===//
|
//===----------------------------------------------------------------------===//
|
||||||
|
|
|
@ -6,6 +6,8 @@ module polymorphic_test
|
||||||
type p1
|
type p1
|
||||||
integer :: a
|
integer :: a
|
||||||
integer :: b
|
integer :: b
|
||||||
|
contains
|
||||||
|
procedure :: print
|
||||||
end type
|
end type
|
||||||
|
|
||||||
type, extends(p1) :: p2
|
type, extends(p1) :: p2
|
||||||
|
@ -27,4 +29,25 @@ module polymorphic_test
|
||||||
! CHECK: %[[LOAD:.*]] = fir.load %[[COORD]] : !fir.ref<i32>
|
! CHECK: %[[LOAD:.*]] = fir.load %[[COORD]] : !fir.ref<i32>
|
||||||
! CHECK: %{{.*}} = fir.call @_FortranAioOutputInteger32(%{{.*}}, %[[LOAD]]) : (!fir.ref<i8>, i32) -> i1
|
! 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
|
end module
|
||||||
|
|
|
@ -117,3 +117,32 @@ TEST_F(FIRTypesTest, isUnlimitedPolymorphicTypeTest) {
|
||||||
EXPECT_FALSE(fir::isUnlimitedPolymorphicType(noneTy));
|
EXPECT_FALSE(fir::isUnlimitedPolymorphicType(noneTy));
|
||||||
EXPECT_FALSE(fir::isUnlimitedPolymorphicType(seqNoneTy));
|
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)))));
|
||||||
|
}
|
||||||
|
|
Loading…
Reference in New Issue