Skip to content

Commit a09571e

Browse files
authored
[flang] represent ABSTRACT in fir.type_info (#170109)
This patch keeps information about ABSTRACT derived types and DEFERRED type bound procedures inside fir.type_info dispatch tables. This is part of the effort to delay generation of runtime type info global by keeping the type information in a more condense fashion inside fir.type_info (which is also easier to use for any potential optimizations).
1 parent 9605666 commit a09571e

File tree

5 files changed

+72
-11
lines changed

5 files changed

+72
-11
lines changed

flang/include/flang/Optimizer/Dialect/FIROps.td

Lines changed: 26 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -3107,9 +3107,12 @@ def fir_TypeInfoOp : fir_Op<"type_info",
31073107
between method identifiers and corresponding `FuncOp` symbols.
31083108
The ordering of associations in the map is determined by the front end.
31093109

3110-
The "no_init" flag indicates that this type has no components requiring default
3111-
initialization (including setting allocatable component to a clean deallocated
3112-
state).
3110+
The "abstract" flag indicates that this type is an ABSTRACT derived type and
3111+
that it cannot be instantiated.
3112+
3113+
The "no_init" flag indicates that this type has no components requiring
3114+
default initialization (including setting allocatable component to a clean
3115+
deallocated state).
31133116

31143117
The "no_destroy" flag indicates that there are no allocatable components
31153118
that require deallocation.
@@ -3118,7 +3121,8 @@ def fir_TypeInfoOp : fir_Op<"type_info",
31183121
for its parents ,or for components.
31193122

31203123
```
3121-
fir.type_info @_QMquuzTfoo noinit nofinal : !fir.type<_QMquuzTfoo{i:i32}> dispatch_table {
3124+
fir.type_info @_QMquuzTfoo abstract noinit nofinal
3125+
: !fir.type<_QMquuzTfoo{i:i32}> dispatch_table {
31223126
fir.dt_entry method1, @_QFNMquuzTfooPmethod1AfooR
31233127
fir.dt_entry method2, @_QFNMquuzTfooPmethod2AfooII
31243128
}
@@ -3129,6 +3133,7 @@ def fir_TypeInfoOp : fir_Op<"type_info",
31293133
SymbolNameAttr:$sym_name,
31303134
TypeAttr:$type,
31313135
OptionalAttr<TypeAttr>:$parent_type,
3136+
UnitAttr:$abstract,
31323137
UnitAttr:$no_init,
31333138
UnitAttr:$no_destroy,
31343139
UnitAttr:$no_final
@@ -3147,8 +3152,9 @@ def fir_TypeInfoOp : fir_Op<"type_info",
31473152
];
31483153

31493154
let assemblyFormat = [{
3150-
$sym_name (`noinit` $no_init^)? (`nodestroy` $no_destroy^)?
3151-
(`nofinal` $no_final^)? (`extends` $parent_type^)? attr-dict `:` $type
3155+
$sym_name (`abstract` $abstract^)? (`noinit` $no_init^)?
3156+
(`nodestroy` $no_destroy^)? (`nofinal` $no_final^)?
3157+
(`extends` $parent_type^)? attr-dict `:` $type
31523158
(`dispatch_table` $dispatch_table^)?
31533159
(`component_info` $component_info^)?
31543160
}];
@@ -3174,23 +3180,34 @@ def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"TypeInfoOp">]> {
31743180
let summary = "map entry in a dispatch table";
31753181

31763182
let description = [{
3177-
An entry in a dispatch table. Allows a function symbol to be bound
3178-
to a specifier method identifier. A dispatch operation uses the dynamic
3183+
An entry in a dispatch table. Allows a function symbol to be bound
3184+
to a specifier method identifier. A dispatch operation uses the dynamic
31793185
type of a distinguished argument to determine an exact dispatch table
31803186
and uses the method identifier to select the type-bound procedure to
31813187
be called.
31823188

3189+
The optional "deferred" flag indicates that the binding is a DEFERRED
3190+
type-bound procedure (declared but without an implementation at this
3191+
type level).
3192+
31833193
```
3194+
// Non-deferred binding
31843195
fir.dt_entry method_name, @uniquedProcedure
3196+
3197+
// Deferred binding
3198+
fir.dt_entry method_name, @uniquedProcedure deferred
31853199
```
31863200
}];
31873201

3188-
let arguments = (ins StrAttr:$method, SymbolRefAttr:$proc);
3202+
let arguments = (ins StrAttr:$method, SymbolRefAttr:$proc, UnitAttr:$deferred);
31893203

31903204
let hasCustomAssemblyFormat = 1;
31913205

31923206
let extraClassDeclaration = [{
31933207
static constexpr llvm::StringRef getProcAttrNameStr() { return "proc"; }
3208+
static constexpr llvm::StringRef getDeferredAttrNameStr() {
3209+
return "deferred";
3210+
}
31943211
}];
31953212
}
31963213

flang/lib/Lower/Bridge.cpp

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -307,7 +307,11 @@ class TypeInfoConverter {
307307
if (!insertPointIfCreated.isSet())
308308
return; // fir.type_info was already built in a previous call.
309309

310-
// Set init, destroy, and nofinal attributes.
310+
// Set abstract, init, destroy, and nofinal attributes.
311+
const Fortran::semantics::Symbol &dtSymbol = info.typeSpec.typeSymbol();
312+
if (dtSymbol.attrs().test(Fortran::semantics::Attr::ABSTRACT))
313+
dt->setAttr(dt.getAbstractAttrName(), builder.getUnitAttr());
314+
311315
if (!info.typeSpec.HasDefaultInitialization(/*ignoreAllocatable=*/false,
312316
/*ignorePointer=*/false))
313317
dt->setAttr(dt.getNoInitAttrName(), builder.getUnitAttr());
@@ -331,10 +335,14 @@ class TypeInfoConverter {
331335
if (details.numPrivatesNotOverridden() > 0)
332336
tbpName += "."s + std::to_string(details.numPrivatesNotOverridden());
333337
std::string bindingName = converter.mangleName(details.symbol());
334-
fir::DTEntryOp::create(
338+
auto dtEntry = fir::DTEntryOp::create(
335339
builder, info.loc,
336340
mlir::StringAttr::get(builder.getContext(), tbpName),
337341
mlir::SymbolRefAttr::get(builder.getContext(), bindingName));
342+
// Propagate DEFERRED attribute on the binding to fir.dt_entry.
343+
if (binding.get().attrs().test(Fortran::semantics::Attr::DEFERRED))
344+
dtEntry->setAttr(fir::DTEntryOp::getDeferredAttrNameStr(),
345+
builder.getUnitAttr());
338346
}
339347
fir::FirEndOp::create(builder, info.loc);
340348
}

flang/lib/Optimizer/Dialect/FIROps.cpp

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3230,11 +3230,19 @@ mlir::ParseResult fir::DTEntryOp::parse(mlir::OpAsmParser &parser,
32303230
parser.parseAttribute(calleeAttr, fir::DTEntryOp::getProcAttrNameStr(),
32313231
result.attributes))
32323232
return mlir::failure();
3233+
3234+
// Optional "deferred" keyword.
3235+
if (succeeded(parser.parseOptionalKeyword("deferred"))) {
3236+
result.addAttribute(fir::DTEntryOp::getDeferredAttrNameStr(),
3237+
parser.getBuilder().getUnitAttr());
3238+
}
32333239
return mlir::success();
32343240
}
32353241

32363242
void fir::DTEntryOp::print(mlir::OpAsmPrinter &p) {
32373243
p << ' ' << getMethodAttr() << ", " << getProcAttr();
3244+
if ((*this)->getAttr(fir::DTEntryOp::getDeferredAttrNameStr()))
3245+
p << " deferred";
32383246
}
32393247

32403248
//===----------------------------------------------------------------------===//

flang/test/Fir/fir-ops.fir

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -467,6 +467,13 @@ fir.type_info @cpinfo : !fir.type<cpinfo{comp_i:!fir.array<10x20xi32>}> componen
467467
fir.dt_component "component_info" lbs [2, 3]
468468
}
469469

470+
// CHECK-LABEL: fir.type_info @abstract_dispatch_tbl abstract : !fir.type<abstract_dispatch_tbl{i:i32}> dispatch_table {
471+
// CHECK: fir.dt_entry "deferred_method", @deferred_impl deferred
472+
// CHECK: }
473+
fir.type_info @abstract_dispatch_tbl abstract : !fir.type<abstract_dispatch_tbl{i:i32}> dispatch_table {
474+
fir.dt_entry "deferred_method", @deferred_impl deferred
475+
}
476+
470477
// CHECK-LABEL: func @compare_complex(
471478
// CHECK-SAME: [[VAL_151:%.*]]: complex<f128>, [[VAL_152:%.*]]: complex<f128>) {
472479
func.func @compare_complex(%a : complex<f128>, %b : complex<f128>) {
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
! Test lowering of ASBTRACT type to fir.type_info
2+
! RUN: %flang_fc1 -emit-hlfir %s -o - | FileCheck %s
3+
4+
module m_abstract_info
5+
type, abstract :: abstract_type
6+
contains
7+
procedure(proc_iface), nopass, deferred :: proc
8+
end type
9+
interface
10+
subroutine proc_iface()
11+
end subroutine
12+
end interface
13+
end module
14+
15+
subroutine test(x)
16+
use m_abstract_info, only : abstract_type
17+
class(abstract_type) :: x
18+
end subroutine
19+
20+
!CHECK-LABEL: fir.type_info @_QMm_abstract_infoTabstract_type abstract noinit nodestroy nofinal : !fir.type<_QMm_abstract_infoTabstract_type> dispatch_table {
21+
!CHECK: fir.dt_entry "proc", @_QPproc_iface deferred

0 commit comments

Comments
 (0)