Revert "[flang] add option to generate runtime type info as external" (#146064)
Reverts llvm/llvm-project#145901 Broke shared library builds because of the usage of `skipExternalRttiDefinition` in Lowering.
This commit is contained in:
@@ -1585,7 +1585,6 @@ 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 *);
|
||||
|
||||
@@ -39,9 +39,6 @@ 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;
|
||||
|
||||
@@ -32,19 +32,6 @@ extern llvm::cl::opt<std::size_t> arrayStackAllocationThreshold;
|
||||
/// generated by the frontend.
|
||||
extern llvm::cl::opt<bool> 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<bool> skipExternalRttiDefinition;
|
||||
|
||||
/// Default optimization level used to create Flang pass pipeline is O0.
|
||||
extern llvm::OptimizationLevel defaultOptLevel;
|
||||
|
||||
|
||||
@@ -35,6 +35,32 @@ inline std::int64_t toInt(mlir::arith::ConstantOp cop) {
|
||||
.getSExtValue();
|
||||
}
|
||||
|
||||
// Reconstruct binding tables for dynamic dispatch.
|
||||
using BindingTable = llvm::DenseMap<llvm::StringRef, unsigned>;
|
||||
using BindingTables = llvm::DenseMap<llvm::StringRef, BindingTable>;
|
||||
|
||||
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<fir::TypeInfoOp>()) {
|
||||
unsigned bindingIdx = 0;
|
||||
BindingTable bindings;
|
||||
if (typeInfo.getDispatchTable().empty()) {
|
||||
bindingTables[typeInfo.getSymName()] = bindings;
|
||||
continue;
|
||||
}
|
||||
for (auto dtEntry :
|
||||
typeInfo.getDispatchTable().front().getOps<fir::DTEntryOp>()) {
|
||||
bindings[dtEntry.getMethod()] = bindingIdx;
|
||||
++bindingIdx;
|
||||
}
|
||||
bindingTables[typeInfo.getSymName()] = bindings;
|
||||
}
|
||||
}
|
||||
|
||||
// Translate front-end KINDs for use in the IR and code gen.
|
||||
inline std::vector<fir::KindTy>
|
||||
fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) {
|
||||
|
||||
@@ -38,10 +38,6 @@ 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"};
|
||||
|
||||
@@ -2334,11 +2334,6 @@ 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");
|
||||
|
||||
@@ -52,7 +52,6 @@
|
||||
#include "flang/Optimizer/Dialect/FIROps.h"
|
||||
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
|
||||
#include "flang/Optimizer/HLFIR/HLFIROps.h"
|
||||
#include "flang/Optimizer/Passes/CommandLineOpts.h"
|
||||
#include "flang/Optimizer/Support/DataLayout.h"
|
||||
#include "flang/Optimizer/Support/FatalError.h"
|
||||
#include "flang/Optimizer/Support/InternalNames.h"
|
||||
@@ -263,7 +262,6 @@ public:
|
||||
}
|
||||
|
||||
void createTypeInfo(Fortran::lower::AbstractConverter &converter) {
|
||||
createTypeInfoForTypeDescriptorBuiltinType(converter);
|
||||
while (!registeredTypeInfoA.empty()) {
|
||||
currentTypeInfoStack = ®isteredTypeInfoB;
|
||||
for (const TypeInfo &info : registeredTypeInfoA)
|
||||
@@ -279,22 +277,10 @@ public:
|
||||
private:
|
||||
void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter,
|
||||
const TypeInfo &info) {
|
||||
if (!::skipExternalRttiDefinition)
|
||||
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
|
||||
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
|
||||
createTypeInfoOp(converter, info);
|
||||
}
|
||||
|
||||
void createTypeInfoForTypeDescriptorBuiltinType(
|
||||
Fortran::lower::AbstractConverter &converter) {
|
||||
if (registeredTypeInfoA.empty())
|
||||
return;
|
||||
auto builtinTypeInfoType = llvm::cast<fir::RecordType>(
|
||||
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{};
|
||||
|
||||
@@ -38,7 +38,6 @@
|
||||
#include "flang/Optimizer/Dialect/FIROps.h"
|
||||
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
|
||||
#include "flang/Optimizer/HLFIR/HLFIROps.h"
|
||||
#include "flang/Optimizer/Passes/CommandLineOpts.h"
|
||||
#include "flang/Optimizer/Support/FatalError.h"
|
||||
#include "flang/Optimizer/Support/InternalNames.h"
|
||||
#include "flang/Optimizer/Support/Utils.h"
|
||||
@@ -653,13 +652,8 @@ getLinkageAttribute(fir::FirOpBuilder &builder,
|
||||
// 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 (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() &&
|
||||
(!::skipExternalRttiDefinition ||
|
||||
Fortran::semantics::IsFromBuiltinModule(var.getSymbol())))
|
||||
// with `linkonce_odr` LLVM linkage.
|
||||
if (var.isRuntimeTypeInfoData())
|
||||
return builder.createLinkOnceODRLinkage();
|
||||
if (var.isModuleOrSubmoduleVariable())
|
||||
return {}; // external linkage
|
||||
|
||||
@@ -1294,51 +1294,6 @@ 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 <typename ModOpTy>
|
||||
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<fir::GlobalOp>(name))
|
||||
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
|
||||
global.getSymName());
|
||||
// The global may have already been translated to LLVM.
|
||||
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name))
|
||||
return rewriter.create<mlir::LLVM::AddressOfOp>(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<mlir::LLVM::ZeroOp>(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<mlir::LLVM::GlobalOp>(
|
||||
loc, llvmPtrTy, /*constant=*/true, mlir::LLVM::Linkage::External, name,
|
||||
mlir::Attribute());
|
||||
rewriter.restoreInsertionPoint(insertPt);
|
||||
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
|
||||
global.getSymName());
|
||||
}
|
||||
|
||||
/// Common base class for embox to descriptor conversion.
|
||||
template <typename OP>
|
||||
struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
|
||||
@@ -1451,6 +1406,36 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
|
||||
stride);
|
||||
}
|
||||
|
||||
/// Get the address of the type descriptor global variable that was created by
|
||||
/// lowering for derived type \p recType.
|
||||
template <typename ModOpTy>
|
||||
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<fir::GlobalOp>(name)) {
|
||||
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
|
||||
global.getSymName());
|
||||
}
|
||||
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
|
||||
// The global may have already been translated to LLVM.
|
||||
return rewriter.create<mlir::LLVM::AddressOfOp>(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<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
|
||||
}
|
||||
|
||||
template <typename ModOpTy>
|
||||
mlir::Value populateDescriptor(mlir::Location loc, ModOpTy mod,
|
||||
fir::BaseBoxType boxTy, mlir::Type inputType,
|
||||
@@ -1515,8 +1500,7 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
|
||||
mlir::Type innerType = fir::unwrapInnerType(inputType);
|
||||
if (innerType && mlir::isa<fir::RecordType>(innerType)) {
|
||||
auto recTy = mlir::dyn_cast<fir::RecordType>(innerType);
|
||||
typeDesc =
|
||||
getTypeDescriptor(mod, rewriter, loc, recTy, this->options);
|
||||
typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy);
|
||||
} else {
|
||||
// Unlimited polymorphic type descriptor with no record type. Set
|
||||
// type descriptor address to a clean state.
|
||||
@@ -1524,8 +1508,8 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
|
||||
loc, ::getLlvmPtrType(mod.getContext()));
|
||||
}
|
||||
} else {
|
||||
typeDesc = getTypeDescriptor(
|
||||
mod, rewriter, loc, fir::unwrapIfDerived(boxTy), this->options);
|
||||
typeDesc = getTypeDescriptor(mod, rewriter, loc,
|
||||
fir::unwrapIfDerived(boxTy));
|
||||
}
|
||||
}
|
||||
if (typeDesc)
|
||||
@@ -3037,10 +3021,22 @@ struct TypeDescOpConversion : public fir::FIROpConversion<fir::TypeDescOp> {
|
||||
assert(mlir::isa<fir::RecordType>(inTy) && "expecting fir.type");
|
||||
auto recordType = mlir::dyn_cast<fir::RecordType>(inTy);
|
||||
auto module = typeDescOp.getOperation()->getParentOfType<mlir::ModuleOp>();
|
||||
mlir::Value typeDesc = getTypeDescriptor(
|
||||
module, rewriter, typeDescOp.getLoc(), recordType, this->options);
|
||||
rewriter.replaceOp(typeDescOp, typeDesc);
|
||||
return mlir::success();
|
||||
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<mlir::LLVM::GlobalOp>(typeDescName)) {
|
||||
rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
|
||||
typeDescOp, llvmPtrTy, global.getSymName());
|
||||
return mlir::success();
|
||||
} else if (auto global = module.lookupSymbol<fir::GlobalOp>(typeDescName)) {
|
||||
rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
|
||||
typeDescOp, llvmPtrTy, global.getSymName());
|
||||
return mlir::success();
|
||||
}
|
||||
return mlir::failure();
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -39,12 +39,6 @@ cl::opt<bool> ignoreMissingTypeDescriptors(
|
||||
"translating FIR to LLVM"),
|
||||
cl::init(false), cl::Hidden);
|
||||
|
||||
cl::opt<bool> 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};
|
||||
|
||||
@@ -108,7 +108,6 @@ 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 =
|
||||
|
||||
@@ -16,6 +16,7 @@
|
||||
#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"
|
||||
@@ -37,45 +38,6 @@ namespace fir {
|
||||
using namespace fir;
|
||||
using namespace mlir;
|
||||
|
||||
// Reconstruct binding tables for dynamic dispatch.
|
||||
using BindingTable = llvm::DenseMap<llvm::StringRef, unsigned>;
|
||||
using BindingTables = llvm::DenseMap<llvm::StringRef, BindingTable>;
|
||||
|
||||
static std::string getTypeDescriptorTypeName() {
|
||||
llvm::SmallVector<llvm::StringRef, 1> modules = {
|
||||
Fortran::semantics::typeInfoBuiltinModule};
|
||||
return fir::NameUniquer::doType(modules, /*proc=*/{}, /*blockId=*/0,
|
||||
Fortran::semantics::typeDescriptorTypeName,
|
||||
/*kinds=*/{});
|
||||
}
|
||||
|
||||
static std::optional<mlir::Type>
|
||||
buildBindingTables(BindingTables &bindingTables, mlir::ModuleOp mod) {
|
||||
|
||||
std::optional<mlir::Type> 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<fir::TypeInfoOp>()) {
|
||||
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<fir::DTEntryOp>()) {
|
||||
bindings[dtEntry.getMethod()] = bindingIdx;
|
||||
++bindingIdx;
|
||||
}
|
||||
bindingTables[typeInfo.getSymName()] = bindings;
|
||||
}
|
||||
return typeDescriptorType;
|
||||
}
|
||||
|
||||
namespace {
|
||||
|
||||
/// SelectTypeOp converted to an if-then-else chain
|
||||
@@ -115,10 +77,9 @@ private:
|
||||
struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
|
||||
using OpConversionPattern<fir::DispatchOp>::OpConversionPattern;
|
||||
|
||||
DispatchOpConv(mlir::MLIRContext *ctx, const BindingTables &bindingTables,
|
||||
std::optional<mlir::Type> typeDescriptorType)
|
||||
DispatchOpConv(mlir::MLIRContext *ctx, const BindingTables &bindingTables)
|
||||
: mlir::OpConversionPattern<fir::DispatchOp>(ctx),
|
||||
bindingTables(bindingTables), typeDescriptorType{typeDescriptorType} {}
|
||||
bindingTables(bindingTables) {}
|
||||
|
||||
llvm::LogicalResult
|
||||
matchAndRewrite(fir::DispatchOp dispatch, OpAdaptor adaptor,
|
||||
@@ -150,11 +111,13 @@ struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
|
||||
|
||||
mlir::Value passedObject = dispatch.getObject();
|
||||
|
||||
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;
|
||||
auto module = dispatch.getOperation()->getParentOfType<mlir::ModuleOp>();
|
||||
Type typeDescTy;
|
||||
std::string typeDescName =
|
||||
NameUniquer::getTypeDescriptorName(recordType.getName());
|
||||
if (auto global = module.lookupSymbol<fir::GlobalOp>(typeDescName)) {
|
||||
typeDescTy = global.getType();
|
||||
}
|
||||
|
||||
// clang-format off
|
||||
// Before:
|
||||
@@ -250,7 +213,6 @@ struct DispatchOpConv : public OpConversionPattern<fir::DispatchOp> {
|
||||
|
||||
private:
|
||||
BindingTables bindingTables;
|
||||
std::optional<mlir::Type> typeDescriptorType;
|
||||
};
|
||||
|
||||
/// Convert FIR structured control flow ops to CFG ops.
|
||||
@@ -267,11 +229,10 @@ public:
|
||||
mlir::RewritePatternSet patterns(context);
|
||||
|
||||
BindingTables bindingTables;
|
||||
std::optional<mlir::Type> typeDescriptorType =
|
||||
buildBindingTables(bindingTables, mod);
|
||||
buildBindingTables(bindingTables, mod);
|
||||
|
||||
patterns.insert<SelectTypeConv>(context);
|
||||
patterns.insert<DispatchOpConv>(context, bindingTables, typeDescriptorType);
|
||||
patterns.insert<DispatchOpConv>(context, bindingTables);
|
||||
mlir::ConversionTarget target(*context);
|
||||
target.addLegalDialect<mlir::affine::AffineDialect,
|
||||
mlir::cf::ControlFlowDialect, FIROpsDialect,
|
||||
@@ -418,11 +379,16 @@ llvm::LogicalResult SelectTypeConv::genTypeLadderStep(
|
||||
} else if (auto a = mlir::dyn_cast<fir::SubclassAttr>(attr)) {
|
||||
// Retrieve the type descriptor from the type guard statement record type.
|
||||
assert(mlir::isa<fir::RecordType>(a.getType()) && "expect fir.record type");
|
||||
mlir::Value typeDescAddr =
|
||||
rewriter.create<fir::TypeDescOp>(loc, mlir::TypeAttr::get(a.getType()));
|
||||
mlir::Type refNoneType = ReferenceType::get(rewriter.getNoneType());
|
||||
fir::RecordType recTy = mlir::dyn_cast<fir::RecordType>(a.getType());
|
||||
std::string typeDescName =
|
||||
fir::NameUniquer::getTypeDescriptorName(recTy.getName());
|
||||
auto typeDescGlobal = mod.lookupSymbol<fir::GlobalOp>(typeDescName);
|
||||
auto typeDescAddr = rewriter.create<fir::AddrOfOp>(
|
||||
loc, fir::ReferenceType::get(typeDescGlobal.getType()),
|
||||
typeDescGlobal.getSymbol());
|
||||
mlir::Type typeDescTy = ReferenceType::get(rewriter.getNoneType());
|
||||
mlir::Value typeDesc =
|
||||
rewriter.create<ConvertOp>(loc, refNoneType, typeDescAddr);
|
||||
rewriter.create<ConvertOp>(loc, typeDescTy, typeDescAddr);
|
||||
|
||||
// Prepare the selector descriptor for the runtime call.
|
||||
mlir::Type descNoneTy = fir::BoxType::get(rewriter.getNoneType());
|
||||
@@ -440,7 +406,7 @@ llvm::LogicalResult SelectTypeConv::genTypeLadderStep(
|
||||
mlir::UnitAttr::get(rewriter.getContext()));
|
||||
callee =
|
||||
fir::createFuncOp(rewriter.getUnknownLoc(), mod, fctName,
|
||||
rewriter.getFunctionType({descNoneTy, refNoneType},
|
||||
rewriter.getFunctionType({descNoneTy, typeDescTy},
|
||||
rewriter.getI1Type()),
|
||||
{runtimeAttr});
|
||||
}
|
||||
@@ -469,11 +435,20 @@ SelectTypeConv::genTypeDescCompare(mlir::Location loc, mlir::Value selector,
|
||||
mlir::Type ty, mlir::ModuleOp mod,
|
||||
mlir::PatternRewriter &rewriter) const {
|
||||
assert(mlir::isa<fir::RecordType>(ty) && "expect fir.record type");
|
||||
mlir::Value typeDescAddr =
|
||||
rewriter.create<fir::TypeDescOp>(loc, mlir::TypeAttr::get(ty));
|
||||
mlir::Value selectorTdescAddr = rewriter.create<fir::BoxTypeDescOp>(
|
||||
loc, typeDescAddr.getType(), selector);
|
||||
fir::RecordType recTy = mlir::dyn_cast<fir::RecordType>(ty);
|
||||
std::string typeDescName =
|
||||
fir::NameUniquer::getTypeDescriptorName(recTy.getName());
|
||||
auto typeDescGlobal = mod.lookupSymbol<fir::GlobalOp>(typeDescName);
|
||||
if (!typeDescGlobal)
|
||||
return {};
|
||||
auto typeDescAddr = rewriter.create<fir::AddrOfOp>(
|
||||
loc, fir::ReferenceType::get(typeDescGlobal.getType()),
|
||||
typeDescGlobal.getSymbol());
|
||||
auto intPtrTy = rewriter.getIndexType();
|
||||
mlir::Type tdescType =
|
||||
fir::TypeDescType::get(mlir::NoneType::get(rewriter.getContext()));
|
||||
mlir::Value selectorTdescAddr =
|
||||
rewriter.create<fir::BoxTypeDescOp>(loc, tdescType, selector);
|
||||
auto typeDescInt =
|
||||
rewriter.create<fir::ConvertOp>(loc, intPtrTy, typeDescAddr);
|
||||
auto selectorTdescInt =
|
||||
|
||||
@@ -1,47 +0,0 @@
|
||||
! 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
|
||||
@@ -30,8 +30,8 @@ contains
|
||||
|
||||
! CHECK-LABEL: func.func @_QMselect_type_2Pselect_type1(
|
||||
! CHECK-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMselect_type_2Tp1{a:i32,b:i32}>> {fir.bindc_name = "a"}) {
|
||||
! 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<none>
|
||||
! CHECK: %[[TDESC_P3_ADDR:.*]] = fir.address_of(@_QMselect_type_2E.dt.p3) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CHECK: %[[TDESC_P3_CONV:.*]] = fir.convert %[[TDESC_P3_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_2Tp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CHECK: %[[CLASS_IS_CMP:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P3_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CHECK: cf.cond_br %[[CLASS_IS_CMP]], ^[[CLASS_IS_P3_BLK:.*]], ^[[NOT_CLASS_IS_P3_BLK:.*]]
|
||||
@@ -40,8 +40,8 @@ contains
|
||||
! 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.type_desc !fir.type<_QMselect_type_2Tp1
|
||||
! CHECK: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref<none>
|
||||
! CHECK: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_2E.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CHECK: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CHECK: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_2Tp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CHECK: %[[CLASS_IS_CMP:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CHECK: cf.cond_br %[[CLASS_IS_CMP]], ^bb[[CLASS_IS_P1]], ^bb[[NOT_CLASS_IS_P1]]
|
||||
|
||||
@@ -68,15 +68,15 @@ contains
|
||||
|
||||
! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type1(
|
||||
! CFG-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>> {fir.bindc_name = "a"}) {
|
||||
! 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.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.tdesc<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.tdesc<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> index
|
||||
! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> index
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.tdesc<none>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> index
|
||||
! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<none>) -> 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.type_desc !fir.type<_QMselect_type_lower_testTp2{{.*}}
|
||||
! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.tdesc<{{.*}}>) -> !fir.ref<none>
|
||||
! CFG: %[[TDESC_P2_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p2) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P2_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS]], ^bb[[CLASS_IS_P2_BLK:.*]], ^[[NOT_CLASS_IS_P2_BLK:.*]]
|
||||
@@ -87,8 +87,8 @@ contains
|
||||
! 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.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<none>
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS]], ^bb[[CLASS_IS_P1_BLK]], ^bb[[NOT_CLASS_IS_P1_BLK]]
|
||||
@@ -126,15 +126,15 @@ contains
|
||||
! CFG: %[[GET_CLASS:.*]] = fir.call @_QMselect_type_lower_testPget_class() {{.*}} : () -> !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>
|
||||
! CFG: fir.save_result %[[GET_CLASS]] to %[[CLASS_ALLOCA]] : !fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>, !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>
|
||||
! CFG: %[[LOAD_CLASS:.*]] = fir.load %[[CLASS_ALLOCA]] : !fir.ref<!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>
|
||||
! 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.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>) -> !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_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[CLASS_TDESC:.*]] = fir.box_tdesc %[[LOAD_CLASS]] : (!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>) -> !fir.tdesc<none>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> index
|
||||
! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[CLASS_TDESC]] : (!fir.tdesc<none>) -> 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.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<none>
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[LOAD_CLASS]] : (!fir.class<!fir.ptr<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS]], ^[[CLASS_IS_BLK:.*]], ^[[NOT_CLASS_IS_BLK:.*]]
|
||||
@@ -176,15 +176,15 @@ contains
|
||||
! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type3(
|
||||
! CFG-SAME: %[[ARG0:.*]]: !fir.ref<!fir.class<!fir.ptr<!fir.array<?x!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>>>> {fir.bindc_name = "a"}) {
|
||||
! CFG: %[[SELECTOR:.*]] = fir.embox %{{.*}} source_box %{{.*}} : (!fir.ref<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>, !fir.class<{{.*}}>) -> !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>
|
||||
! 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.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !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_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[SELECTOR_TDESC:.*]] = fir.box_tdesc %[[SELECTOR]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.tdesc<none>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> index
|
||||
! CFG: %[[TDESC_CONV:.*]] = fir.convert %[[SELECTOR_TDESC]] : (!fir.tdesc<none>) -> 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.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<none>
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[SELECTOR]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS]], ^[[CLASS_IS_BLK:.*]], ^[[NOT_CLASS_IS:.*]]
|
||||
@@ -222,25 +222,25 @@ contains
|
||||
|
||||
! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type4(
|
||||
! CFG-SAME: %[[ARG0:.*]]: !fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>> {fir.bindc_name = "a"}) {
|
||||
! CFG: %[[TDESC_P3_8_ADDR:.*]] = fir.type_desc !fir.type<_QMselect_type_lower_testTp3K8
|
||||
! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !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_P3_8_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p3.8) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.tdesc<none>
|
||||
! CFG: %[[TDESC_P3_8_CONV:.*]] = fir.convert %[[TDESC_P3_8_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> index
|
||||
! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<none>) -> 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.type_desc !fir.type<_QMselect_type_lower_testTp3K4
|
||||
! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !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_P3_4_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p3.4) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[BOX_TDESC:.*]] = fir.box_tdesc %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.tdesc<none>
|
||||
! CFG: %[[TDESC_P3_4_CONV:.*]] = fir.convert %[[TDESC_P3_4_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> index
|
||||
! CFG: %[[BOX_TDESC_CONV:.*]] = fir.convert %[[BOX_TDESC]] : (!fir.tdesc<none>) -> 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.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<none>
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<!fir.type<_QMselect_type_lower_testTp1{a:i32,b:i32}>>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS]], ^[[P1_BLK:.*]], ^[[NOT_P1_BLK:.*]]
|
||||
@@ -409,8 +409,8 @@ contains
|
||||
|
||||
! CFG-LABEL: func.func @_QMselect_type_lower_testPselect_type7(
|
||||
! CFG-SAME: %[[ARG0:.*]]: !fir.class<none> {fir.bindc_name = "a"}) {
|
||||
! 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<none>
|
||||
! CFG: %[[TDESC_P4_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p4) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P4_CONV:.*]] = fir.convert %[[TDESC_P4_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<none>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS_P4:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P4_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS_P4]], ^[[CLASS_IS_P4_BLK:.*]], ^[[CLASS_NOT_P4_BLK:.*]]
|
||||
@@ -419,16 +419,16 @@ contains
|
||||
! 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.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<none>
|
||||
! CFG: %[[TDESC_P1_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p1) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P1_CONV:.*]] = fir.convert %[[TDESC_P1_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<none>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS_P1:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P1_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> 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.type_desc !fir.type<_QMselect_type_lower_testTp2
|
||||
! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.tdesc{{.*}}>) -> !fir.ref<none>
|
||||
! CFG: %[[TDESC_P2_ADDR:.*]] = fir.address_of(@_QMselect_type_lower_testE.dt.p2) : !fir.ref<!fir.type<{{.*}}>>
|
||||
! CFG: %[[TDESC_P2_CONV:.*]] = fir.convert %[[TDESC_P2_ADDR]] : (!fir.ref<!fir.type<{{.*}}>>) -> !fir.ref<none>
|
||||
! CFG: %[[BOX_NONE:.*]] = fir.convert %[[ARG0]] : (!fir.class<none>) -> !fir.box<none>
|
||||
! CFG: %[[CLASS_IS_P2:.*]] = fir.call @_FortranAClassIs(%[[BOX_NONE]], %[[TDESC_P2_CONV]]) : (!fir.box<none>, !fir.ref<none>) -> i1
|
||||
! CFG: cf.cond_br %[[CLASS_IS_P2]], ^bb[[CLASS_IS_P2_BLK]], ^bb[[CLASS_NOT_P2_BLK]]
|
||||
|
||||
Reference in New Issue
Block a user