Skip to content

Commit 02c94ed

Browse files
committed
[flang] add option to generate runtime type info as external
1 parent f64d5df commit 02c94ed

File tree

15 files changed

+256
-153
lines changed

15 files changed

+256
-153
lines changed

flang/include/flang/Evaluate/tools.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1575,6 +1575,7 @@ bool IsExtensibleType(const DerivedTypeSpec *);
15751575
bool IsSequenceOrBindCType(const DerivedTypeSpec *);
15761576
bool IsBuiltinDerivedType(const DerivedTypeSpec *derived, const char *name);
15771577
bool IsBuiltinCPtr(const Symbol &);
1578+
bool IsFromBuiltinModule(const Symbol &);
15781579
bool IsEventType(const DerivedTypeSpec *);
15791580
bool IsLockType(const DerivedTypeSpec *);
15801581
bool IsNotifyType(const DerivedTypeSpec *);

flang/include/flang/Optimizer/CodeGen/CodeGen.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,9 @@ struct FIRToLLVMPassOptions {
3939
// that such programs would crash at runtime if the derived type descriptors
4040
// are required by the runtime, so this is only an option to help debugging.
4141
bool ignoreMissingTypeDescriptors = false;
42+
// Similar to ignoreMissingTypeDescriptors, but generate external declaration
43+
// for the missing type descriptor globals instead.
44+
bool skipExternalRttiDefinition = false;
4245

4346
// Generate TBAA information for FIR types and memory accessing operations.
4447
bool applyTBAA = false;

flang/include/flang/Optimizer/Passes/CommandLineOpts.h

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,19 @@ extern llvm::cl::opt<std::size_t> arrayStackAllocationThreshold;
3232
/// generated by the frontend.
3333
extern llvm::cl::opt<bool> ignoreMissingTypeDescriptors;
3434

35+
/// Shared option in tools to only generate rtti static object definitions for
36+
/// derived types defined in the current compilation unit. Derived type
37+
/// descriptor object for types defined in other objects will only be declared
38+
/// as external. This also changes the linkage of rtti objects defined in the
39+
/// current compilation unit from linkonce_odr to external so that unused rtti
40+
/// objects are retained and can be accessed from other compilation units. This
41+
/// is an experimental option to explore compilation speed improvements and is
42+
/// an ABI breaking change because of the linkage change.
43+
/// It will also require linking against module file objects of modules defining
44+
/// only types (even for trivial types without type bound procedures, which
45+
/// differs from most compilers).
46+
extern llvm::cl::opt<bool> skipExternalRttiDefinition;
47+
3548
/// Default optimization level used to create Flang pass pipeline is O0.
3649
extern llvm::OptimizationLevel defaultOptLevel;
3750

flang/include/flang/Optimizer/Support/Utils.h

Lines changed: 0 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -35,32 +35,6 @@ inline std::int64_t toInt(mlir::arith::ConstantOp cop) {
3535
.getSExtValue();
3636
}
3737

38-
// Reconstruct binding tables for dynamic dispatch.
39-
using BindingTable = llvm::DenseMap<llvm::StringRef, unsigned>;
40-
using BindingTables = llvm::DenseMap<llvm::StringRef, BindingTable>;
41-
42-
inline void buildBindingTables(BindingTables &bindingTables,
43-
mlir::ModuleOp mod) {
44-
45-
// The binding tables are defined in FIR after lowering inside fir.type_info
46-
// operations. Go through each binding tables and store the procedure name and
47-
// binding index for later use by the fir.dispatch conversion pattern.
48-
for (auto typeInfo : mod.getOps<fir::TypeInfoOp>()) {
49-
unsigned bindingIdx = 0;
50-
BindingTable bindings;
51-
if (typeInfo.getDispatchTable().empty()) {
52-
bindingTables[typeInfo.getSymName()] = bindings;
53-
continue;
54-
}
55-
for (auto dtEntry :
56-
typeInfo.getDispatchTable().front().getOps<fir::DTEntryOp>()) {
57-
bindings[dtEntry.getMethod()] = bindingIdx;
58-
++bindingIdx;
59-
}
60-
bindingTables[typeInfo.getSymName()] = bindings;
61-
}
62-
}
63-
6438
// Translate front-end KINDs for use in the IR and code gen.
6539
inline std::vector<fir::KindTy>
6640
fromDefaultKinds(const Fortran::common::IntrinsicTypeDefaultKinds &defKinds) {

flang/include/flang/Semantics/runtime-type-info.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,10 @@ RuntimeDerivedTypeTables BuildRuntimeDerivedTypeTables(SemanticsContext &);
3838
/// to describe other derived types at runtime in flang descriptor.
3939
constexpr char typeInfoBuiltinModule[]{"__fortran_type_info"};
4040

41+
/// Name of the builtin derived type in __fortran_type_inf that is used for
42+
/// derived type descriptors.
43+
constexpr char typeDescriptorTypeName[]{"derivedtype"};
44+
4145
/// Name of the bindings descriptor component in the DerivedType type of the
4246
/// __Fortran_type_info module
4347
constexpr char bindingDescCompName[]{"binding"};

flang/lib/Evaluate/tools.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2334,6 +2334,11 @@ bool IsBuiltinCPtr(const Symbol &symbol) {
23342334
return false;
23352335
}
23362336

2337+
bool IsFromBuiltinModule(const Symbol &symbol) {
2338+
const Scope &scope{symbol.GetUltimate().owner()};
2339+
return IsSameModule(&scope, scope.context().GetBuiltinsScope());
2340+
}
2341+
23372342
bool IsIsoCType(const DerivedTypeSpec *derived) {
23382343
return IsBuiltinDerivedType(derived, "c_ptr") ||
23392344
IsBuiltinDerivedType(derived, "c_funptr");

flang/lib/Lower/Bridge.cpp

Lines changed: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,7 @@
5252
#include "flang/Optimizer/Dialect/FIROps.h"
5353
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
5454
#include "flang/Optimizer/HLFIR/HLFIROps.h"
55+
#include "flang/Optimizer/Passes/CommandLineOpts.h"
5556
#include "flang/Optimizer/Support/DataLayout.h"
5657
#include "flang/Optimizer/Support/FatalError.h"
5758
#include "flang/Optimizer/Support/InternalNames.h"
@@ -262,6 +263,7 @@ class TypeInfoConverter {
262263
}
263264

264265
void createTypeInfo(Fortran::lower::AbstractConverter &converter) {
266+
createTypeInfoForTypeDescriptorBuiltinType(converter);
265267
while (!registeredTypeInfoA.empty()) {
266268
currentTypeInfoStack = &registeredTypeInfoB;
267269
for (const TypeInfo &info : registeredTypeInfoA)
@@ -277,10 +279,22 @@ class TypeInfoConverter {
277279
private:
278280
void createTypeInfoOpAndGlobal(Fortran::lower::AbstractConverter &converter,
279281
const TypeInfo &info) {
280-
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
282+
if (!::skipExternalRttiDefinition)
283+
Fortran::lower::createRuntimeTypeInfoGlobal(converter, info.symbol.get());
281284
createTypeInfoOp(converter, info);
282285
}
283286

287+
void createTypeInfoForTypeDescriptorBuiltinType(
288+
Fortran::lower::AbstractConverter &converter) {
289+
if (registeredTypeInfoA.empty())
290+
return;
291+
auto builtinTypeInfoType = llvm::cast<fir::RecordType>(
292+
converter.genType(registeredTypeInfoA[0].symbol.get()));
293+
converter.getFirOpBuilder().createTypeInfoOp(
294+
registeredTypeInfoA[0].loc, builtinTypeInfoType,
295+
/*parentType=*/fir::RecordType{});
296+
}
297+
284298
void createTypeInfoOp(Fortran::lower::AbstractConverter &converter,
285299
const TypeInfo &info) {
286300
fir::RecordType parentType{};

flang/lib/Lower/ConvertVariable.cpp

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@
3838
#include "flang/Optimizer/Dialect/FIROps.h"
3939
#include "flang/Optimizer/Dialect/Support/FIRContext.h"
4040
#include "flang/Optimizer/HLFIR/HLFIROps.h"
41+
#include "flang/Optimizer/Passes/CommandLineOpts.h"
4142
#include "flang/Optimizer/Support/FatalError.h"
4243
#include "flang/Optimizer/Support/InternalNames.h"
4344
#include "flang/Optimizer/Support/Utils.h"
@@ -652,8 +653,13 @@ getLinkageAttribute(fir::FirOpBuilder &builder,
652653
// Runtime type info for a same derived type is identical in each compilation
653654
// unit. It desired to avoid having to link against module that only define a
654655
// type. Therefore the runtime type info is generated everywhere it is needed
655-
// with `linkonce_odr` LLVM linkage.
656-
if (var.isRuntimeTypeInfoData())
656+
// with `linkonce_odr` LLVM linkage (unless the skipExternalRttiDefinition
657+
// option is set, in which case one will need to link against objects of
658+
// modules defining types). Builtin objects rtti is always generated because
659+
// the builtin module is currently not compiled or part of the runtime.
660+
if (var.isRuntimeTypeInfoData() &&
661+
(!::skipExternalRttiDefinition ||
662+
Fortran::semantics::IsFromBuiltinModule(var.getSymbol())))
657663
return builder.createLinkOnceODRLinkage();
658664
if (var.isModuleOrSubmoduleVariable())
659665
return {}; // external linkage

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 53 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -1294,6 +1294,51 @@ genCUFAllocDescriptor(mlir::Location loc,
12941294
.getResult();
12951295
}
12961296

1297+
/// Get the address of the type descriptor global variable that was created by
1298+
/// lowering for derived type \p recType.
1299+
template <typename ModOpTy>
1300+
static mlir::Value
1301+
getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter,
1302+
mlir::Location loc, fir::RecordType recType,
1303+
const fir::FIRToLLVMPassOptions &options) {
1304+
std::string name =
1305+
options.typeDescriptorsRenamedForAssembly
1306+
? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1307+
: fir::NameUniquer::getTypeDescriptorName(recType.getName());
1308+
mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
1309+
if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name))
1310+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1311+
global.getSymName());
1312+
// The global may have already been translated to LLVM.
1313+
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name))
1314+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1315+
global.getSymName());
1316+
// Type info derived types do not have type descriptors since they are the
1317+
// types defining type descriptors.
1318+
if (options.ignoreMissingTypeDescriptors ||
1319+
fir::NameUniquer::belongsToModule(
1320+
name, Fortran::semantics::typeInfoBuiltinModule))
1321+
return rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
1322+
1323+
if (!options.skipExternalRttiDefinition)
1324+
fir::emitFatalError(loc,
1325+
"runtime derived type info descriptor was not "
1326+
"generated and skipExternalRttiDefinition and "
1327+
"ignoreMissingTypeDescriptors options are not set");
1328+
1329+
// Rtti for a derived type defined in another compilation unit and for which
1330+
// rtti was not defined in lowering because of the skipExternalRttiDefinition
1331+
// option. Generate the object declaration now.
1332+
auto insertPt = rewriter.saveInsertionPoint();
1333+
rewriter.setInsertionPoint(mod.getBody(), mod.getBody()->end());
1334+
mlir::LLVM::GlobalOp global = rewriter.create<mlir::LLVM::GlobalOp>(
1335+
loc, llvmPtrTy, /*constant=*/true, mlir::LLVM::Linkage::External, name,
1336+
mlir::Attribute());
1337+
rewriter.restoreInsertionPoint(insertPt);
1338+
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1339+
global.getSymName());
1340+
}
1341+
12971342
/// Common base class for embox to descriptor conversion.
12981343
template <typename OP>
12991344
struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
@@ -1406,36 +1451,6 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
14061451
stride);
14071452
}
14081453

