Skip to content

Commit 87bd946

Browse files
committed
[flang] Lowering and implementation for extends_type_of
Add implementation and loweirng for the extends_type_of intrinsic. The standard mentions this: otherwise if the dynamic type of A or MOLD is extensible, the result is true if and only if the dynamic type of A is an extension type of the dynamic type of MOLD. Which could be interpreted that `extends_type_of(a, a)` could be false since a type is not an extension of itself. Gfortran result for this is `true` so the same behavior is applied here as well. Depends on D141364 Reviewed By: jeanPerier, PeteSteinfeld Differential Revision: https://reviews.llvm.org/D141376
1 parent 4bb1751 commit 87bd946

File tree

6 files changed

+131
-0
lines changed

6 files changed

+131
-0
lines changed

flang/include/flang/Optimizer/Builder/Runtime/Derived.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,5 +40,8 @@ void genNullifyDerivedType(fir::FirOpBuilder &builder, mlir::Location loc,
4040
mlir::Value genSameTypeAs(fir::FirOpBuilder &builder, mlir::Location loc,
4141
mlir::Value a, mlir::Value b);
4242

43+
mlir::Value genExtendsTypeOf(fir::FirOpBuilder &builder, mlir::Location loc,
44+
mlir::Value a, mlir::Value b);
45+
4346
} // namespace fir::runtime
4447
#endif // FORTRAN_OPTIMIZER_BUILDER_RUNTIME_DERIVED_H

flang/include/flang/Runtime/derived-api.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,9 @@ bool RTNAME(ClassIs)(const Descriptor &, const typeInfo::DerivedType &);
4949
// Perform the test of the SAME_TYPE_AS intrinsic.
5050
bool RTNAME(SameTypeAs)(const Descriptor &, const Descriptor &);
5151

52+
// Perform the test of the EXTENDS_TYPE_OF intrinsic.
53+
bool RTNAME(ExtendsTypeOf)(const Descriptor &, const Descriptor &);
54+
5255
} // extern "C"
5356
} // namespace Fortran::runtime
5457
#endif // FORTRAN_RUNTIME_DERIVED_API_H_

