Skip to content

Commit

Permalink
[flang][nfc] replace fir.dispatch_table with more generic fir.type_in…
Browse files Browse the repository at this point in the history
…fo (#68309)

The goal is to progressively propagate all the derived type info that is
currently in the runtime type info globals into a FIR operation that can
be easily queried and used by FIR/HLFIR passes.

When this will be complete, the last step will be to stop generating the
runtime info global in lowering, but to do that later in or just before
codegen to keep the FIR files readable (on the added type-info.f90
tests, the lowered runtime info globals takes a whooping 2.6 millions
characters on 1600 lines of the FIR textual output. The fir.type_info that
contains all the info required to generate those globals for such
"trivial" types takes 1721 characters on 9 lines).

So far this patch simply starts by replacing the fir.dispatch_table
operation by the fir.type_info operation and to add the noinit/
nofinal/nodestroy flags to it. These flags will soon be used in HLFIR to
better rewrite hlfir.assign with derived types.
  • Loading branch information
jeanPerier committed Oct 6, 2023
1 parent 98341df commit 4ccd57d
Show file tree
Hide file tree
Showing 16 changed files with 292 additions and 258 deletions.
10 changes: 4 additions & 6 deletions flang/include/flang/Lower/AbstractConverter.h
Original file line number Diff line number Diff line change
Expand Up @@ -212,12 +212,10 @@ class AbstractConverter {

/// Register a runtime derived type information object symbol to ensure its
/// object will be generated as a global.
virtual void registerRuntimeTypeInfo(mlir::Location loc,
SymbolRef typeInfoSym) = 0;

virtual void registerDispatchTableInfo(
mlir::Location loc,
const Fortran::semantics::DerivedTypeSpec *typeSpec) = 0;
virtual void
registerTypeInfo(mlir::Location loc, SymbolRef typeInfoSym,
const Fortran::semantics::DerivedTypeSpec &typeSpec,
fir::RecordType type) = 0;

//===--------------------------------------------------------------------===//
// Locations
Expand Down
5 changes: 0 additions & 5 deletions flang/include/flang/Optimizer/Builder/FIRBuilder.h
Original file line number Diff line number Diff line change
Expand Up @@ -254,11 +254,6 @@ class FirOpBuilder : public mlir::OpBuilder, public mlir::OpBuilder::Listener {
bodyBuilder, linkage);
}

/// Create a fir::DispatchTable operation.
fir::DispatchTableOp createDispatchTableOp(mlir::Location loc,
llvm::StringRef name,
llvm::StringRef parentName);

/// Convert a StringRef string into a fir::StringLitOp.
fir::StringLitOp createStringLitOp(mlir::Location loc,
llvm::StringRef string);
Expand Down
65 changes: 47 additions & 18 deletions flang/include/flang/Optimizer/Dialect/FIROps.td
Original file line number Diff line number Diff line change
Expand Up @@ -2778,6 +2778,10 @@ def fir_GlobalOp : fir_Op<"global", [IsolatedFromAbove, Symbol]> {
(*this)->getAttrOfType<mlir::StringAttr>(
mlir::SymbolTable::getSymbolAttrName()).getValue());
}

bool isInitialized() {
return getInitVal() || hasInitializationBody();
}
}];
}

