diff --git a/clang/include/clang/AST/Mangle.h b/clang/include/clang/AST/Mangle.h --- a/clang/include/clang/AST/Mangle.h +++ b/clang/include/clang/AST/Mangle.h @@ -119,6 +119,10 @@ // FIXME: consider replacing raw_ostream & with something like SmallString &. void mangleName(GlobalDecl GD, raw_ostream &); + // Mangling for function definitions in Arm64EC ABI. + virtual void mangleArm64ECFnDef(GlobalDecl GD, raw_ostream &) { + llvm_unreachable("Unexpected ABI"); + } virtual void mangleCXXName(GlobalDecl GD, raw_ostream &) = 0; virtual void mangleThunk(const CXXMethodDecl *MD, const ThunkInfo &Thunk, diff --git a/clang/lib/AST/MicrosoftMangle.cpp b/clang/lib/AST/MicrosoftMangle.cpp --- a/clang/lib/AST/MicrosoftMangle.cpp +++ b/clang/lib/AST/MicrosoftMangle.cpp @@ -299,6 +299,7 @@ return AnonymousNamespaceHash; } + void mangleArm64ECFnDef(GlobalDecl GD, raw_ostream &) override; private: void mangleInitFiniStub(const VarDecl *D, char CharCode, raw_ostream &Out); }; @@ -361,7 +362,7 @@ void mangle(GlobalDecl GD, StringRef Prefix = "?"); void mangleName(GlobalDecl GD); - void mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle); + void mangleFunctionEncoding(GlobalDecl GD, bool ShouldMangle, bool Arm64ECDef = false); void mangleVariableEncoding(const VarDecl *VD); void mangleMemberDataPointer(const CXXRecordDecl *RD, const ValueDecl *VD, StringRef Prefix = "$"); @@ -385,6 +386,7 @@ bool ForceThisQuals = false, bool MangleExceptionSpec = true); void mangleNestedName(GlobalDecl GD); + void mangleArm64ECFnDef(GlobalDecl GD); private: bool isStructorDecl(const NamedDecl *ND) const { @@ -575,7 +577,8 @@ } void MicrosoftCXXNameMangler::mangleFunctionEncoding(GlobalDecl GD, - bool ShouldMangle) { + bool ShouldMangle, + bool Arm64ECDef) { const FunctionDecl *FD = cast(GD.getDecl()); // ::= @@ -599,6 +602,8 @@ if (FD->isExternC() && FD->hasAttr()) Out << "$$J0"; + if (Arm64ECDef) + Out << "$$h"; mangleFunctionClass(FD); mangleFunctionType(FT, FD, false, false); @@ -3954,6 +3959,29 @@ Mangler.getStream() << '@'; } +void MicrosoftMangleContextImpl::mangleArm64ECFnDef(GlobalDecl GD, + raw_ostream &Out) { + const FunctionDecl *D = cast(GD.getDecl()); + PrettyStackTraceDecl CrashInfo(D, SourceLocation(), + getASTContext().getSourceManager(), + "Mangling Arm64EC function def"); + + if (!shouldMangleCXXName(D)) { + Out << '#' << D->getName(); + return; + } + + msvc_hashing_ostream MHO(Out); + MicrosoftCXXNameMangler Mangler(*this, MHO); + return Mangler.mangleArm64ECFnDef(GD); +} + +void MicrosoftCXXNameMangler::mangleArm64ECFnDef(GlobalDecl GD) { + Out << '?'; + mangleName(GD); + mangleFunctionEncoding(GD, /*ShouldMangle*/true, /*Arm64ECDef*/true); +} + MicrosoftMangleContext *MicrosoftMangleContext::create(ASTContext &Context, DiagnosticsEngine &Diags, bool IsAux) { diff --git a/clang/lib/CodeGen/CodeGenModule.cpp b/clang/lib/CodeGen/CodeGenModule.cpp --- a/clang/lib/CodeGen/CodeGenModule.cpp +++ b/clang/lib/CodeGen/CodeGenModule.cpp @@ -5289,6 +5289,23 @@ if (!GV->isDeclaration()) return; + if (getTriple().isWindowsArm64EC()) { + // For ARM64EC targets, a function definition's name is mangled differently + // from the normal symbol. We then emit an alias from the normal + // symbol to the remangled definition. + // FIXME: MSVC uses IMAGE_WEAK_EXTERN_ANTI_DEPENDENCY, we just emit + // multiple definition symbols. Why does this matter? + // FIXME: For hybrid_patchable functions, the alias doesn't point + // to the function itself; it points to a stub for the compiler. + // FIXME: We also need to emit an entry thunk. + SmallString<256> MangledName; + llvm::raw_svector_ostream Out(MangledName); + getCXXABI().getMangleContext().mangleArm64ECFnDef(GD, Out); + auto *Alias = llvm::GlobalAlias::create("", GV); + Alias->takeName(GV); + GV->setName(MangledName); + } + // We need to set linkage and visibility on the function before // generating code for it because various parts of IR generation // want to propagate this information down (e.g. to local static diff --git a/clang/test/CodeGen/arm64ec.c b/clang/test/CodeGen/arm64ec.c new file mode 100644 --- /dev/null +++ b/clang/test/CodeGen/arm64ec.c @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -no-opaque-pointers -triple arm64ec-windows-msvc -emit-llvm -o - %s | FileCheck %s + +// CHECK: @g = alias void ([2 x float], [4 x float]), void ([2 x float], [4 x float])* @"#g" +// CHECK: define dso_local void @"#g" +typedef struct { float x[2]; } A; +typedef struct { float x[4]; } B; +void g(A a, B b) { } diff --git a/clang/test/CodeGenCXX/arm64ec.cpp b/clang/test/CodeGenCXX/arm64ec.cpp new file mode 100644 --- /dev/null +++ b/clang/test/CodeGenCXX/arm64ec.cpp @@ -0,0 +1,7 @@ +// RUN: %clang_cc1 -no-opaque-pointers -triple arm64ec-windows-msvc -emit-llvm -o - %s | FileCheck %s + +// CHECK: @"?g@@YAXUA@@UB@@@Z" = alias void ([2 x float], [4 x float]), void ([2 x float], [4 x float])* @"?g@@$$hYAXUA@@UB@@@Z" +// CHECK: define dso_local void @"?g@@$$hYAXUA@@UB@@@Z" +typedef struct { float x[2]; } A; +typedef struct { float x[4]; } B; +void g(A a, B b) { }