Skip to content

Commit 7d71164

Browse files
authored
[CIR] Upstream support for name mangling (#137094)
We have been using the default names for global symbols to this point. This change introduces proper name mangling for functions. This requires introducing a CXXABI class in the CIRGenModule. Because only target independent name mangling is handled in this patch, the CXXABI class does not require a target-specific implementation. The general mechanism for selecting an implementation is introduced here, but the actual target-specific subclasses are deferred until needed.
1 parent bae4c94 commit 7d71164

23 files changed

+335
-173
lines changed

clang/include/clang/CIR/MissingFeatures.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -151,14 +151,15 @@ struct MissingFeatures {
151151
static bool weakRefReference() { return false; }
152152
static bool hip() { return false; }
153153
static bool setObjCGCLValueClass() { return false; }
154-
static bool mangledNames() { return false; }
155154
static bool setDLLStorageClass() { return false; }
156155
static bool openMP() { return false; }
157156
static bool emitCheckedInBoundsGEP() { return false; }
158157
static bool preservedAccessIndexRegion() { return false; }
159158
static bool bitfields() { return false; }
160159
static bool typeChecks() { return false; }
161160
static bool lambdaFieldToName() { return false; }
161+
static bool targetSpecificCXXABI() { return false; }
162+
static bool moduleNameHash() { return false; }
162163

163164
// Missing types
164165
static bool dataMemberType() { return false; }

clang/lib/CIR/CodeGen/CIRGenCXXABI.h

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
//===----------------------------------------------------------------------===//
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+
// This provides an abstract class for C++ code generation. Concrete subclasses
10+
// of this implement code generation for specific C++ ABIs.
11+
//
12+
//===----------------------------------------------------------------------===//
13+
14+
#ifndef LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
15+
#define LLVM_CLANG_LIB_CIR_CIRGENCXXABI_H
16+
17+
#include "CIRGenModule.h"
18+
19+
#include "clang/AST/Mangle.h"
20+
21+
namespace clang::CIRGen {
22+
23+
/// Implements C++ ABI-specific code generation functions.
24+
class CIRGenCXXABI {
25+
protected:
26+
CIRGenModule &cgm;
27+
std::unique_ptr<clang::MangleContext> mangleContext;
28+
29+
public:
30+
// TODO(cir): make this protected when target-specific CIRGenCXXABIs are
31+
// implemented.
32+
CIRGenCXXABI(CIRGenModule &cgm)
33+
: cgm(cgm), mangleContext(cgm.getASTContext().createMangleContext()) {}
34+
~CIRGenCXXABI();
35+
36+
public:
37+
/// Gets the mangle context.
38+
clang::MangleContext &getMangleContext() { return *mangleContext; }
39+
};
40+
41+
/// Creates and Itanium-family ABI
42+
CIRGenCXXABI *CreateCIRGenItaniumCXXABI(CIRGenModule &cgm);
43+
44+
} // namespace clang::CIRGen
45+
46+
#endif

clang/lib/CIR/CodeGen/CIRGenModule.cpp

+113-10
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "CIRGenModule.h"
14+
#include "CIRGenCXXABI.h"
1415
#include "CIRGenConstantEmitter.h"
1516
#include "CIRGenFunction.h"
1617

@@ -30,14 +31,46 @@
3031
using namespace clang;
3132
using namespace clang::CIRGen;
3233

34+
static CIRGenCXXABI *createCXXABI(CIRGenModule &cgm) {
35+
switch (cgm.getASTContext().getCXXABIKind()) {
36+
case TargetCXXABI::GenericItanium:
37+
case TargetCXXABI::GenericAArch64:
38+
case TargetCXXABI::AppleARM64:
39+
return CreateCIRGenItaniumCXXABI(cgm);
40+
41+
case TargetCXXABI::Fuchsia:
42+
case TargetCXXABI::GenericARM:
43+
case TargetCXXABI::iOS:
44+
case TargetCXXABI::WatchOS:
45+
case TargetCXXABI::GenericMIPS:
46+
case TargetCXXABI::WebAssembly:
47+
case TargetCXXABI::XL:
48+
case TargetCXXABI::Microsoft:
49+
cgm.errorNYI("C++ ABI kind not yet implemented");
50+
return nullptr;
51+
}
52+
53+
llvm_unreachable("invalid C++ ABI kind");
54+
}
55+
56+
namespace clang::CIRGen {
57+
// TODO(cir): Implement target-specific CIRGenCXXABIs
58+
CIRGenCXXABI *CreateCIRGenItaniumCXXABI(CIRGenModule &cgm) {
59+
assert(!cir::MissingFeatures::targetSpecificCXXABI());
60+
return new CIRGenCXXABI(cgm);
61+
}
62+
} // namespace clang::CIRGen
63+
CIRGenCXXABI::~CIRGenCXXABI() {}
64+
3365
CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
3466
clang::ASTContext &astContext,
3567
const clang::CodeGenOptions &cgo,
3668
DiagnosticsEngine &diags)
3769
: builder(mlirContext, *this), astContext(astContext),
3870
langOpts(astContext.getLangOpts()), codeGenOpts(cgo),
3971
theModule{mlir::ModuleOp::create(mlir::UnknownLoc::get(&mlirContext))},
40-
diags(diags), target(astContext.getTargetInfo()), genTypes(*this) {
72+
diags(diags), target(astContext.getTargetInfo()),
73+
abi(createCXXABI(*this)), genTypes(*this) {
4174

4275
// Initialize cached types
4376
VoidTy = cir::VoidType::get(&getMLIRContext());
@@ -74,6 +107,8 @@ CIRGenModule::CIRGenModule(mlir::MLIRContext &mlirContext,
74107
builder.getStringAttr(getTriple().str()));
75108
}
76109

110+
CIRGenModule::~CIRGenModule() = default;
111+
77112
CharUnits CIRGenModule::getNaturalTypeAlignment(QualType t,
78113
LValueBaseInfo *baseInfo) {
79114
assert(!cir::MissingFeatures::opTBAA());
@@ -301,9 +336,9 @@ CIRGenModule::getOrCreateCIRGlobal(const VarDecl *d, mlir::Type ty,
301336
if (!ty)
302337
ty = getTypes().convertTypeForMem(astTy);
303338

304-
assert(!cir::MissingFeatures::mangledNames());
305-
return getOrCreateCIRGlobal(d->getIdentifier()->getName(), ty,
306-
astTy.getAddressSpace(), d, isForDefinition);
339+
StringRef mangledName = getMangledName(d);
340+
return getOrCreateCIRGlobal(mangledName, ty, astTy.getAddressSpace(), d,
341+
isForDefinition);
307342
}
308343

309344
/// Return the mlir::Value for the address of the given global variable. If
@@ -332,8 +367,9 @@ void CIRGenModule::emitGlobalVarDefinition(const clang::VarDecl *vd,
332367
const QualType astTy = vd->getType();
333368
const mlir::Type type = convertType(vd->getType());
334369
if (clang::IdentifierInfo *identifier = vd->getIdentifier()) {
335-
auto varOp = builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()),
336-
identifier->getName(), type);
370+
StringRef name = getMangledName(GlobalDecl(vd));
371+
auto varOp =
372+
builder.create<cir::GlobalOp>(getLoc(vd->getSourceRange()), name, type);
337373
// TODO(CIR): This code for processing initial values is a placeholder
338374
// until class ConstantEmitter is upstreamed and the code for processing
339375
// constant expressions is filled out. Only the most basic handling of
@@ -639,13 +675,80 @@ cir::FuncOp CIRGenModule::getAddrOfFunction(clang::GlobalDecl gd,
639675
funcType = convertType(fd->getType());
640676
}
641677

642-
assert(!cir::MissingFeatures::mangledNames());
643-
cir::FuncOp func = getOrCreateCIRFunction(
644-
cast<NamedDecl>(gd.getDecl())->getIdentifier()->getName(), funcType, gd,
645-
forVTable, dontDefer, /*isThunk=*/false, isForDefinition);
678+
StringRef mangledName = getMangledName(gd);
679+
cir::FuncOp func =
680+
getOrCreateCIRFunction(mangledName, funcType, gd, forVTable, dontDefer,
681+
/*isThunk=*/false, isForDefinition);
646682
return func;
647683
}
648684

685+
static std::string getMangledNameImpl(CIRGenModule &cgm, GlobalDecl gd,
686+
const NamedDecl *nd) {
687+
SmallString<256> buffer;
688+
689+
llvm::raw_svector_ostream out(buffer);
690+
MangleContext &mc = cgm.getCXXABI().getMangleContext();
691+
692+
assert(!cir::MissingFeatures::moduleNameHash());
693+
694+
if (mc.shouldMangleDeclName(nd)) {
695+
mc.mangleName(gd.getWithDecl(nd), out);
696+
} else {
697+
IdentifierInfo *ii = nd->getIdentifier();
698+
assert(ii && "Attempt to mangle unnamed decl.");
699+
700+
const auto *fd = dyn_cast<FunctionDecl>(nd);
701+
if (fd &&
702+
fd->getType()->castAs<FunctionType>()->getCallConv() == CC_X86RegCall) {
703+
cgm.errorNYI(nd->getSourceRange(), "getMangledName: X86RegCall");
704+
} else if (fd && fd->hasAttr<CUDAGlobalAttr>() &&
705+
gd.getKernelReferenceKind() == KernelReferenceKind::Stub) {
706+
cgm.errorNYI(nd->getSourceRange(), "getMangledName: CUDA device stub");
707+
}
708+
out << ii->getName();
709+
}
710+
711+
// Check if the module name hash should be appended for internal linkage
712+
// symbols. This should come before multi-version target suffixes are
713+
// appendded. This is to keep the name and module hash suffix of the internal
714+
// linkage function together. The unique suffix should only be added when name
715+
// mangling is done to make sure that the final name can be properly
716+
// demangled. For example, for C functions without prototypes, name mangling
717+
// is not done and the unique suffix should not be appended then.
718+
assert(!cir::MissingFeatures::moduleNameHash());
719+
720+
if (const auto *fd = dyn_cast<FunctionDecl>(nd)) {
721+
if (fd->isMultiVersion()) {
722+
cgm.errorNYI(nd->getSourceRange(),
723+
"getMangledName: multi-version functions");
724+
}
725+
}
726+
if (cgm.getLangOpts().GPURelocatableDeviceCode) {
727+
cgm.errorNYI(nd->getSourceRange(),
728+
"getMangledName: GPU relocatable device code");
729+
}
730+
731+
return std::string(out.str());
732+
}
733+
734+
StringRef CIRGenModule::getMangledName(GlobalDecl gd) {
735+
GlobalDecl canonicalGd = gd.getCanonicalDecl();
736+
737+
// Some ABIs don't have constructor variants. Make sure that base and complete
738+
// constructors get mangled the same.
739+
if (const auto *cd = dyn_cast<CXXConstructorDecl>(canonicalGd.getDecl())) {
740+
errorNYI(cd->getSourceRange(), "getMangledName: C++ constructor");
741+
return cast<NamedDecl>(gd.getDecl())->getIdentifier()->getName();
742+
}
743+
744+
// Keep the first result in the case of a mangling collision.
745+
const auto *nd = cast<NamedDecl>(gd.getDecl());
746+
std::string mangledName = getMangledNameImpl(*this, gd, nd);
747+
748+
auto result = manglings.insert(std::make_pair(mangledName, gd));
749+
return mangledDeclNames[canonicalGd] = result.first->first();
750+
}
751+
649752
cir::FuncOp CIRGenModule::getOrCreateCIRFunction(
650753
StringRef mangledName, mlir::Type funcType, GlobalDecl gd, bool forVTable,
651754
bool dontDefer, bool isThunk, ForDefinition_t isForDefinition,

clang/lib/CIR/CodeGen/CIRGenModule.h

+13-1
Original file line numberDiff line numberDiff line change
@@ -45,6 +45,7 @@ class VarDecl;
4545
namespace CIRGen {
4646

4747
class CIRGenFunction;
48+
class CIRGenCXXABI;
4849

4950
enum ForDefinition_t : bool { NotForDefinition = false, ForDefinition = true };
5051

@@ -59,7 +60,7 @@ class CIRGenModule : public CIRGenTypeCache {
5960
const clang::CodeGenOptions &cgo,
6061
clang::DiagnosticsEngine &diags);
6162

62-
~CIRGenModule() = default;
63+
~CIRGenModule();
6364

6465
private:
6566
mutable std::unique_ptr<TargetCIRGenInfo> theTargetCIRGenInfo;
@@ -80,6 +81,8 @@ class CIRGenModule : public CIRGenTypeCache {
8081

8182
const clang::TargetInfo &target;
8283

84+
std::unique_ptr<CIRGenCXXABI> abi;
85+
8386
CIRGenTypes genTypes;
8487

8588
/// Per-function codegen information. Updated everytime emitCIR is called
@@ -94,6 +97,8 @@ class CIRGenModule : public CIRGenTypeCache {
9497
const clang::CodeGenOptions &getCodeGenOpts() const { return codeGenOpts; }
9598
CIRGenTypes &getTypes() { return genTypes; }
9699
const clang::LangOptions &getLangOpts() const { return langOpts; }
100+
101+
CIRGenCXXABI &getCXXABI() const { return *abi; }
97102
mlir::MLIRContext &getMLIRContext() { return *builder.getContext(); }
98103

99104
const cir::CIRDataLayout getDataLayout() const {
@@ -169,6 +174,8 @@ class CIRGenModule : public CIRGenTypeCache {
169174
/// expression of the given type.
170175
mlir::Value emitNullConstant(QualType t, mlir::Location loc);
171176

177+
llvm::StringRef getMangledName(clang::GlobalDecl gd);
178+
172179
cir::FuncOp
173180
getOrCreateCIRFunction(llvm::StringRef mangledName, mlir::Type funcType,
174181
clang::GlobalDecl gd, bool forVTable,
@@ -226,6 +233,11 @@ class CIRGenModule : public CIRGenTypeCache {
226233
const T &name) {
227234
return errorNYI(loc.getBegin(), feature, name) << loc;
228235
}
236+
237+
private:
238+
// An ordered map of canonical GlobalDecls to their mangled names.
239+
llvm::MapVector<clang::GlobalDecl, llvm::StringRef> mangledDeclNames;
240+
llvm::StringMap<clang::GlobalDecl, llvm::BumpPtrAllocator> manglings;
229241
};
230242
} // namespace CIRGen
231243

0 commit comments

Comments
 (0)