diff --git a/flang/include/flang/Evaluate/tools.h b/flang/include/flang/Evaluate/tools.h index d26a477ddded1..cad1b634f8924 100644 --- a/flang/include/flang/Evaluate/tools.h +++ b/flang/include/flang/Evaluate/tools.h @@ -1585,6 +1585,7 @@ bool IsExtensibleType(const DerivedTypeSpec *); bool IsSequenceOrBindCType(const DerivedTypeSpec *); bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name); bool IsBuiltinCPtr(const Symbol &); +bool IsFromBuiltinModule(const Symbol &); bool IsEventType(const DerivedTypeSpec *); bool IsLockType(const DerivedTypeSpec *); bool IsNotifyType(const DerivedTypeSpec *); diff --git a/flang/include/flang/Lower/LoweringOptions.def b/flang/include/flang/Lower/LoweringOptions.def index d97abf4d864b8..3263ab129d076 100644 --- a/flang/include/flang/Lower/LoweringOptions.def +++ b/flang/include/flang/Lower/LoweringOptions.def @@ -66,5 +66,9 @@ ENUM_LOWERINGOPT(RepackArraysWhole, unsigned, 1, 0) /// If true, CUDA Fortran runtime check is inserted. ENUM_LOWERINGOPT(CUDARuntimeCheck, unsigned, 1, 0) +/// If true, do not generate definition for runtime type info global objects of +/// derived types defined in other compilation units. +ENUM_LOWERINGOPT(SkipExternalRttiDefinition, unsigned, 1, 0) + #undef LOWERINGOPT #undef ENUM_LOWERINGOPT diff --git a/flang/include/flang/Optimizer/CodeGen/CodeGen.h b/flang/include/flang/Optimizer/CodeGen/CodeGen.h index 0398d0f248e08..93f07d8d5d4d9 100644 --- a/flang/include/flang/Optimizer/CodeGen/CodeGen.h +++ b/flang/include/flang/Optimizer/CodeGen/CodeGen.h @@ -39,6 +39,9 @@ struct FIRToLLVMPassOptions { // that such programs would crash at runtime if the derived type descriptors // are required by the runtime, so this is only an option to help debugging. bool ignoreMissingTypeDescriptors = false; + // Similar to ignoreMissingTypeDescriptors, but generate external declaration + // for the missing type descriptor globals instead. + bool skipExternalRttiDefinition = false; // Generate TBAA information for FIR types and memory accessing operations. bool applyTBAA = false; diff --git a/flang/include/flang/Optimizer/Passes/CommandLineOpts.h b/flang/include/flang/Optimizer/Passes/CommandLineOpts.h index 1cfaf285e75e6..76ac9d0622d2b 100644 --- a/flang/include/flang/Optimizer/Passes/CommandLineOpts.h +++ b/flang/include/flang/Optimizer/Passes/CommandLineOpts.h @@ -32,6 +32,19 @@ extern llvm::cl::opt arrayStackAllocationThreshold; /// generated by the frontend. extern llvm::cl::opt ignoreMissingTypeDescriptors; +/// Shared option in tools to only generate rtti static object definitions for +/// derived types defined in the current compilation unit. Derived type +/// descriptor object for types defined in other objects will only be declared +/// as external. This also changes the linkage of rtti objects defined in the +/// current compilation unit from linkonce_odr to external so that unused rtti +/// objects are retained and can be accessed from other compilation units. This +/// is an experimental option to explore compilation speed improvements and is +/// an ABI breaking change because of the linkage change. +/// It will also require linking against module file objects of modules defining +/// only types (even for trivial types without type bound procedures, which +/// differs from most compilers). +extern llvm::cl::opt skipExternalRttiDefinition; + /// Default optimization level used to create Flang pass pipeline is O0. extern llvm::OptimizationLevel defaultOptLevel; diff --git a/flang/include/flang/Optimizer/Support/Utils.h b/flang/include/flang/Optimizer/Support/Utils.h index ec73af6ec72e9..83c936b7dcada 100644 --- a/flang/include/flang/Optimizer/Support/Utils.h +++ b/flang/include/flang/Optimizer/Support/Utils.h @@ -35,32 +35,6 @@ inline std::int64_t toInt(mlir::arith::ConstantOp cop) { .getSExtValue(); } -// Reconstruct binding tables for dynamic dispatch. -using BindingTable = llvm::DenseMap; -using BindingTables = llvm::DenseMap; - -inline void buildBindingTables(BindingTables &bindingTables, - mlir::ModuleOp mod) { - - // 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 typeInfo : mod.getOps()) { - unsigned bindingIdx = 0; - BindingTable bindings; - if (typeInfo.getDispatchTable().empty()) { - bindingTables[typeInfo.getSymName()] = bindings; - continue; - } - for (auto dtEntry : - typeInfo.getDispatchTable().front().getOps()) { - bindings[dtEntry.getMethod()] = bindingIdx; - ++bindingIdx; - } - bindingTables[typeInfo.getSymName()] = bindings; - } -} - // Translate front-end KINDs for use in the IR and code gen. inline std::vector fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) { diff --git a/flang/include/flang/Semantics/runtime-type-info.h b/flang/include/flang/Semantics/runtime-type-info.h index e90d3ae8baf1e..6c5a061d1c1a2 100644 --- a/flang/include/flang/Semantics/runtime-type-info.h +++ b/flang/include/flang/Semantics/runtime-type-info.h @@ -38,6 +38,10 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(SemanticsContext &); /// to describe other derived types at runtime in flang descriptor. constexpr char typeInfoBuiltinModule[]{"__fortran_type_info"}; +/// Name of the builtin derived type in __fortran_type_inf that is used for +/// derived type descriptors. +constexpr char typeDescriptorTypeName[]{"derivedtype"}; + /// Name of the bindings descriptor component in the DerivedType type of the /// __Fortran_type_info module constexpr char bindingDescCompName[]{"binding"}; diff --git a/flang/lib/Evaluate/tools.cpp b/flang/lib/Evaluate/tools.cpp index 68838564f87ba..fcacdb93d662b 100644 --- a/flang/lib/Evaluate/tools.cpp +++ b/flang/lib/Evaluate/tools.cpp @@ -2334,6 +2334,11 @@ bool IsBuiltinCPtr(const Symbol &symbol) { return false; } +bool IsFromBuiltinModule(const Symbol &symbol) { + const Scope &scope{symbol.GetUltimate().owner()}; + return IsSameModule(&scope, scope.context().GetBuiltinsScope()); +} + bool IsIsoCType(const DerivedTypeSpec *derived) { return IsBuiltinDerivedType(derived, "c_ptr") || IsBuiltinDerivedType(derived, "c_funptr"); diff --git a/flang/lib/Frontend/CompilerInvocation.cpp b/flang/lib/Frontend/CompilerInvocation.cpp index 766131fd69d85..30d81f3daa969 100644 --- a/flang/lib/Frontend/CompilerInvocation.cpp +++ b/flang/lib/Frontend/CompilerInvocation.cpp @@ -14,6 +14,7 @@ #include "flang/Frontend/CodeGenOptions.h" #include "flang/Frontend/PreprocessorOptions.h" #include "flang/Frontend/TargetOptions.h" +#include "flang/Optimizer/Passes/CommandLineOpts.h" #include "flang/Semantics/semantics.h" #include "flang/Support/Fortran-features.h" #include "flang/Support/OpenMP-features.h" @@ -1792,6 +1793,7 @@ void CompilerInvocation::setLoweringOptions() { // Lower TRANSPOSE as a runtime call under -O0. loweringOpts.setOptimizeTranspose(codegenOpts.OptimizationLevel > 0); loweringOpts.setUnderscoring(codegenOpts.Underscoring); + loweringOpts.setSkipExternalRttiDefinition(skipExternalRttiDefinition); const Fortran::common::LangOptions &langOptions = getLangOpts(); loweringOpts.setIntegerWrapAround(langOptions.getSignedOverflowBehavior() == diff --git a/flang/lib/Lower/Bridge.cpp b/flang/lib/Lower/Bridge.cpp index 7b640dd497af3..ff35840a6668c 100644 --- a/flang/lib/Lower/Bridge.cpp +++ b/flang/lib/Lower/Bridge.cpp @@ -262,6 +262,7 @@ class TypeInfoConverter { } void createTypeInfo(Fortran::lower::AbstractConverter &converter) { + createTypeInfoForTypeDescriptorBuiltinType(converter); while (!registeredTypeInfoA.empty()) { currentTypeInfoStack = ®isteredTypeInfoB; for (const TypeInfo &info : registeredTypeInfoA) @@ -277,10 +278,22 @@ class TypeInfoConverter { private: void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter, const TypeInfo &info) { - Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get()); + if (!converter.getLoweringOptions().getSkipExternalRttiDefinition()) + Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get()); createTypeInfoOp(converter, info); } + void createTypeInfoForTypeDescriptorBuiltinType( + Fortran::lower::AbstractConverter &converter) { + if (registeredTypeInfoA.empty()) + return; + auto builtinTypeInfoType = llvm::cast( + converter.genType(registeredTypeInfoA[0].symbol.get())); + converter.getFirOpBuilder().createTypeInfoOp( + registeredTypeInfoA[0].loc, builtinTypeInfoType, + /*parentType=*/fir::RecordType{}); + } + void createTypeInfoOp(Fortran::lower::AbstractConverter &converter, const TypeInfo &info) { fir::RecordType parentType{}; diff --git a/flang/lib/Lower/ConvertVariable.cpp b/flang/lib/Lower/ConvertVariable.cpp index 49e6ea02d51a7..7ab3c43016bd9 100644 --- a/flang/lib/Lower/ConvertVariable.cpp +++ b/flang/lib/Lower/ConvertVariable.cpp @@ -647,13 +647,19 @@ fir::GlobalOp Fortran::lower::defineGlobal( /// Return linkage attribute for \p var. static mlir::StringAttr -getLinkageAttribute(fir::FirOpBuilder &builder, +getLinkageAttribute(Fortran::lower::AbstractConverter &converter, const Fortran::lower::pft::Variable &var) { + fir::FirOpBuilder &builder = converter.getFirOpBuilder(); // Runtime type info for a same derived type is identical in each compilation // unit. It desired to avoid having to link against module that only define a // type. Therefore the runtime type info is generated everywhere it is needed - // with `linkonce_odr` LLVM linkage. - if (var.isRuntimeTypeInfoData()) + // with `linkonce_odr` LLVM linkage (unless the skipExternalRttiDefinition + // option is set, in which case one will need to link against objects of + // modules defining types). Builtin objects rtti is always generated because + // the builtin module is currently not compiled or part of the runtime. + if (var.isRuntimeTypeInfoData() && + (!converter.getLoweringOptions().getSkipExternalRttiDefinition() || + Fortran::semantics::IsFromBuiltinModule(var.getSymbol()))) return builder.createLinkOnceODRLinkage(); if (var.isModuleOrSubmoduleVariable()) return {}; // external linkage @@ -673,7 +679,7 @@ static void instantiateGlobal(Fortran::lower::AbstractConverter &converter, fir::FirOpBuilder &builder = converter.getFirOpBuilder(); std::string globalName = converter.mangleName(sym); mlir::Location loc = genLocation(converter, sym); - mlir::StringAttr linkage = getLinkageAttribute(builder, var); + mlir::StringAttr linkage = getLinkageAttribute(converter, var); fir::GlobalOp global; if (var.isModuleOrSubmoduleVariable()) { // A non-intrinsic module global is defined when lowering the module. @@ -1265,7 +1271,7 @@ instantiateAggregateStore(Fortran::lower::AbstractConverter &converter, if (var.isGlobal()) { fir::GlobalOp global; auto &aggregate = var.getAggregateStore(); - mlir::StringAttr linkage = getLinkageAttribute(builder, var); + mlir::StringAttr linkage = getLinkageAttribute(converter, var); if (var.isModuleOrSubmoduleVariable()) { // A module global was or will be defined when lowering the module. Emit // only a declaration if the global does not exist at that point. @@ -2470,8 +2476,7 @@ void Fortran::lower::defineModuleVariable( AbstractConverter &converter, const Fortran::lower::pft::Variable &var) { // Use empty linkage for module variables, which makes them available // for use in another unit. - mlir::StringAttr linkage = - getLinkageAttribute(converter.getFirOpBuilder(), var); + mlir::StringAttr linkage = getLinkageAttribute(converter, var); if (!var.isGlobal()) fir::emitFatalError(converter.getCurrentLocation(), "attempting to lower module variable as local"); @@ -2606,10 +2611,9 @@ void Fortran::lower::createIntrinsicModuleGlobal( void Fortran::lower::createRuntimeTypeInfoGlobal( Fortran::lower::AbstractConverter &converter, const Fortran::semantics::Symbol &typeInfoSym) { - fir::FirOpBuilder &builder = converter.getFirOpBuilder(); std::string globalName = converter.mangleName(typeInfoSym); auto var = Fortran::lower::pft::Variable(typeInfoSym, /*global=*/true); - mlir::StringAttr linkage = getLinkageAttribute(builder, var); + mlir::StringAttr linkage = getLinkageAttribute(converter, var); defineGlobal(converter, var, globalName, linkage); } diff --git a/flang/lib/Optimizer/CodeGen/CodeGen.cpp b/flang/lib/Optimizer/CodeGen/CodeGen.cpp index a3de3ae9d116a..2b018912b40e4 100644 --- a/flang/lib/Optimizer/CodeGen/CodeGen.cpp +++ b/flang/lib/Optimizer/CodeGen/CodeGen.cpp @@ -1294,6 +1294,51 @@ genCUFAllocDescriptor(mlir::Location loc, .getResult(); } +/// Get the address of the type descriptor global variable that was created by +/// lowering for derived type \p recType. +template +static mlir::Value +getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter, + mlir::Location loc, fir::RecordType recType, + const fir::FIRToLLVMPassOptions &options) { + std::string name = + options.typeDescriptorsRenamedForAssembly + ? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName()) + : fir::NameUniquer::getTypeDescriptorName(recType.getName()); + mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext()); + if (auto global = mod.template lookupSymbol(name)) + return rewriter.create(loc, llvmPtrTy, + global.getSymName()); + // The global may have already been translated to LLVM. + if (auto global = mod.template lookupSymbol(name)) + return rewriter.create(loc, llvmPtrTy, + global.getSymName()); + // Type info derived types do not have type descriptors since they are the + // types defining type descriptors. + if (options.ignoreMissingTypeDescriptors || + fir::NameUniquer::belongsToModule( + name, Fortran::semantics::typeInfoBuiltinModule)) + return rewriter.create(loc, llvmPtrTy); + + if (!options.skipExternalRttiDefinition) + fir::emitFatalError(loc, + "runtime derived type info descriptor was not " + "generated and skipExternalRttiDefinition and " + "ignoreMissingTypeDescriptors options are not set"); + + // Rtti for a derived type defined in another compilation unit and for which + // rtti was not defined in lowering because of the skipExternalRttiDefinition + // option. Generate the object declaration now. + auto insertPt = rewriter.saveInsertionPoint(); + rewriter.setInsertionPoint(mod.getBody(), mod.getBody()->end()); + mlir::LLVM::GlobalOp global = rewriter.create( + loc, llvmPtrTy, /*constant=*/true, mlir::LLVM::Linkage::External, name, + mlir::Attribute()); + rewriter.restoreInsertionPoint(insertPt); + return rewriter.create(loc, llvmPtrTy, + global.getSymName()); +} + /// Common base class for embox to descriptor conversion. template struct EmboxCommonConversion : public fir::FIROpConversion { @@ -1406,36 +1451,6 @@ struct EmboxCommonConversion : public fir::FIROpConversion { stride); } - /// Get the address of the type descriptor global variable that was created by - /// lowering for derived type \p recType. - template - mlir::Value - getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter, - mlir::Location loc, fir::RecordType recType) const { - std::string name = - this->options.typeDescriptorsRenamedForAssembly - ? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName()) - : fir::NameUniquer::getTypeDescriptorName(recType.getName()); - mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext()); - if (auto global = mod.template lookupSymbol(name)) { - return rewriter.create(loc, llvmPtrTy, - global.getSymName()); - } - if (auto global = mod.template lookupSymbol(name)) { - // The global may have already been translated to LLVM. - return rewriter.create(loc, llvmPtrTy, - global.getSymName()); - } - // Type info derived types do not have type descriptors since they are the - // types defining type descriptors. - if (!this->options.ignoreMissingTypeDescriptors && - !fir::NameUniquer::belongsToModule( - name, Fortran::semantics::typeInfoBuiltinModule)) - fir::emitFatalError( - loc, "runtime derived type info descriptor was not generated"); - return rewriter.create(loc, llvmPtrTy); - } - template mlir::Value populateDescriptor(mlir::Location loc, ModOpTy mod, fir::BaseBoxType boxTy, mlir::Type inputType, @@ -1500,7 +1515,8 @@ struct EmboxCommonConversion : public fir::FIROpConversion { mlir::Type innerType = fir::unwrapInnerType(inputType); if (innerType && mlir::isa(innerType)) { auto recTy = mlir::dyn_cast(innerType); - typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy); + typeDesc = + getTypeDescriptor(mod, rewriter, loc, recTy, this->options); } else { // Unlimited polymorphic type descriptor with no record type. Set // type descriptor address to a clean state. @@ -1508,8 +1524,8 @@ struct EmboxCommonConversion : public fir::FIROpConversion { loc, ::getLlvmPtrType(mod.getContext())); } } else { - typeDesc = getTypeDescriptor(mod, rewriter, loc, - fir::unwrapIfDerived(boxTy)); + typeDesc = getTypeDescriptor( + mod, rewriter, loc, fir::unwrapIfDerived(boxTy), this->options); } } if (typeDesc) @@ -3021,22 +3037,10 @@ struct TypeDescOpConversion : public fir::FIROpConversion { assert(mlir::isa(inTy) && "expecting fir.type"); auto recordType = mlir::dyn_cast(inTy); auto module = typeDescOp.getOperation()->getParentOfType(); - std::string typeDescName = - this->options.typeDescriptorsRenamedForAssembly - ? fir::NameUniquer::getTypeDescriptorAssemblyName( - recordType.getName()) - : fir::NameUniquer::getTypeDescriptorName(recordType.getName()); - auto llvmPtrTy = ::getLlvmPtrType(typeDescOp.getContext()); - if (auto global = module.lookupSymbol(typeDescName)) { - rewriter.replaceOpWithNewOp( - typeDescOp, llvmPtrTy, global.getSymName()); - return mlir::success(); - } else if (auto global = module.lookupSymbol(typeDescName)) { - rewriter.replaceOpWithNewOp( - typeDescOp, llvmPtrTy, global.getSymName()); - return mlir::success(); - } - return mlir::failure(); + mlir::Value typeDesc = getTypeDescriptor( + module, rewriter, typeDescOp.getLoc(), recordType, this->options); + rewriter.replaceOp(typeDescOp, typeDesc); + return mlir::success(); } }; diff --git a/flang/lib/Optimizer/Passes/CommandLineOpts.cpp b/flang/lib/Optimizer/Passes/CommandLineOpts.cpp index f95a280883cba..014237542f24d 100644 --- a/flang/lib/Optimizer/Passes/CommandLineOpts.cpp +++ b/flang/lib/Optimizer/Passes/CommandLineOpts.cpp @@ -39,6 +39,12 @@ cl::opt ignoreMissingTypeDescriptors( "translating FIR to LLVM"), cl::init(false), cl::Hidden); +cl::opt skipExternalRttiDefinition( + "skip-external-rtti-definition", llvm::cl::init(false), + llvm::cl::desc("do not define rtti static objects for types belonging to " + "other compilation units"), + cl::Hidden); + OptimizationLevel defaultOptLevel{OptimizationLevel::O0}; codegenoptions::DebugInfoKind noDebugInfo{codegenoptions::NoDebugInfo}; diff --git a/flang/lib/Optimizer/Passes/Pipelines.cpp b/flang/lib/Optimizer/Passes/Pipelines.cpp index 70f57bdeddd3f..42d9e7ba2418f 100644 --- a/flang/lib/Optimizer/Passes/Pipelines.cpp +++ b/flang/lib/Optimizer/Passes/Pipelines.cpp @@ -108,6 +108,7 @@ void addFIRToLLVMPass(mlir::PassManager &pm, const MLIRToLLVMPassPipelineConfig &config) { fir::FIRToLLVMPassOptions options; options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors; + options.skipExternalRttiDefinition = skipExternalRttiDefinition; options.applyTBAA = config.AliasAnalysis; options.forceUnifiedTBAATree = useOldAliasTags; options.typeDescriptorsRenamedForAssembly = diff --git a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp index f9a4c4d0283c7..57eae1ff052a2 100644 --- a/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp +++ b/flang/lib/Optimizer/Transforms/PolymorphicOpConversion.cpp @@ -16,7 +16,6 @@ #include "flang/Optimizer/Dialect/Support/KindMapping.h" #include "flang/Optimizer/Support/InternalNames.h" #include "flang/Optimizer/Support/TypeCode.h" -#include "flang/Optimizer/Support/Utils.h" #include "flang/Optimizer/Transforms/Passes.h" #include "flang/Runtime/derived-api.h" #include "flang/Semantics/runtime-type-info.h" @@ -38,6 +37,45 @@ namespace fir { using namespace fir; using namespace mlir; +// Reconstruct binding tables for dynamic dispatch. +using BindingTable = llvm::DenseMap; +using BindingTables = llvm::DenseMap; + +static std::string getTypeDescriptorTypeName() { + llvm::SmallVector modules = { + Fortran::semantics::typeInfoBuiltinModule}; + return fir::NameUniquer::doType(modules, /*proc=*/{}, /*blockId=*/0, + Fortran::semantics::typeDescriptorTypeName, + /*kinds=*/{}); +} + +static std::optional +buildBindingTables(BindingTables &bindingTables, mlir::ModuleOp mod) { + + std::optional typeDescriptorType; + std::string typeDescriptorTypeName = getTypeDescriptorTypeName(); + // 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 typeInfo : mod.getOps()) { + if (!typeDescriptorType && typeInfo.getSymName() == typeDescriptorTypeName) + typeDescriptorType = typeInfo.getType(); + unsigned bindingIdx = 0; + BindingTable bindings; + if (typeInfo.getDispatchTable().empty()) { + bindingTables[typeInfo.getSymName()] = bindings; + continue; + } + for (auto dtEntry : + typeInfo.getDispatchTable().front().getOps()) { + bindings[dtEntry.getMethod()] = bindingIdx; + ++bindingIdx; + } + bindingTables[typeInfo.getSymName()] = bindings; + } + return typeDescriptorType; +} + namespace { /// SelectTypeOp converted to an if-then-else chain @@ -77,9 +115,10 @@ class SelectTypeConv : public OpConversionPattern { struct DispatchOpConv : public OpConversionPattern { using OpConversionPattern::OpConversionPattern; - DispatchOpConv(mlir::MLIRContext *ctx, const BindingTables &bindingTables) + DispatchOpConv(mlir::MLIRContext *ctx, const BindingTables &bindingTables, + std::optional typeDescriptorType) : mlir::OpConversionPattern(ctx), - bindingTables(bindingTables) {} + bindingTables(bindingTables), typeDescriptorType{typeDescriptorType} {} llvm::LogicalResult matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor, @@ -111,13 +150,11 @@ struct DispatchOpConv : public OpConversionPattern { mlir::Value passedObject = dispatch.getObject(); - auto module = dispatch.getOperation()->getParentOfType(); - Type typeDescTy; - std::string typeDescName = - NameUniquer::getTypeDescriptorName(recordType.getName()); - if (auto global = module.lookupSymbol(typeDescName)) { - typeDescTy = global.getType(); - } + if (!typeDescriptorType) + return emitError(loc) << "cannot find " << getTypeDescriptorTypeName() + << " fir.type_info that is required to get the " + "related builtin type and lower fir.dispatch"; + mlir::Type typeDescTy = *typeDescriptorType; // clang-format off // Before: @@ -213,6 +250,7 @@ struct DispatchOpConv : public OpConversionPattern { private: BindingTables bindingTables; + std::optional typeDescriptorType; }; /// Convert FIR structured control flow ops to CFG ops. @@ -229,10 +267,11 @@ class PolymorphicOpConversion mlir::RewritePatternSet patterns(context); BindingTables bindingTables; - buildBindingTables(bindingTables, mod); + std::optional typeDescriptorType = + buildBindingTables(bindingTables, mod); patterns.insert(context); - patterns.insert(context, bindingTables); + patterns.insert(context, bindingTables, typeDescriptorType); mlir::ConversionTarget target(*context); target.addLegalDialect(attr)) { // Retrieve the type descriptor from the type guard statement record type. assert(mlir::isa(a.getType()) && "expect fir.record type"); - fir::RecordType recTy = mlir::dyn_cast(a.getType()); - std::string typeDescName = - fir::NameUniquer::getTypeDescriptorName(recTy.getName()); - auto typeDescGlobal = mod.lookupSymbol(typeDescName); - auto typeDescAddr = rewriter.create( - loc, fir::ReferenceType::get(typeDescGlobal.getType()), - typeDescGlobal.getSymbol()); - mlir::Type typeDescTy = ReferenceType::get(rewriter.getNoneType()); + mlir::Value typeDescAddr = + rewriter.create(loc, mlir::TypeAttr::get(a.getType())); + mlir::Type refNoneType = ReferenceType::get(rewriter.getNoneType()); mlir::Value typeDesc = - rewriter.create(loc, typeDescTy, typeDescAddr); + rewriter.create(loc, refNoneType, typeDescAddr); // Prepare the selector descriptor for the runtime call. mlir::Type descNoneTy = fir::BoxType::get(rewriter.getNoneType()); @@ -406,7 +440,7 @@ llvm::LogicalResult SelectTypeConv::genTypeLadderStep( mlir::UnitAttr::get(rewriter.getContext())); callee = fir::createFuncOp(rewriter.getUnknownLoc(), mod, fctName, - rewriter.getFunctionType({descNoneTy, typeDescTy}, + rewriter.getFunctionType({descNoneTy, refNoneType}, rewriter.getI1Type()), {runtimeAttr}); } @@ -435,20 +469,11 @@ SelectTypeConv::genTypeDescCompare(mlir::Location loc, mlir::Value selector, mlir::Type ty, mlir::ModuleOp mod, mlir::PatternRewriter &rewriter) const { assert(mlir::isa(ty) && "expect fir.record type"); - fir::RecordType recTy = mlir::dyn_cast(ty); - std::string typeDescName = - fir::NameUniquer::getTypeDescriptorName(recTy.getName()); - auto typeDescGlobal = mod.lookupSymbol(typeDescName); - if (!typeDescGlobal) - return {}; - auto typeDescAddr = rewriter.create( - loc, fir::ReferenceType::get(typeDescGlobal.getType()), - typeDescGlobal.getSymbol()); + mlir::Value typeDescAddr = + rewriter.create(loc, mlir::TypeAttr::get(ty)); + mlir::Value selectorTdescAddr = rewriter.create( + loc, typeDescAddr.getType(), selector); auto intPtrTy = rewriter.getIndexType(); - mlir::Type tdescType = - fir::TypeDescType::get(mlir::NoneType::get(rewriter.getContext())); - mlir::Value selectorTdescAddr = - rewriter.create(loc, tdescType, selector); auto typeDescInt = rewriter.create(loc, intPtrTy, typeDescAddr); auto selectorTdescInt = diff --git a/flang/test/Integration/skip-external-rtti-definition.F90 b/flang/test/Integration/skip-external-rtti-definition.F90 new file mode 100644 index 0000000000000..f86cc069b304d --- /dev/null +++ b/flang/test/Integration/skip-external-rtti-definition.F90 @@ -0,0 +1,47 @@ +! Test -skip-external-rtti-definition option + +!RUN: rm -rf %t && mkdir -p %t +!RUN: %flang_fc1 -fsyntax-only -DSTEP=1 -J%t %s +!RUN: %flang_fc1 -emit-llvm -J%t %s -o - | FileCheck %s -check-prefix=LINKONCE +!RUN: %flang_fc1 -emit-llvm -J%t -mllvm -skip-external-rtti-definition %s -o - | FileCheck %s -check-prefix=EXTERNAL + +#if STEP == 1 +module module_external_type_definition + type t1 + end type +end module +#else + +module module_same_unit_type_definition + type t2 + end type +end module + +subroutine test + use module_external_type_definition + use module_same_unit_type_definition + interface + subroutine needs_descriptor(x) + class(*) :: x + end subroutine + end interface + type(t1) :: x1 + type(t2) :: x2 + call needs_descriptor(x1) + call needs_descriptor(x2) +end subroutine + +#endif + +! LINKONCE-DAG: @_QMmodule_external_type_definitionEXnXt1 = linkonce_odr constant [2 x i8] c"t1", comdat +! LINKONCE-DAG: @_QMmodule_external_type_definitionEXdtXt1 = linkonce_odr constant {{.*}} { +! LINKONCE-DAG: @_QMmodule_same_unit_type_definitionEXnXt2 = linkonce_odr constant [2 x i8] c"t2", comdat +! LINKONCE-DAG: @_QMmodule_same_unit_type_definitionEXdtXt2 = linkonce_odr constant {{.*}} { + +! EXTERNAL-NOT: @_QMmodule_external_type_definitionEXnXt1 +! EXTERNAL: @_QMmodule_same_unit_type_definitionEXnXt2 = constant [2 x i8] c"t2" +! EXTERNAL-NOT: @_QMmodule_external_type_definitionEXnXt1 +! EXTERNAL: @_QMmodule_same_unit_type_definitionEXdtXt2 = constant {{.*}} { +! EXTERNAL-NOT: @_QMmodule_external_type_definitionEXnXt1 +! EXTERNAL: @_QMmodule_external_type_definitionEXdtXt1 = external constant ptr +! EXTERNAL-NOT: @_QMmodule_external_type_definitionEXnXt1 diff --git a/flang/test/Lower/select-type-2.f90 b/flang/test/Lower/select-type-2.f90 index 7b4cf96069e53..59485c176c76a 100644 --- a/flang/test/Lower/select-type-2.f90 +++ b/flang/test/Lower/select-type-2.f90 @@ -30,8 +30,8 @@ subroutine select_type1(a) ! CHECK-LABEL: func.func @_QMselect_type_2Pselect_type1( ! CHECK-SAME: %[[ARG0:.*]]: !fir.class> {fir.bindc_name = "a"}) { -! CHECK: %[[TDESC_P3_ADDR:.*]] = fir.address_of(@_QMselect_type_2E.dt.p3) : !fir.ref> -! CHECK: %[[TDESC_P3_CONV:.*]] = fir.convert %[[TDESC_P3_ADDR]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[TDESC_P3_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_2Tp3 +! CHECK: %[[TDESC_P3_CONV:.*]] = fir.convert %[[TDESC_P3_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CHECK: %[[CLASS_IS_CMP:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P3_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CHECK: cf.cond_br %[[CLASS_IS_CMP]], ^[[CLASS_IS_P3_BLK:.*]], ^[[NOT_CLASS_IS_P3_BLK:.*]] @@ -40,8 +40,8 @@ subroutine select_type1(a) ! CHECK: ^bb[[CLASS_IS_P1:[0-9]]]: ! CHECK: cf.br ^bb[[END_SELECT_BLK:[0-9]]] ! CHECK: ^[[NOT_CLASS_IS_P3_BLK]]: -! CHECK: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_2E.dt.p1) : !fir.ref> -! CHECK: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CHECK: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_2Tp1 +! CHECK: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CHECK: %[[CLASS_IS_CMP:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CHECK: cf.cond_br %[[CLASS_IS_CMP]], ^bb[[CLASS_IS_P1]], ^bb[[NOT_CLASS_IS_P1]] diff --git a/flang/test/Lower/select-type.f90 b/flang/test/Lower/select-type.f90 index 64dd639731ab1..e2ca87ad447c9 100644 --- a/flang/test/Lower/select-type.f90 +++ b/flang/test/Lower/select-type.f90 @@ -68,15 +68,15 @@ subroutine select_type1(a) ! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type1( ! CFG-SAME: %[[ARG0:.*]]: !fir.class> {fir.bindc_name = "a"}) { -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> index -! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc) -> index +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc>) -> index +! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc>) -> index ! CFG: %[[TDESC_CMP:.*]] = arith.cmpi eq, %[[TDESC_P1_CONV]], %[[BOX_TDESC_CONV]] : index ! CFG: cf.cond_br %[[TDESC_CMP]], ^[[TYPE_IS_P1_BLK:.*]], ^[[NOT_TYPE_IS_P1_BLK:.*]] ! CFG: ^[[NOT_TYPE_IS_P1_BLK]]: -! CFG: %[[TDESC_P2_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p2) : !fir.ref> -! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P2_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp2{{.*}} +! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.tdesc<{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P2_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS]], ^bb[[CLASS_IS_P2_BLK:.*]], ^[[NOT_CLASS_IS_P2_BLK:.*]] @@ -87,8 +87,8 @@ subroutine select_type1(a) ! CFG: ^bb[[CLASS_IS_P1_BLK:[0-9]]]: ! CFG: cf.br ^[[END_SELECT_BLK:.*]] ! CFG: ^[[NOT_CLASS_IS_P2_BLK]]: -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc<{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS]], ^bb[[CLASS_IS_P1_BLK]], ^bb[[NOT_CLASS_IS_P1_BLK]] @@ -126,15 +126,15 @@ subroutine select_type2() ! CFG: %[[GET_CLASS:.*]] = fir.call @_QMselect_type_lower_testPget_class() {{.*}} : () -> !fir.class>> ! CFG: fir.save_result %[[GET_CLASS]] to %[[CLASS_ALLOCA]] : !fir.class>>, !fir.ref>>> ! CFG: %[[LOAD_CLASS:.*]] = fir.load %[[CLASS_ALLOCA]] : !fir.ref>>> -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[CLASS_TDESC:.*]] = fir.box_tdesc %[[LOAD_CLASS]] : (!fir.class>>) -> !fir.tdesc -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> index -! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[CLASS_TDESC]] : (!fir.tdesc) -> index +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[CLASS_TDESC:.*]] = fir.box_tdesc %[[LOAD_CLASS]] : (!fir.class>>) -> !fir.tdesc<{{.*}}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> index +! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[CLASS_TDESC]] : (!fir.tdesc<{{.*}}>) -> index ! CFG: %[[TDESC_CMP:.*]] = arith.cmpi eq, %[[TDESC_P1_CONV]], %[[BOX_TDESC_CONV]] : index ! CFG: cf.cond_br %[[TDESC_CMP]], ^[[TYPE_IS_P1_BLK:.*]], ^[[NOT_TYPE_IS_P1_BLK:.*]] ! CFG: ^[[NOT_TYPE_IS_P1_BLK]]: -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[LOAD_CLASS]] : (!fir.class>>) -> !fir.box ! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS]], ^[[CLASS_IS_BLK:.*]], ^[[NOT_CLASS_IS_BLK:.*]] @@ -176,15 +176,15 @@ subroutine select_type3(a) ! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type3( ! CFG-SAME: %[[ARG0:.*]]: !fir.ref>>>> {fir.bindc_name = "a"}) { ! CFG: %[[SELECTOR:.*]] = fir.embox %{{.*}} source_box %{{.*}} : (!fir.ref>, !fir.class<{{.*}}>) -> !fir.class> -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[SELECTOR_TDESC:.*]] = fir.box_tdesc %[[SELECTOR]] : (!fir.class>) -> !fir.tdesc -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> index -! CFG: %[[TDESC_CONV:.*]] = fir.convert %[[SELECTOR_TDESC]] : (!fir.tdesc) -> index +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[SELECTOR_TDESC:.*]] = fir.box_tdesc %[[SELECTOR]] : (!fir.class>) -> !fir.tdesc<{{.*}}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> index +! CFG: %[[TDESC_CONV:.*]] = fir.convert %[[SELECTOR_TDESC]] : (!fir.tdesc<{{.*}}>) -> index ! CFG: %[[TDESC_CMP:.*]] = arith.cmpi eq, %[[TDESC_P1_CONV]], %[[TDESC_CONV]] : index ! CFG: cf.cond_br %[[TDESC_CMP]], ^[[TYPE_IS_P1_BLK:.*]], ^[[NOT_TYPE_IS_P1_BLK:.*]] ! CFG: ^[[NOT_TYPE_IS_P1_BLK]]: -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[SELECTOR]] : (!fir.class>) -> !fir.box ! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS]], ^[[CLASS_IS_BLK:.*]], ^[[NOT_CLASS_IS:.*]] @@ -222,25 +222,25 @@ subroutine select_type4(a) ! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type4( ! CFG-SAME: %[[ARG0:.*]]: !fir.class> {fir.bindc_name = "a"}) { -! CFG: %[[TDESC_P3_8_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p3.8) : !fir.ref> -! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc -! CFG: %[[TDESC_P3_8_CONV:.*]] = fir.convert %[[TDESC_P3_8_ADDR]] : (!fir.ref>) -> index -! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc) -> index +! CFG: %[[TDESC_P3_8_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp3K8 +! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc<{{.*}}> +! CFG: %[[TDESC_P3_8_CONV:.*]] = fir.convert %[[TDESC_P3_8_ADDR]] : (!fir.tdesc{{.*}}>) -> index +! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<{{.*}}>) -> index ! CFG: %[[TDESC_CMP:.*]] = arith.cmpi eq, %[[TDESC_P3_8_CONV]], %[[BOX_TDESC_CONV]] : index ! CFG: cf.cond_br %[[TDESC_CMP]], ^[[P3_8_BLK:.*]], ^[[NOT_P3_8_BLK:.*]] ! CFG: ^[[NOT_P3_8_BLK]]: -! CFG: %[[TDESC_P3_4_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p3.4) : !fir.ref> -! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc -! CFG: %[[TDESC_P3_4_CONV:.*]] = fir.convert %[[TDESC_P3_4_ADDR]] : (!fir.ref>) -> index -! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc) -> index +! CFG: %[[TDESC_P3_4_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp3K4 +! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class>) -> !fir.tdesc<{{.*}}> +! CFG: %[[TDESC_P3_4_CONV:.*]] = fir.convert %[[TDESC_P3_4_ADDR]] : (!fir.tdesc{{.*}}>) -> index +! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<{{.*}}>) -> index ! CFG: %[[TDESC_CMP:.*]] = arith.cmpi eq, %[[TDESC_P3_4_CONV]], %[[BOX_TDESC_CONV]] : index ! CFG: cf.cond_br %[[TDESC_CMP]], ^[[P3_4_BLK:.*]], ^[[NOT_P3_4_BLK:.*]] ! CFG: ^[[P3_8_BLK]]: ! CFG: _FortranAioOutputAscii ! CFG: cf.br ^bb[[EXIT_SELECT_BLK:[0-9]]] ! CFG: ^[[NOT_P3_4_BLK]]: -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class>) -> !fir.box ! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS]], ^[[P1_BLK:.*]], ^[[NOT_P1_BLK:.*]] @@ -409,8 +409,8 @@ subroutine select_type7(a) ! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type7( ! CFG-SAME: %[[ARG0:.*]]: !fir.class {fir.bindc_name = "a"}) { -! CFG: %[[TDESC_P4_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p4) : !fir.ref> -! CFG: %[[TDESC_P4_CONV:.*]] = fir.convert %[[TDESC_P4_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P4_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp4 +! CFG: %[[TDESC_P4_CONV:.*]] = fir.convert %[[TDESC_P4_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class) -> !fir.box ! CFG: %[[CLASS_IS_P4:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P4_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS_P4]], ^[[CLASS_IS_P4_BLK:.*]], ^[[CLASS_NOT_P4_BLK:.*]] @@ -419,16 +419,16 @@ subroutine select_type7(a) ! CFG: ^bb[[CLASS_IS_P1_BLK:[0-9]]]: ! CFG: cf.br ^[[EXIT_SELECT_BLK:.*]] ! CFG: ^bb[[CLASS_NOT_P2_BLK:[0-9]]]: -! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref> -! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P1_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}> +! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class) -> !fir.box ! CFG: %[[CLASS_IS_P1:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS_P1]], ^bb[[CLASS_IS_P1_BLK]], ^bb[[CLASS_NOT_P1_BLK]] ! CFG: ^bb[[CLASS_IS_P2_BLK:[0-9]]]: ! CFG: cf.br ^[[EXIT_SELECT_BLK]] ! CFG: ^[[CLASS_NOT_P4_BLK]]: -! CFG: %[[TDESC_P2_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p2) : !fir.ref> -! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.ref>) -> !fir.ref +! CFG: %[[TDESC_P2_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp2 +! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref ! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class) -> !fir.box ! CFG: %[[CLASS_IS_P2:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P2_CONV]]) : (!fir.box, !fir.ref) -> i1 ! CFG: cf.cond_br %[[CLASS_IS_P2]], ^bb[[CLASS_IS_P2_BLK]], ^bb[[CLASS_NOT_P2_BLK]] diff --git a/flang/tools/bbc/bbc.cpp b/flang/tools/bbc/bbc.cpp index 015c86604a1fd..59372a8eb58ed 100644 --- a/flang/tools/bbc/bbc.cpp +++ b/flang/tools/bbc/bbc.cpp @@ -434,6 +434,7 @@ static llvm::LogicalResult convertFortranSourceToMLIR( loweringOptions.setStackRepackArrays(stackRepackArrays); loweringOptions.setRepackArrays(repackArrays); loweringOptions.setRepackArraysWhole(repackArraysWhole); + loweringOptions.setSkipExternalRttiDefinition(skipExternalRttiDefinition); if (enableCUDA) loweringOptions.setCUDARuntimeCheck(true); std::vector envDefaults = {};