Expand Down Expand Up @@ -2809,20 +2813,31 @@ def fir_GlobalLenOp : fir_Op<"global_len", []> {

def ImplicitFirTerminator : SingleBlockImplicitTerminator<"FirEndOp">;

def fir_DispatchTableOp : fir_Op<"dispatch_table",
def fir_TypeInfoOp : fir_Op<"type_info",
[IsolatedFromAbove, Symbol, ImplicitFirTerminator]> {
let summary = "Dispatch table definition";
let summary = "Derived type information";

let description = [{
Define a dispatch table for a derived type with type-bound procedures.
Define extra information about a !fir.type<> that represents
a Fortran derived type.

A dispatch table is an untyped symbol that contains a list of associations
The optional dispatch table region defines a dispatch table with the derived
type type-bound procedures. It contains a list of associations
between method identifiers and corresponding `FuncOp` symbols.

The ordering of associations in the map is determined by the front end.

The "no_init" flag indicates that this type has no components requiring default
initialization (including setting allocatable component to a clean deallocated
state).

The "no_destroy" flag indicates that there are no allocatable components
that require deallocation.

The "no_final" flag indicates that there are no final methods for this type,
for its parents ,or for components.

```mlir
fir.dispatch_table @_QDTMquuzTfoo {
fir.type_info @_QMquuzTfoo noinit nofinal : !fir.type<_QMquuzTfoo{i:i32}> dispatch_table {
fir.dt_entry method1, @_QFNMquuzTfooPmethod1AfooR
fir.dt_entry method2, @_QFNMquuzTfooPmethod2AfooII
}
Expand All @@ -2831,32 +2846,46 @@ def fir_DispatchTableOp : fir_Op<"dispatch_table",

let arguments = (ins
SymbolNameAttr:$sym_name,
OptionalAttr<StrAttr>:$parent
TypeAttr:$type,
OptionalAttr<TypeAttr>:$parent_type,
UnitAttr:$no_init,
UnitAttr:$no_destroy,
UnitAttr:$no_final
);

let hasCustomAssemblyFormat = 1;
let hasVerifier = 1;

let regions = (region AnyRegion:$region);
let regions = (region MaxSizedRegion<1>:$dispatch_table);

let skipDefaultBuilders = 1;
let builders = [
OpBuilder<(ins "llvm::StringRef":$name, "mlir::Type":$type,
"llvm::StringRef":$parent,
OpBuilder<(ins "fir::RecordType":$type, "fir::RecordType":$parent_type,
CArg<"llvm::ArrayRef<mlir::NamedAttribute>", "{}">:$attrs)>
];

let extraClassDeclaration = [{
static constexpr llvm::StringRef getParentAttrNameStr() { return "parent"; }
static constexpr llvm::StringRef getExtendsKeyword() { return "extends"; }
let assemblyFormat = [{
$sym_name (`noinit` $no_init^)? (`nodestroy` $no_destroy^)?
(`nofinal` $no_final^)? (`extends` $parent_type^)? attr-dict `:` $type
(`dispatch_table` $dispatch_table^)?
}];

mlir::Block &getBlock() {
return getRegion().front();
let extraClassDeclaration = [{
fir::RecordType getRecordType() {
return mlir::cast<fir::RecordType>(getType());
}
fir::RecordType getIfParentType() {
if (auto parentType = getParentType())
return mlir::cast<fir::RecordType>(*parentType);
return {};
}
std::optional<llvm::StringRef> getIfParentName() {
if (auto parentType = getIfParentType())
return parentType.getName();
return std::nullopt;
}
}];
}

def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"DispatchTableOp">]> {
def fir_DTEntryOp : fir_Op<"dt_entry", [HasParent<"TypeInfoOp">]> {
let summary = "map entry in a dispatch table";

let description = [{
Expand Down
15 changes: 8 additions & 7 deletions flang/include/flang/Optimizer/Support/Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,21 +36,22 @@ using BindingTables = llvm::DenseMap<llvm::StringRef, BindingTable>;
inline void buildBindingTables(BindingTables &bindingTables,
mlir::ModuleOp mod) {

// The binding tables are defined in FIR from lowering as fir.dispatch_table
// operation. Go through each binding tables and store the procedure name and
// The binding tables are defined in FIR after lowering inside fir.type_info
// operations. Go through each binding tables and store the procedure name and
// binding index for later use by the fir.dispatch conversion pattern.
for (auto dispatchTableOp : mod.getOps<fir::DispatchTableOp>()) {
for (auto typeInfo : mod.getOps<fir::TypeInfoOp>()) {
unsigned bindingIdx = 0;
BindingTable bindings;
if (dispatchTableOp.getRegion().empty()) {
bindingTables[dispatchTableOp.getSymName()] = bindings;
if (typeInfo.getDispatchTable().empty()) {
bindingTables[typeInfo.getSymName()] = bindings;
continue;
}
for (auto dtEntry : dispatchTableOp.getBlock().getOps<fir::DTEntryOp>()) {
for (auto dtEntry :
typeInfo.getDispatchTable().front().getOps<fir::DTEntryOp>()) {
bindings[dtEntry.getMethod()] = bindingIdx;
++bindingIdx;
}
bindingTables[dispatchTableOp.getSymName()] = bindings;
bindingTables[typeInfo.getSymName()] = bindings;
}
}

Expand Down

0 comments on commit 4ccd57d

Please sign in to comment.