Skip to content

Commit cfd4c18

Browse files
authored
[RFC][flang] Replace special symbols in uniqued global names. (llvm#104859)
This change addresses more "issues" as the one resolved in llvm#71338. Some targets (e.g. NVPTX) do not accept global names containing `.`. In particular, the global variables created to represent the runtime information of derived types use `.` in their names. A derived type's descriptor object may be used in the device code, e.g. to initialize a descriptor of a variable of this type. Thus, the runtime type info objects may need to be compiled for the device. Moreover, at least the derived types' descriptor objects may need to be registered (think of `omp declare target`) for the host-device association so that the addendum pointer can be properly mapped to the device for descriptors using a derived type's descriptor as their addendum pointer. The registration implies knowing the name of the global variable in the device image so that proper host code can be created. So it is better to name the globals the same way for the host and the device. CompilerGeneratedNamesConversion pass renames all uniqued globals such that the special symbols (currently `.`) are replaced with `X`. The pass is supposed to be run for the host and the device. An option is added to FIR-to-LLVM conversion pass to indicate whether the new pass has been run before or not. This setting affects how the codegen computes the names of the derived types' descriptors for FIR derived types. fir::NameUniquer now allows `X` to be part of a name, because the name deconstruction may be applied to the mangled names after CompilerGeneratedNamesConversion pass.
1 parent 84fa7b4 commit cfd4c18

20 files changed

+270
-56
lines changed

flang/include/flang/Optimizer/CodeGen/CGPasses.td

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,11 @@ def FIRToLLVMLowering : Pass<"fir-to-llvm-ir", "mlir::ModuleOp"> {
3636
Option<"forcedTargetFeatures", "target-features", "std::string",
3737
/*default=*/"", "Override module's target features.">,
3838
Option<"applyTBAA", "apply-tbaa", "bool", /*default=*/"false",
39-
"Attach TBAA tags to memory accessing operations.">
39+
"Attach TBAA tags to memory accessing operations.">,
40+
Option<"typeDescriptorsRenamedForAssembly",
41+
"type-descriptors-renamed-for-assembly", "bool", /*default=*/"false",
42+
"Global variables created to describe derived types "
43+
"have been renamed to avoid special symbols in their names.">
4044
];
4145
}
4246

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

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -44,6 +44,16 @@ struct FIRToLLVMPassOptions {
4444

4545
// Force the usage of a unified tbaa tree in TBAABuilder.
4646
bool forceUnifiedTBAATree = false;
47+
48+
// If set to true, then the global variables created
49+
// for the derived types have been renamed to avoid usage
50+
// of special symbols that may not be supported by all targets.
51+
// The renaming is done by the CompilerGeneratedNamesConversion pass.
52+
// If it is true, FIR-to-LLVM pass has to use
53+
// fir::NameUniquer::getTypeDescriptorAssemblyName() to take
54+
// the name of the global variable corresponding to a derived
55+
// type's descriptor.
56+
bool typeDescriptorsRenamedForAssembly = false;
4757
};
4858

4959
/// Convert FIR to the LLVM IR dialect with default options.

flang/include/flang/Optimizer/Support/InternalNames.h

Lines changed: 20 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -14,13 +14,23 @@
1414
#include <cstdint>
1515
#include <optional>
1616