1409-
/// Get the address of the type descriptor global variable that was created by
1410-
/// lowering for derived type \p recType.
1411-
template <typename ModOpTy>
1412-
mlir::Value
1413-
getTypeDescriptor(ModOpTy mod, mlir::ConversionPatternRewriter &rewriter,
1414-
mlir::Location loc, fir::RecordType recType) const {
1415-
std::string name =
1416-
this->options.typeDescriptorsRenamedForAssembly
1417-
? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1418-
: fir::NameUniquer::getTypeDescriptorName(recType.getName());
1419-
mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
1420-
if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name)) {
1421-
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1422-
global.getSymName());
1423-
}
1424-
if (auto global = mod.template lookupSymbol<mlir::LLVM::GlobalOp>(name)) {
1425-
// The global may have already been translated to LLVM.
1426-
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
1427-
global.getSymName());
1428-
}
1429-
// Type info derived types do not have type descriptors since they are the
1430-
// types defining type descriptors.
1431-
if (!this->options.ignoreMissingTypeDescriptors &&
1432-
!fir::NameUniquer::belongsToModule(
1433-
name, Fortran::semantics::typeInfoBuiltinModule))
1434-
fir::emitFatalError(
1435-
loc, "runtime derived type info descriptor was not generated");
1436-
return rewriter.create<mlir::LLVM::ZeroOp>(loc, llvmPtrTy);
1437-
}
1438-
14391454
template <typename ModOpTy>
14401455
mlir::Value populateDescriptor(mlir::Location loc, ModOpTy mod,
14411456
fir::BaseBoxType boxTy, mlir::Type inputType,
@@ -1500,16 +1515,17 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
15001515
mlir::Type innerType = fir::unwrapInnerType(inputType);
15011516
if (innerType && mlir::isa<fir::RecordType>(innerType)) {
15021517
auto recTy = mlir::dyn_cast<fir::RecordType>(innerType);
1503-
typeDesc = getTypeDescriptor(mod, rewriter, loc, recTy);
1518+
typeDesc =
1519+
getTypeDescriptor(mod, rewriter, loc, recTy, this->options);
15041520
} else {
15051521
// Unlimited polymorphic type descriptor with no record type. Set
15061522
// type descriptor address to a clean state.
15071523
typeDesc = rewriter.create<mlir::LLVM::ZeroOp>(
15081524
loc, ::getLlvmPtrType(mod.getContext()));
15091525
}
15101526
} else {
1511-
typeDesc = getTypeDescriptor(mod, rewriter, loc,
1512-
fir::unwrapIfDerived(boxTy));
1527+
typeDesc = getTypeDescriptor(
1528+
mod, rewriter, loc, fir::unwrapIfDerived(boxTy), this->options);
15131529
}
15141530
}
15151531
if (typeDesc)
@@ -3021,22 +3037,10 @@ struct TypeDescOpConversion : public fir::FIROpConversion<fir::TypeDescOp> {
30213037
assert(mlir::isa<fir::RecordType>(inTy) && "expecting fir.type");
30223038
auto recordType = mlir::dyn_cast<fir::RecordType>(inTy);
30233039
auto module = typeDescOp.getOperation()->getParentOfType<mlir::ModuleOp>();
3024-
std::string typeDescName =
3025-
this->options.typeDescriptorsRenamedForAssembly
3026-
? fir::NameUniquer::getTypeDescriptorAssemblyName(
3027-
recordType.getName())
3028-
: fir::NameUniquer::getTypeDescriptorName(recordType.getName());
3029-
auto llvmPtrTy = ::getLlvmPtrType(typeDescOp.getContext());
3030-
if (auto global = module.lookupSymbol<mlir::LLVM::GlobalOp>(typeDescName)) {
3031-
rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
3032-
typeDescOp, llvmPtrTy, global.getSymName());
3033-
return mlir::success();
3034-
} else if (auto global = module.lookupSymbol<fir::GlobalOp>(typeDescName)) {
3035-
rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
3036-
typeDescOp, llvmPtrTy, global.getSymName());
3037-
return mlir::success();
3038-
}
3039-
return mlir::failure();
3040+
mlir::Value typeDesc = getTypeDescriptor(
3041+
module, rewriter, typeDescOp.getLoc(), recordType, this->options);
3042+
rewriter.replaceOp(typeDescOp, typeDesc);
3043+
return mlir::success();
30403044
}
30413045
};
30423046

flang/lib/Optimizer/Passes/CommandLineOpts.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ cl::opt<bool> ignoreMissingTypeDescriptors(
3939
"translating FIR to LLVM"),
4040
cl::init(false), cl::Hidden);
4141

42+
cl::opt<bool> skipExternalRttiDefinition(
43+
"skip-external-rtti-definition", llvm::cl::init(false),
44+
llvm::cl::desc("do not define rtti static objects for types belonging to "
45+
"other compilation units"),
46+
cl::Hidden);
47+
4248
OptimizationLevel defaultOptLevel{OptimizationLevel::O0};
4349

4450
codegenoptions::DebugInfoKind noDebugInfo{codegenoptions::NoDebugInfo};

0 commit comments

Comments
 (0)