flang/lib/Lower/IntrinsicCall.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -501,6 +501,8 @@ struct IntrinsicLibrary {
501501
fir::ExtendedValue genEoshift(mlir::Type, llvm::ArrayRef<fir::ExtendedValue>);
502502
void genExit(llvm::ArrayRef<fir::ExtendedValue>);
503503
mlir::Value genExponent(mlir::Type, llvm::ArrayRef<mlir::Value>);
504+
fir::ExtendedValue genExtendsTypeOf(mlir::Type,
505+
llvm::ArrayRef<fir::ExtendedValue>);
504506
template <Extremum, ExtremumBehavior>
505507
mlir::Value genExtremum(mlir::Type, llvm::ArrayRef<mlir::Value>);
506508
mlir::Value genFloor(mlir::Type, llvm::ArrayRef<mlir::Value>);
@@ -815,6 +817,10 @@ static constexpr IntrinsicHandler handlers[]{
815817
{{{"status", asValue, handleDynamicOptional}}},
816818
/*isElemental=*/false},
817819
{"exponent", &I::genExponent},
820+
{"extends_type_of",
821+
&I::genExtendsTypeOf,
822+
{{{"a", asBox}, {"mold", asBox}}},
823+
/*isElemental=*/false},
818824
{"findloc",
819825
&I::genFindloc,
820826
{{{"array", asBox},
@@ -3292,6 +3298,18 @@ mlir::Value IntrinsicLibrary::genExponent(mlir::Type resultType,
32923298
fir::getBase(args[0])));
32933299
}
32943300

3301+
// EXTENDS_TYPE_OF
3302+
fir::ExtendedValue
3303+
IntrinsicLibrary::genExtendsTypeOf(mlir::Type resultType,
3304+
llvm::ArrayRef<fir::ExtendedValue> args) {
3305+
assert(args.size() == 2);
3306+
3307+
return builder.createConvert(
3308+
loc, resultType,
3309+
fir::runtime::genExtendsTypeOf(builder, loc, fir::getBase(args[0]),
3310+
fir::getBase(args[1])));
3311+
}
3312+
32953313
// FINDLOC
32963314
fir::ExtendedValue
32973315
IntrinsicLibrary::genFindloc(mlir::Type resultType,

flang/lib/Optimizer/Builder/Runtime/Derived.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,3 +72,13 @@ mlir::Value fir::runtime::genSameTypeAs(fir::FirOpBuilder &builder,
7272
auto args = fir::runtime::createArguments(builder, loc, fTy, a, b);
7373
return builder.create<fir::CallOp>(loc, sameTypeAsFunc, args).getResult(0);
7474
}
75+
76+
mlir::Value fir::runtime::genExtendsTypeOf(fir::FirOpBuilder &builder,
77+
mlir::Location loc, mlir::Value a,
78+
mlir::Value mold) {
79+
mlir::func::FuncOp extendsTypeOfFunc =
80+
fir::runtime::getRuntimeFunc<mkRTKey(ExtendsTypeOf)>(loc, builder);
81+
auto fTy = extendsTypeOfFunc.getFunctionType();
82+
auto args = fir::runtime::createArguments(builder, loc, fTy, a, mold);
83+
return builder.create<fir::CallOp>(loc, extendsTypeOfFunc, args).getResult(0);
84+
}

flang/runtime/derived-api.cpp

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,11 @@ static bool CompareDerivedTypeNames(const Descriptor &a, const Descriptor &b) {
7272
return false;
7373
}
7474

75+
inline bool CompareDerivedType(
76+
const typeInfo::DerivedType *a, const typeInfo::DerivedType *b) {
77+
return a == b || CompareDerivedTypeNames(a->name(), b->name());
78+
}
79+
7580
static const typeInfo::DerivedType *GetDerivedType(const Descriptor &desc) {
7681
if (const DescriptorAddendum * addendum{desc.Addendum()}) {
7782
if (const auto *derived{addendum->derivedType()}) {
@@ -96,6 +101,49 @@ bool RTNAME(SameTypeAs)(const Descriptor &a, const Descriptor &b) {
96101
return CompareDerivedTypeNames(derivedTypeA->name(), derivedTypeB->name());
97102
}
98103

104+
bool RTNAME(ExtendsTypeOf)(const Descriptor &a, const Descriptor &mold) {
105+
const typeInfo::DerivedType *derivedTypeA{GetDerivedType(a)};
106+
const typeInfo::DerivedType *derivedTypeMold{GetDerivedType(mold)};
107+
108+
// If MOLD is unlimited polymorphic and is either a disassociated pointer or
109+
// unallocated allocatable, the result is true.
110+
// Unlimited polymorphic descriptors are initialized with a CFI_type_other
111+
// type.
112+
if (mold.type().raw() == CFI_type_other &&
113+
(mold.IsAllocatable() || mold.IsPointer()) &&
114+
derivedTypeMold == nullptr) {
115+
return true;
116+
}
117+
118+
// If A is unlimited polymorphic and is either a disassociated pointer or
119+
// unallocated allocatable, the result is false.
120+
// Unlimited polymorphic descriptors are initialized with a CFI_type_other
121+
// type.
122+
if (a.type().raw() == CFI_type_other &&
123+
(a.IsAllocatable() || a.IsPointer()) && derivedTypeA == nullptr) {
124+
return false;
125+
}
126+
127+
if (derivedTypeA == nullptr || derivedTypeMold == nullptr) {
128+
return false;
129+
}
130+
131+
// Otherwise if the dynamic type of A or MOLD is extensible, the result is
132+
// true if and only if the dynamic type of A is an extension type of the
133+
// dynamic type of MOLD.
134+
if (CompareDerivedType(derivedTypeA, derivedTypeMold)) {
135+
return true;
136+
}
137+
const typeInfo::DerivedType *parent{derivedTypeA->GetParentType()};
138+
while (parent) {
139+
if (CompareDerivedType(parent, derivedTypeMold)) {
140+
return true;
141+
}
142+
parent = parent->GetParentType();
143+
}
144+
return false;
145+
}
146+
99147
// TODO: Assign()
100148

101149
} // extern "C"
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
! RUN: bbc -emit-fir -polymorphic-type %s -o - | FileCheck %s
2+
3+
module extends_type_of_mod
4+
5+
type p1
6+
integer :: a
7+
end type
8+
9+
type, extends(p1) :: p2
10+
integer :: b
11+
end type
12+
13+
type k1(a)
14+
integer, kind :: a
15+
end type
16+
17+
contains
18+
subroutine is_extended_type(a, b)
19+
class(*) :: a
20+
class(*) :: b
21+
22+
if (extends_type_of(a, b)) then
23+
print*, 'extends_type_of ok'
24+
else
25+
print*, 'extends_type_of failed'
26+
end if
27+
end subroutine
28+
29+
! CHECK-LABEL: func.func @_QMextends_type_of_modPis_extended_type(
30+
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<none> {fir.bindc_name = "a"}, %[[ARG1:.*]]: !fir.class<none> {fir.bindc_name = "b"}) {
31+
! CHECK: %[[BOX0:.*]] = fir.convert %[[ARG0]] : (!fir.class<none>) -> !fir.box<none>
32+
! CHECK: %[[BOX1:.*]] = fir.convert %[[ARG1]] : (!fir.class<none>) -> !fir.box<none>
33+
! CHECK: %{{.*}} = fir.call @_FortranAExtendsTypeOf(%[[BOX0]], %[[BOX1]]) {{.*}} : (!fir.box<none>, !fir.box<none>) -> i1
34+
35+
end module
36+
37+
program test
38+
use extends_type_of_mod
39+
type(p1) :: p, r
40+
type(p2) :: q
41+
type(k1(10)) :: k10
42+
type(k1(20)) :: k20
43+
44+
call is_extended_type(p, p)
45+
call is_extended_type(p, q)
46+
call is_extended_type(p, r)
47+
call is_extended_type(q, p)
48+
call is_extended_type(k10, k20)
49+
end

0 commit comments

Comments
 (0)