17-
static constexpr llvm::StringRef typeDescriptorSeparator = ".dt.";
18-
static constexpr llvm::StringRef componentInitSeparator = ".di.";
19-
static constexpr llvm::StringRef bindingTableSeparator = ".v.";
20-
static constexpr llvm::StringRef boxprocSuffix = "UnboxProc";
21-
2217
namespace fir {
2318

19+
static constexpr llvm::StringRef kNameSeparator = ".";
20+
static constexpr llvm::StringRef kBoundsSeparator = ".b.";
21+
static constexpr llvm::StringRef kComponentSeparator = ".c.";
22+
static constexpr llvm::StringRef kComponentInitSeparator = ".di.";
23+
static constexpr llvm::StringRef kDataPtrInitSeparator = ".dp.";
24+
static constexpr llvm::StringRef kTypeDescriptorSeparator = ".dt.";
25+
static constexpr llvm::StringRef kKindParameterSeparator = ".kp.";
26+
static constexpr llvm::StringRef kLenKindSeparator = ".lpk.";
27+
static constexpr llvm::StringRef kLenParameterSeparator = ".lv.";
28+
static constexpr llvm::StringRef kNameStringSeparator = ".n.";
29+
static constexpr llvm::StringRef kProcPtrSeparator = ".p.";
30+
static constexpr llvm::StringRef kSpecialBindingSeparator = ".s.";
31+
static constexpr llvm::StringRef kBindingTableSeparator = ".v.";
32+
static constexpr llvm::StringRef boxprocSuffix = "UnboxProc";
33+
2434
/// Internal name mangling of identifiers
2535
///
2636
/// In order to generate symbolically referencable artifacts in a ModuleOp,
@@ -150,6 +160,9 @@ struct NameUniquer {
150160
/// not a valid mangled derived type name.
151161
static std::string getTypeDescriptorName(llvm::StringRef mangledTypeName);
152162

163+
static std::string
164+
getTypeDescriptorAssemblyName(llvm::StringRef mangledTypeName);
165+
153166
/// Given a mangled derived type name, get the name of the related binding
154167
/// table object. Returns an empty string if \p mangledTypeName is not a valid
155168
/// mangled derived type name.
@@ -169,6 +182,8 @@ struct NameUniquer {
169182
static llvm::StringRef
170183
dropTypeConversionMarkers(llvm::StringRef mangledTypeName);
171184

185+
static std::string replaceSpecialSymbols(const std::string &name);
186+
172187
private:
173188
static std::string intAsString(std::int64_t i);
174189
static std::string doKind(std::int64_t kind);

flang/include/flang/Optimizer/Transforms/Passes.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ namespace fir {
5959
#define GEN_PASS_DECL_VSCALEATTR
6060
#define GEN_PASS_DECL_FUNCTIONATTR
6161
#define GEN_PASS_DECL_CONSTANTARGUMENTGLOBALISATIONOPT
62+
#define GEN_PASS_DECL_COMPILERGENERATEDNAMESCONVERSION
6263

6364
#include "flang/Optimizer/Transforms/Passes.h.inc"
6465

flang/include/flang/Optimizer/Transforms/Passes.td

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -170,6 +170,24 @@ def ExternalNameConversion : Pass<"external-name-interop", "mlir::ModuleOp"> {
170170
];
171171
}
172172

173+
def CompilerGeneratedNamesConversion : Pass<"compiler-generated-names",
174+
"mlir::ModuleOp"> {
175+
let summary = "Convert names of compiler generated globals";
176+
let description = [{
177+
Transforms names of compiler generated globals to avoid
178+
characters that might be unsupported by some target toolchains.
179+
All special symbols are replaced with a predefined 'X' character.
180+
This is only done for uniqued names that are not externally facing.
181+
The uniqued names always use '_Q' prefix, and the user entity names
182+
are always lower cased, so using 'X' instead of the special symbols
183+
will guarantee that the converted name will not conflict with the user
184+
space. This pass does not affect the externally facing names,
185+
because the expectation is that the compiler will not generate
186+
externally facing names on its own, and these names cannot use
187+
special symbols.
188+
}];
189+
}
190+
173191
def MemRefDataFlowOpt : Pass<"fir-memref-dataflow-opt", "::mlir::func::FuncOp"> {
174192
let summary =
175193
"Perform store/load forwarding and potentially removing dead stores.";

flang/include/flang/Tools/CLOptions.inc

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,8 @@ DisableOption(ExternalNameConversion, "external-name-interop",
9393
"convert names with external convention");
9494
EnableOption(ConstantArgumentGlobalisation, "constant-argument-globalisation",
9595
"the local constant argument to global constant conversion");
96+
DisableOption(CompilerGeneratedNamesConversion, "compiler-generated-names",
97+
"replace special symbols in compiler generated names");
9698

9799
using PassConstructor = std::unique_ptr<mlir::Pass>();
98100

@@ -222,6 +224,8 @@ inline void addFIRToLLVMPass(
222224
options.ignoreMissingTypeDescriptors = ignoreMissingTypeDescriptors;
223225
options.applyTBAA = config.AliasAnalysis;
224226
options.forceUnifiedTBAATree = useOldAliasTags;
227+
options.typeDescriptorsRenamedForAssembly =
228+
!disableCompilerGeneratedNamesConversion;
225229
addPassConditionally(pm, disableFirToLlvmIr,
226230
[&]() { return fir::createFIRToLLVMPass(options); });
227231
// The dialect conversion framework may leave dead unrealized_conversion_cast
@@ -248,6 +252,11 @@ inline void addExternalNameConversionPass(
248252
[&]() { return fir::createExternalNameConversion({appendUnderscore}); });
249253
}
250254

255+
inline void addCompilerGeneratedNamesConversionPass(mlir::PassManager &pm) {
256+
addPassConditionally(pm, disableCompilerGeneratedNamesConversion,
257+
[&]() { return fir::createCompilerGeneratedNamesConversion(); });
258+
}
259+
251260
// Use inliner extension point callback to register the default inliner pass.
252261
inline void registerDefaultInlinerPass(MLIRToLLVMPassPipelineConfig &config) {
253262
config.registerFIRInlinerCallback(
@@ -379,6 +388,7 @@ inline void createDefaultFIRCodeGenPassPipeline(mlir::PassManager &pm,
379388
fir::addCodeGenRewritePass(
380389
pm, (config.DebugInfo != llvm::codegenoptions::NoDebugInfo));
381390
fir::addTargetRewritePass(pm);
391+
fir::addCompilerGeneratedNamesConversionPass(pm);
382392
fir::addExternalNameConversionPass(pm, config.Underscoring);
383393
fir::createDebugPasses(pm, config.DebugInfo, config.OptLevel, inputFilename);
384394

flang/lib/Optimizer/CodeGen/CodeGen.cpp

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1201,7 +1201,9 @@ struct EmboxCommonConversion : public fir::FIROpConversion<OP> {
12011201
mlir::Location loc,
12021202
fir::RecordType recType) const {
12031203
std::string name =
1204-
fir::NameUniquer::getTypeDescriptorName(recType.getName());
1204+
this->options.typeDescriptorsRenamedForAssembly
1205+
? fir::NameUniquer::getTypeDescriptorAssemblyName(recType.getName())
1206+
: fir::NameUniquer::getTypeDescriptorName(recType.getName());
12051207
mlir::Type llvmPtrTy = ::getLlvmPtrType(mod.getContext());
12061208
if (auto global = mod.template lookupSymbol<fir::GlobalOp>(name)) {
12071209
return rewriter.create<mlir::LLVM::AddressOfOp>(loc, llvmPtrTy,
@@ -2704,7 +2706,10 @@ struct TypeDescOpConversion : public fir::FIROpConversion<fir::TypeDescOp> {
27042706
auto recordType = mlir::dyn_cast<fir::RecordType>(inTy);
27052707
auto module = typeDescOp.getOperation()->getParentOfType<mlir::ModuleOp>();
27062708
std::string typeDescName =
2707-
fir::NameUniquer::getTypeDescriptorName(recordType.getName());
2709+
this->options.typeDescriptorsRenamedForAssembly
2710+
? fir::NameUniquer::getTypeDescriptorAssemblyName(
2711+
recordType.getName())
2712+
: fir::NameUniquer::getTypeDescriptorName(recordType.getName());
27082713
auto llvmPtrTy = ::getLlvmPtrType(typeDescOp.getContext());
27092714
if (auto global = module.lookupSymbol<mlir::LLVM::GlobalOp>(typeDescName)) {
27102715
rewriter.replaceOpWithNewOp<mlir::LLVM::AddressOfOp>(
@@ -3653,6 +3658,10 @@ class FIRToLLVMLowering
36533658
if (!forcedTargetFeatures.empty())
36543659
fir::setTargetFeatures(mod, forcedTargetFeatures);
36553660

3661+
if (typeDescriptorsRenamedForAssembly)
3662+
options.typeDescriptorsRenamedForAssembly =
3663+
typeDescriptorsRenamedForAssembly;
3664+
36563665
// Run dynamic pass pipeline for converting Math dialect
36573666
// operations into other dialects (llvm, func, etc.).
36583667
// Some conversions of Math operations cannot be done

flang/lib/Optimizer/Support/InternalNames.cpp

Lines changed: 23 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
#include "mlir/IR/Diagnostics.h"
1717
#include "llvm/Support/CommandLine.h"
1818
#include <optional>
19+
#include <regex>
1920

2021
static llvm::cl::opt<std::string> mainEntryName(
2122
"main-entry-name",
@@ -59,7 +60,11 @@ convertToStringRef(const std::optional<std::string> &from) {
5960

6061
static std::string readName(llvm::StringRef uniq, std::size_t &i,
6162
std::size_t init, std::size_t end) {
62-
for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z'); ++i) {
63+
// Allow 'X' to be part of the mangled name, which
64+
// can happen after the special symbols are replaced
65+
// in the mangled names by CompilerGeneratedNamesConversionPass.
66+
for (i = init; i < end && (uniq[i] < 'A' || uniq[i] > 'Z' || uniq[i] == 'X');
67+
++i) {
6368
// do nothing
6469
}
6570
return uniq.substr(init, i - init).str();
@@ -348,7 +353,7 @@ mangleTypeDescriptorKinds(llvm::ArrayRef<std::int64_t> kinds) {
348353
return "";
349354
std::string result;
350355
for (std::int64_t kind : kinds)
351-
result += "." + std::to_string(kind);
356+
result += (fir::kNameSeparator + std::to_string(kind)).str();
352357
return result;
353358
}
354359

@@ -373,26 +378,36 @@ static std::string getDerivedTypeObjectName(llvm::StringRef mangledTypeName,
373378

374379
std::string
375380
fir::NameUniquer::getTypeDescriptorName(llvm::StringRef mangledTypeName) {
376-
return getDerivedTypeObjectName(mangledTypeName, typeDescriptorSeparator);
381+
return getDerivedTypeObjectName(mangledTypeName,
382+
fir::kTypeDescriptorSeparator);
383+
}
384+
385+
std::string fir::NameUniquer::getTypeDescriptorAssemblyName(
386+
llvm::StringRef mangledTypeName) {
387+
return replaceSpecialSymbols(getTypeDescriptorName(mangledTypeName));
377388
}
378389

379390
std::string fir::NameUniquer::getTypeDescriptorBindingTableName(
380391
llvm::StringRef mangledTypeName) {
381-
return getDerivedTypeObjectName(mangledTypeName, bindingTableSeparator);
392+
return getDerivedTypeObjectName(mangledTypeName, fir::kBindingTableSeparator);
382393
}
383394

384395
std::string
385396
fir::NameUniquer::getComponentInitName(llvm::StringRef mangledTypeName,
386397
llvm::StringRef componentName) {
387398

388399
std::string prefix =
389-
getDerivedTypeObjectName(mangledTypeName, componentInitSeparator);
390-
return prefix + "." + componentName.str();
400+
getDerivedTypeObjectName(mangledTypeName, fir::kComponentInitSeparator);
401+
return (prefix + fir::kNameSeparator + componentName).str();
391402
}
392403

393404
llvm::StringRef
394405
fir::NameUniquer::dropTypeConversionMarkers(llvm::StringRef mangledTypeName) {
395-
if (mangledTypeName.ends_with(boxprocSuffix))
396-
return mangledTypeName.drop_back(boxprocSuffix.size());
406+
if (mangledTypeName.ends_with(fir::boxprocSuffix))
407+
return mangledTypeName.drop_back(fir::boxprocSuffix.size());
397408
return mangledTypeName;
398409
}
410+
411+
std::string fir::NameUniquer::replaceSpecialSymbols(const std::string &name) {
412+
return std::regex_replace(name, std::regex{"\\."}, "X");
413+
}

flang/lib/Optimizer/Transforms/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ add_flang_library(FIRTransforms
66
AnnotateConstant.cpp
77
AssumedRankOpConversion.cpp
88
CharacterConversion.cpp
9+
CompilerGeneratedNames.cpp
910
ConstantArgumentGlobalisation.cpp
1011
ControlFlowConverter.cpp
1112
CufOpConversion.cpp
Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
//=== CompilerGeneratedNames.cpp - convert special symbols in global names ===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
9+
#include "flang/Optimizer/Dialect/FIRDialect.h"
10+
#include "flang/Optimizer/Dialect/FIROps.h"
11+
#include "flang/Optimizer/Dialect/FIROpsSupport.h"
12+
#include "flang/Optimizer/Support/InternalNames.h"
13+
#include "flang/Optimizer/Transforms/Passes.h"
14+
#include "mlir/IR/Attributes.h"
15+
#include "mlir/IR/SymbolTable.h"
16+
#include "mlir/Pass/Pass.h"
17+
18+
namespace fir {
19+
#define GEN_PASS_DEF_COMPILERGENERATEDNAMESCONVERSION
20+
#include "flang/Optimizer/Transforms/Passes.h.inc"
21+
} // namespace fir
22+
23+
using namespace mlir;
24+
25+
namespace {
26+
27+
class CompilerGeneratedNamesConversionPass
28+
: public fir::impl::CompilerGeneratedNamesConversionBase<
29+
CompilerGeneratedNamesConversionPass> {
30+
public:
31+
using CompilerGeneratedNamesConversionBase<
32+
CompilerGeneratedNamesConversionPass>::
33+
CompilerGeneratedNamesConversionBase;
34+
35+
mlir::ModuleOp getModule() { return getOperation(); }
36+
void runOnOperation() override;
37+
};
38+
} // namespace
39+
40+
void CompilerGeneratedNamesConversionPass::runOnOperation() {
41+
auto op = getOperation();
42+
auto *context = &getContext();
43+
44+
llvm::DenseMap<mlir::StringAttr, mlir::FlatSymbolRefAttr> remappings;
45+
for (auto &funcOrGlobal : op->getRegion(0).front()) {
46+
if (llvm::isa<mlir::func::FuncOp>(funcOrGlobal) ||
47+
llvm::isa<fir::GlobalOp>(funcOrGlobal)) {
48+
auto symName = funcOrGlobal.getAttrOfType<mlir::StringAttr>(
49+
mlir::SymbolTable::getSymbolAttrName());
50+
auto deconstructedName = fir::NameUniquer::deconstruct(symName);
51+
if (deconstructedName.first != fir::NameUniquer::NameKind::NOT_UNIQUED &&
52+
!fir::NameUniquer::isExternalFacingUniquedName(deconstructedName)) {
53+
std::string newName =
54+
fir::NameUniquer::replaceSpecialSymbols(symName.getValue().str());
55+
if (newName != symName) {
56+
auto newAttr = mlir::StringAttr::get(context, newName);
57+
mlir::SymbolTable::setSymbolName(&funcOrGlobal, newAttr);
58+
auto newSymRef = mlir::FlatSymbolRefAttr::get(newAttr);
59+
remappings.try_emplace(symName, newSymRef);
60+
}
61+
}
62+
}
63+
}
64+
65+
if (remappings.empty())
66+
return;
67+
68+
// Update all uses of the functions and globals that have been renamed.
69+
op.walk([&remappings](mlir::Operation *nestedOp) {
70+
llvm::SmallVector<std::pair<mlir::StringAttr, mlir::SymbolRefAttr>> updates;
71+
for (const mlir::NamedAttribute &attr : nestedOp->getAttrDictionary())
72+
if (auto symRef = llvm::dyn_cast<mlir::SymbolRefAttr>(attr.getValue()))
73+
if (auto remap = remappings.find(symRef.getRootReference());
74+
remap != remappings.end())
75+
updates.emplace_back(std::pair<mlir::StringAttr, mlir::SymbolRefAttr>{
76+
attr.getName(), mlir::SymbolRefAttr(remap->second)});
77+
for (auto update : updates)
78+
nestedOp->setAttr(update.first, update.second);
79+
});
80+
}

0 commit comments

Comments
 (0)