|
46 | 46 | #include "flang/Optimizer/Transforms/Passes.h" |
47 | 47 | #include "flang/Parser/parse-tree.h" |
48 | 48 | #include "flang/Runtime/iostat.h" |
| 49 | +#include "flang/Semantics/runtime-type-info.h" |
49 | 50 | #include "flang/Semantics/tools.h" |
50 | 51 | #include "mlir/Dialect/ControlFlow/IR/ControlFlowOps.h" |
51 | 52 | #include "mlir/IR/PatternMatch.h" |
52 | 53 | #include "mlir/Parser/Parser.h" |
53 | 54 | #include "mlir/Transforms/RegionUtils.h" |
| 55 | +#include "llvm/ADT/StringSet.h" |
54 | 56 | #include "llvm/Support/CommandLine.h" |
55 | 57 | #include "llvm/Support/Debug.h" |
56 | 58 | #include "llvm/Support/ErrorHandling.h" |
@@ -193,6 +195,67 @@ class RuntimeTypeInfoConverter { |
193 | 195 | llvm::SmallSetVector<Fortran::semantics::SymbolRef, 64> seen; |
194 | 196 | }; |
195 | 197 |
|
| 198 | +class DispatchTableConverter { |
| 199 | + struct DispatchTableInfo { |
| 200 | + const Fortran::semantics::DerivedTypeSpec *typeSpec; |
| 201 | + mlir::Location loc; |
| 202 | + }; |
| 203 | + |
| 204 | +public: |
| 205 | + void registerTypeSpec(mlir::Location loc, |
| 206 | + const Fortran::semantics::DerivedTypeSpec *typeSpec) { |
| 207 | + assert(typeSpec && "type spec is null"); |
| 208 | + std::string dtName = Fortran::lower::mangle::mangleName(*typeSpec); |
| 209 | + if (seen.contains(dtName) || dtName.find("__fortran") != std::string::npos) |
| 210 | + return; |
| 211 | + seen.insert(dtName); |
| 212 | + registeredDispatchTableInfo.emplace_back(DispatchTableInfo{typeSpec, loc}); |
| 213 | + } |
| 214 | + |
| 215 | + void createDispatchTableOps(Fortran::lower::AbstractConverter &converter) { |
| 216 | + for (const DispatchTableInfo &info : registeredDispatchTableInfo) { |
| 217 | + std::string dtName = Fortran::lower::mangle::mangleName(*info.typeSpec); |
| 218 | + const Fortran::semantics::DerivedTypeSpec *parent = |
| 219 | + Fortran::evaluate::GetParentTypeSpec(*info.typeSpec); |
| 220 | + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); |
| 221 | + fir::DispatchTableOp dt = builder.createDispatchTableOp( |
| 222 | + info.loc, dtName, |
| 223 | + parent ? Fortran::lower::mangle::mangleName(*parent) : ""); |
| 224 | + auto insertPt = builder.saveInsertionPoint(); |
| 225 | + |
| 226 | + std::vector<const Fortran::semantics::Symbol *> bindings = |
| 227 | + Fortran::semantics::CollectBindings(*info.typeSpec->scope()); |
| 228 | + |
| 229 | + if (!bindings.empty()) |
| 230 | + builder.createBlock(&dt.getRegion()); |
| 231 | + |
| 232 | + for (const Fortran::semantics::Symbol *binding : bindings) { |
| 233 | + const auto *details = |
| 234 | + binding->detailsIf<Fortran::semantics::ProcBindingDetails>(); |
| 235 | + std::string bindingName = |
| 236 | + Fortran::lower::mangle::mangleName(details->symbol()); |
| 237 | + builder.create<fir::DTEntryOp>( |
| 238 | + info.loc, |
| 239 | + mlir::StringAttr::get(builder.getContext(), |
| 240 | + binding->name().ToString()), |
| 241 | + mlir::SymbolRefAttr::get(builder.getContext(), bindingName)); |
| 242 | + } |
| 243 | + if (!bindings.empty()) |
| 244 | + builder.create<fir::FirEndOp>(info.loc); |
| 245 | + builder.restoreInsertionPoint(insertPt); |
| 246 | + } |
| 247 | + registeredDispatchTableInfo.clear(); |
| 248 | + } |
| 249 | + |
| 250 | +private: |
| 251 | + /// Store the semantic DerivedTypeSpec that will be required to generate the |
| 252 | + /// dispatch table. |
| 253 | + llvm::SmallVector<DispatchTableInfo> registeredDispatchTableInfo; |
| 254 | + |
| 255 | + /// Track processed type specs to avoid multiple creation. |
| 256 | + llvm::StringSet<> seen; |
| 257 | +}; |
| 258 | + |
196 | 259 | using IncrementLoopNestInfo = llvm::SmallVector<IncrementLoopInfo, 8>; |
197 | 260 | } // namespace |
198 | 261 |
|
@@ -270,6 +333,10 @@ class FirConverter : public Fortran::lower::AbstractConverter { |
270 | 333 | createGlobalOutsideOfFunctionLowering( |
271 | 334 | [&]() { runtimeTypeInfoConverter.createTypeInfoGlobals(*this); }); |
272 | 335 |
|
| 336 | + /// Create the dispatch tables for derived types. |
| 337 | + createGlobalOutsideOfFunctionLowering( |
| 338 | + [&]() { dispatchTableConverter.createDispatchTableOps(*this); }); |
| 339 | + |
273 | 340 | // Create the list of any environment defaults for the runtime to set. The |
274 | 341 | // runtime default list is only created if there is a main program to ensure |
275 | 342 | // it only happens once and to provide consistent results if multiple files |
@@ -745,6 +812,12 @@ class FirConverter : public Fortran::lower::AbstractConverter { |
745 | 812 | runtimeTypeInfoConverter.registerTypeInfoSymbol(*this, loc, typeInfoSym); |
746 | 813 | } |
747 | 814 |
|
| 815 | + void registerDispatchTableInfo( |
| 816 | + mlir::Location loc, |
| 817 | + const Fortran::semantics::DerivedTypeSpec *typeSpec) override final { |
| 818 | + dispatchTableConverter.registerTypeSpec(loc, typeSpec); |
| 819 | + } |
| 820 | + |
748 | 821 | private: |
749 | 822 | FirConverter() = delete; |
750 | 823 | FirConverter(const FirConverter &) = delete; |
@@ -3591,6 +3664,7 @@ class FirConverter : public Fortran::lower::AbstractConverter { |
3591 | 3664 | Fortran::lower::SymMap localSymbols; |
3592 | 3665 | Fortran::parser::CharBlock currentPosition; |
3593 | 3666 | RuntimeTypeInfoConverter runtimeTypeInfoConverter; |
| 3667 | + DispatchTableConverter dispatchTableConverter; |
3594 | 3668 |
|
3595 | 3669 | /// WHERE statement/construct mask expression stack. |
3596 | 3670 | Fortran::lower::ImplicitIterSpace implicitIterSpace; |
|
0 commit comments