Currently, code generation was creating weak symbols for derived type descriptor global it could not find in the current compilation unit. The rational is that: - the derived type descriptors of external module derived types are generated in the compilation unit that compiled the module so that the type descriptor address is uniquely associated with the type. - some types do not have derived type descriptors: the builtin derived types used to create derived type descriptors. The runtime knows about them and does not need them to accomplish the feat of describing themselves. Hence, all unresolved derived type descriptors in codegen cannot be assumed to be resolved at link time. However, this caused immense debugging pain when, for some reasons, derived type descriptor that should be generated were not. This caused random runtime failures instead of a much cleaner link time failure. Improve this situation by allowing codegen to detect the builtin derived types that have no derived type descriptors and requiring the other unresolved derived type descriptor to be resolved at link time. Also make derived type descriptor constant data since this was a TODO and makes the situation even cleaner. This requiring telling lowering which compiler created symbols can be placed in read only memory. I considered using PARAMETER, but I have mixed feeling using it since that would cause the initializer expressions of derived type descriptor to be invalid from a Fortran point of view since pointer targets cannot be parameters. I do not want to start misusing Fortran attributes, even if I think it is quite unlikely semantics would currently complain. I also do not want to rely on the fact that all object symbols with the CompilerCreated flags are currently constant data. This could easily change in the future and cause runtime bugs if lowering rely on this while the assumption is not loud and clear in semantics. Instead, add a ReadOnly symbol flag to tell lowering that a compiler generated symbol can be placed in read only memory. Differential Revision: https://reviews.llvm.org/D119555
327 lines
10 KiB
C++
327 lines
10 KiB
C++
//===-- InternalNames.cpp -------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
//
|
|
// Coding style: https://mlir.llvm.org/getting_started/DeveloperGuide/
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "flang/Optimizer/Support/InternalNames.h"
|
|
#include "flang/Optimizer/Dialect/FIRType.h"
|
|
#include "mlir/IR/BuiltinTypes.h"
|
|
#include "mlir/IR/Diagnostics.h"
|
|
#include "llvm/Support/CommandLine.h"
|
|
|
|
static llvm::cl::opt<std::string> mainEntryName(
|
|
"main-entry-name",
|
|
llvm::cl::desc("override the name of the default PROGRAM entry (may be "
|
|
"helpful for using other runtimes)"));
|
|
|
|
constexpr std::int64_t badValue = -1;
|
|
|
|
inline std::string prefix() { return "_Q"; }
|
|
|
|
static std::string doModules(llvm::ArrayRef<llvm::StringRef> mods) {
|
|
std::string result;
|
|
auto *token = "M";
|
|
for (auto mod : mods) {
|
|
result.append(token).append(mod.lower());
|
|
token = "S";
|
|
}
|
|
return result;
|
|
}
|
|
|
|
static std::string doModulesHost(llvm::ArrayRef<llvm::StringRef> mods,
|
|
llvm::Optional<llvm::StringRef> host) {
|
|
std::string result = doModules(mods);
|
|
if (host.hasValue())
|
|
result.append("F").append(host->lower());
|
|
return result;
|
|
}
|
|
|
|
inline llvm::SmallVector<llvm::StringRef>
|
|
convertToStringRef(llvm::ArrayRef<std::string> from) {
|
|
return {from.begin(), from.end()};
|
|
}
|
|
|
|
inline llvm::Optional<llvm::StringRef>
|
|
convertToStringRef(const llvm::Optional<std::string> &from) {
|
|
llvm::Optional<llvm::StringRef> to;
|
|
if (from.hasValue())
|
|
to = from.getValue();
|
|
return to;
|
|
}
|
|
|
|
static std::string readName(llvm::StringRef uniq, std::size_t &i,
|
|
std::size_t init, std::size_t end) {
|
|
for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z'); ++i) {
|
|
// do nothing
|
|
}
|
|
return uniq.substr(init, i - init).str();
|
|
}
|
|
|
|
static std::int64_t readInt(llvm::StringRef uniq, std::size_t &i,
|
|
std::size_t init, std::size_t end) {
|
|
for (i = init; i < end && uniq[i] >= '0' && uniq[i] <= '9'; ++i) {
|
|
// do nothing
|
|
}
|
|
std::int64_t result = badValue;
|
|
if (uniq.substr(init, i - init).getAsInteger(10, result))
|
|
return badValue;
|
|
return result;
|
|
}
|
|
|
|
std::string fir::NameUniquer::toLower(llvm::StringRef name) {
|
|
return name.lower();
|
|
}
|
|
|
|
std::string fir::NameUniquer::intAsString(std::int64_t i) {
|
|
assert(i >= 0);
|
|
return std::to_string(i);
|
|
}
|
|
|
|
std::string fir::NameUniquer::doKind(std::int64_t kind) {
|
|
std::string result = "K";
|
|
if (kind < 0)
|
|
return result.append("N").append(intAsString(-kind));
|
|
return result.append(intAsString(kind));
|
|
}
|
|
|
|
std::string fir::NameUniquer::doKinds(llvm::ArrayRef<std::int64_t> kinds) {
|
|
std::string result;
|
|
for (auto i : kinds)
|
|
result.append(doKind(i));
|
|
return result;
|
|
}
|
|
|
|
std::string fir::NameUniquer::doCommonBlock(llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
return result.append("B").append(toLower(name));
|
|
}
|
|
|
|
std::string fir::NameUniquer::doBlockData(llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
return result.append("L").append(toLower(name));
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doConstant(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("EC");
|
|
return result.append(toLower(name));
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doDispatchTable(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name,
|
|
llvm::ArrayRef<std::int64_t> kinds) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("DT");
|
|
return result.append(toLower(name)).append(doKinds(kinds));
|
|
}
|
|
|
|
std::string fir::NameUniquer::doGenerated(llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
return result.append("Q").append(name);
|
|
}
|
|
|
|
std::string fir::NameUniquer::doIntrinsicTypeDescriptor(
|
|
llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host, IntrinsicType type,
|
|
std::int64_t kind) {
|
|
const char *name = nullptr;
|
|
switch (type) {
|
|
case IntrinsicType::CHARACTER:
|
|
name = "character";
|
|
break;
|
|
case IntrinsicType::COMPLEX:
|
|
name = "complex";
|
|
break;
|
|
case IntrinsicType::INTEGER:
|
|
name = "integer";
|
|
break;
|
|
case IntrinsicType::LOGICAL:
|
|
name = "logical";
|
|
break;
|
|
case IntrinsicType::REAL:
|
|
name = "real";
|
|
break;
|
|
}
|
|
assert(name && "unknown intrinsic type");
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("C");
|
|
return result.append(name).append(doKind(kind));
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doProcedure(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("P");
|
|
return result.append(toLower(name));
|
|
}
|
|
|
|
std::string fir::NameUniquer::doType(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name,
|
|
llvm::ArrayRef<std::int64_t> kinds) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("T");
|
|
return result.append(toLower(name)).append(doKinds(kinds));
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doTypeDescriptor(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name,
|
|
llvm::ArrayRef<std::int64_t> kinds) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("CT");
|
|
return result.append(toLower(name)).append(doKinds(kinds));
|
|
}
|
|
|
|
std::string fir::NameUniquer::doTypeDescriptor(
|
|
llvm::ArrayRef<std::string> modules, llvm::Optional<std::string> host,
|
|
llvm::StringRef name, llvm::ArrayRef<std::int64_t> kinds) {
|
|
auto rmodules = convertToStringRef(modules);
|
|
auto rhost = convertToStringRef(host);
|
|
return doTypeDescriptor(rmodules, rhost, name, kinds);
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doVariable(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("E");
|
|
return result.append(toLower(name));
|
|
}
|
|
|
|
std::string
|
|
fir::NameUniquer::doNamelistGroup(llvm::ArrayRef<llvm::StringRef> modules,
|
|
llvm::Optional<llvm::StringRef> host,
|
|
llvm::StringRef name) {
|
|
std::string result = prefix();
|
|
result.append(doModulesHost(modules, host)).append("G");
|
|
return result.append(toLower(name));
|
|
}
|
|
|
|
llvm::StringRef fir::NameUniquer::doProgramEntry() {
|
|
if (mainEntryName.size())
|
|
return mainEntryName;
|
|
return "_QQmain";
|
|
}
|
|
|
|
std::pair<fir::NameUniquer::NameKind, fir::NameUniquer::DeconstructedName>
|
|
fir::NameUniquer::deconstruct(llvm::StringRef uniq) {
|
|
if (uniq.startswith("_Q")) {
|
|
llvm::SmallVector<std::string> modules;
|
|
llvm::Optional<std::string> host;
|
|
std::string name;
|
|
llvm::SmallVector<std::int64_t> kinds;
|
|
NameKind nk = NameKind::NOT_UNIQUED;
|
|
for (std::size_t i = 2, end{uniq.size()}; i != end;) {
|
|
switch (uniq[i]) {
|
|
case 'B':
|
|
nk = NameKind::COMMON;
|
|
name = readName(uniq, i, i + 1, end);
|
|
break;
|
|
case 'C':
|
|
if (uniq[i + 1] == 'T') {
|
|
nk = NameKind::TYPE_DESC;
|
|
name = readName(uniq, i, i + 2, end);
|
|
} else {
|
|
nk = NameKind::INTRINSIC_TYPE_DESC;
|
|
name = readName(uniq, i, i + 1, end);
|
|
}
|
|
break;
|
|
case 'D':
|
|
nk = NameKind::DISPATCH_TABLE;
|
|
assert(uniq[i + 1] == 'T');
|
|
name = readName(uniq, i, i + 2, end);
|
|
break;
|
|
case 'E':
|
|
if (uniq[i + 1] == 'C') {
|
|
nk = NameKind::CONSTANT;
|
|
name = readName(uniq, i, i + 2, end);
|
|
} else {
|
|
nk = NameKind::VARIABLE;
|
|
name = readName(uniq, i, i + 1, end);
|
|
}
|
|
break;
|
|
case 'L':
|
|
nk = NameKind::BLOCK_DATA_NAME;
|
|
name = readName(uniq, i, i + 1, end);
|
|
break;
|
|
case 'P':
|
|
nk = NameKind::PROCEDURE;
|
|
name = readName(uniq, i, i + 1, end);
|
|
break;
|
|
case 'Q':
|
|
nk = NameKind::GENERATED;
|
|
name = uniq;
|
|
i = end;
|
|
break;
|
|
case 'T':
|
|
nk = NameKind::DERIVED_TYPE;
|
|
name = readName(uniq, i, i + 1, end);
|
|
break;
|
|
|
|
case 'M':
|
|
case 'S':
|
|
modules.push_back(readName(uniq, i, i + 1, end));
|
|
break;
|
|
case 'F':
|
|
host = readName(uniq, i, i + 1, end);
|
|
break;
|
|
case 'K':
|
|
if (uniq[i + 1] == 'N')
|
|
kinds.push_back(-readInt(uniq, i, i + 2, end));
|
|
else
|
|
kinds.push_back(readInt(uniq, i, i + 1, end));
|
|
break;
|
|
case 'G':
|
|
nk = NameKind::NAMELIST_GROUP;
|
|
name = readName(uniq, i, i + 1, end);
|
|
break;
|
|
|
|
default:
|
|
assert(false && "unknown uniquing code");
|
|
break;
|
|
}
|
|
}
|
|
return {nk, DeconstructedName(modules, host, name, kinds)};
|
|
}
|
|
return {NameKind::NOT_UNIQUED, DeconstructedName(uniq)};
|
|
}
|
|
|
|
bool fir::NameUniquer::isExternalFacingUniquedName(
|
|
const std::pair<fir::NameUniquer::NameKind,
|
|
fir::NameUniquer::DeconstructedName> &deconstructResult) {
|
|
return (deconstructResult.first == NameKind::PROCEDURE ||
|
|
deconstructResult.first == NameKind::COMMON) &&
|
|
deconstructResult.second.modules.empty() &&
|
|
!deconstructResult.second.host;
|
|
}
|
|
|
|
bool fir::NameUniquer::needExternalNameMangling(llvm::StringRef uniquedName) {
|
|
auto result = fir::NameUniquer::deconstruct(uniquedName);
|
|
return result.first != fir::NameUniquer::NameKind::NOT_UNIQUED &&
|
|
fir::NameUniquer::isExternalFacingUniquedName(result);
|
|
}
|
|
|
|
bool fir::NameUniquer::belongsToModule(llvm::StringRef uniquedName,
|
|
llvm::StringRef moduleName) {
|
|
auto result = fir::NameUniquer::deconstruct(uniquedName);
|
|
return !result.second.modules.empty() &&
|
|
result.second.modules[0] == moduleName;
|
|
}
|