[llvm] [ORC] Add SymbolNameSpec for mangling-aware symbol names (PR #221635)
Lang Hames via llvm-commits
llvm-commits at lists.llvm.org
Mon Sep 7 22:27:30 PDT 2026
https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/221635
>From 23de6a727feac70a61db702de19e5c2cc90812b5 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Mon, 7 Sep 2026 14:48:08 +1000
Subject: [PATCH 1/4] [ORC] Add SymbolNameSpec, hoist name mangling into
Shared.
Introduce two Shared, ExecutionSession-independent pieces:
- SymbolNameSpec (Shared/SymbolNameSpec.h): a StringRef paired with a
SymbolNameKind (Verbatim, Linker, IR, C) describing the naming level a
symbol name is expressed in. A lightweight, dependency-free value type, so
it can describe interface-name constants in Shared/ headers.
- Mangler (Shared/Mangler.h, Shared/Mangler.cpp): the linker name-mangling
logic factored out of MangleAndInterner. It holds only a ManglingMode (no
ExecutionSession or SymbolStringPool), so names can be mangled on the
executor side as well as the controller side. It exposes withMangledNameDo
(which avoids allocating when mangling is a no-op) and a mangledCopy
convenience, both dispatching on the spec's SymbolNameKind.
MangleAndInterner becomes a thin wrapper: it derives a ManglingMode (from an
ABIName / ManglingMode / DataLayout), holds a Mangler, and interns whatever the
Mangler produces. Behavior is unchanged.
This lets lookup utilities eventually accept C / IR source names and mangle
them to linker level on the caller's behalf, rather than requiring pre-mangled
names. The MangleAndInternerTest unit tests are renamed to ManglerTest and now
exercise Mangler directly; MangleAndInterner is left untested since it is
slated for removal.
---
.../llvm/ExecutionEngine/Orc/Mangling.h | 42 ++++----
.../llvm/ExecutionEngine/Orc/Shared/Mangler.h | 95 +++++++++++++++++++
.../Orc/Shared/SymbolNameSpec.h | 68 +++++++++++++
llvm/lib/ExecutionEngine/Orc/LLJIT.cpp | 2 +-
llvm/lib/ExecutionEngine/Orc/Mangling.cpp | 79 ---------------
.../ExecutionEngine/Orc/Shared/CMakeLists.txt | 1 +
.../ExecutionEngine/Orc/Shared/Mangler.cpp | 53 +++++++++++
.../ExecutionEngine/Orc/CMakeLists.txt | 2 +-
.../Orc/MangleAndInternerTest.cpp | 87 -----------------
.../ExecutionEngine/Orc/ManglerTest.cpp | 87 +++++++++++++++++
10 files changed, 329 insertions(+), 187 deletions(-)
create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
create mode 100644 llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
delete mode 100644 llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
create mode 100644 llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
index 650ba1fe8cc54..5fd664008e23d 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
@@ -14,6 +14,7 @@
#define LLVM_EXECUTIONENGINE_ORC_MANGLING_H
#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/Shared/Mangler.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Compiler.h"
@@ -26,30 +27,33 @@ namespace llvm::orc {
/// ExecutionSession.
class MangleAndInterner {
public:
- enum class ManglingMode {
- None,
- ELF,
- MachO,
- WinCOFF,
- WinCOFFX86,
- GOFF,
- Mips,
- XCOFF
- };
+ using ManglingMode = Mangler::ManglingMode;
+
+ MangleAndInterner(ExecutionSession &ES, Mangler M)
+ : ES(ES), M(std::move(M)) {}
+ MangleAndInterner(ExecutionSession &ES, ManglingMode Mode)
+ : ES(ES), M(Mode) {}
+ MangleAndInterner(ExecutionSession &ES, StringRef ABIName = "")
+ : ES(ES), M(ES.getTargetTriple(), ABIName) {}
+ MangleAndInterner(ExecutionSession &ES, const DataLayout &DL)
+ : ES(ES), M(DL.getStringRepresentation()) {}
+
+ const Mangler &mangler() const { return M; }
+
+ SymbolStringPtr operator()(const SymbolNameSpec &NameSpec) {
+ return M.withMangledNameDo(
+ [this](StringRef MangledName) { return ES.intern(MangledName); },
+ NameSpec);
+ }
- LLVM_ABI MangleAndInterner(ExecutionSession &ES, StringRef ABIName = "");
- LLVM_ABI MangleAndInterner(ExecutionSession &ES, ManglingMode Mode);
- LLVM_ABI MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
- LLVM_ABI SymbolStringPtr operator()(StringRef Name);
+ SymbolStringPtr operator()(StringRef Name) {
+ return (*this)(SymbolNameSpec(Name, SymbolNameKind::IR));
+ }
private:
- static ManglingMode fromDataLayoutStr(StringRef DLStr);
- static ManglingMode fromTriple(const Triple &TT, StringRef ABIName);
- static ManglingMode fromDataLayout(const DataLayout &DL);
- bool doNotMangleLeadingQuestionMark() const;
ExecutionSession &ES;
- ManglingMode Mode;
+ Mangler M;
};
/// Maps IR global values to their linker symbol names / flags.
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
new file mode 100644
index 0000000000000..c5075214a9155
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
@@ -0,0 +1,95 @@
+//===------- Mangler.h -- Linker name mangling for ORC ---------*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Linker name mangling for ORC.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_MANGLER_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_MANGLER_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h"
+#include "llvm/Support/Compiler.h"
+
+namespace llvm {
+
+class Triple;
+
+namespace orc {
+
+/// Applies linker name-mangling for a target.
+class Mangler {
+public:
+ /// The linker name-mangling scheme for a target, determined by its object
+ /// format. This captures the platform decoration applied to symbol names
+ /// (e.g. a leading '_' on MachO), independently of any ExecutionSession.
+ enum class ManglingMode {
+ None,
+ ELF,
+ MachO,
+ WinCOFF,
+ WinCOFFX86,
+ GOFF,
+ Mips,
+ XCOFF
+ };
+
+ explicit Mangler(ManglingMode Mode) : Mode(Mode) {}
+ explicit Mangler(StringRef DLStr) : Mode(fromDataLayoutStr(DLStr)) {}
+ explicit Mangler(const Triple &TT, StringRef ABIName = "")
+ : Mode(fromTriple(TT, ABIName)) {}
+
+ /// Calls the given callback with the mangled version of Name as a StringRef.
+ /// The mangled name is only valid for the duration of the callback and must
+ /// not escape. This allows withMangledNameDo to avoid allocations when
+ /// mangling is a no-op.
+ template <typename HandlerFn>
+ decltype(auto) withMangledNameDo(HandlerFn &&H,
+ const SymbolNameSpec &Name) const {
+ if (Name.getKind() == SymbolNameKind::Verbatim ||
+ Name.getKind() == SymbolNameKind::Linker)
+ return H(Name.getName());
+
+ if (Name.getName().empty())
+ return H(Name.getName());
+
+ if (Name.getName()[0] == '\1')
+ return H(Name.getName().substr(1));
+
+ if (Name.getName()[0] == '?' && doNotMangleLeadingQuestionMark())
+ return H(Name.getName());
+
+ if (Mode == ManglingMode::MachO || Mode == ManglingMode::WinCOFFX86)
+ return H(StringRef(("_" + Name.getName()).str()));
+
+ return H(Name.getName());
+ }
+
+ /// Construct a mangled version of the given name as a std::string.
+ /// This always produces a copy, even for no-op manglings. Prefer
+ /// withMangledNameDo in any performance-sensitive context.
+ std::string mangledCopy(const SymbolNameSpec &Name) const {
+ return withMangledNameDo(
+ [](StringRef MangledName) { return MangledName.str(); }, Name);
+ }
+
+private:
+ LLVM_ABI static ManglingMode fromDataLayoutStr(StringRef DLStr);
+ LLVM_ABI static ManglingMode fromTriple(const Triple &TT, StringRef ABIName);
+ bool doNotMangleLeadingQuestionMark() const {
+ return Mode == ManglingMode::WinCOFF || Mode == ManglingMode::WinCOFFX86;
+ }
+
+ ManglingMode Mode;
+};
+
+} // namespace orc
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_MANGLING_H
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
new file mode 100644
index 0000000000000..c52d4e1f770af
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
@@ -0,0 +1,68 @@
+//===- SymbolNameSpec.h - A symbol name plus its mangling kind --*- C++ -*-===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// A symbol name paired with the naming level it is expressed in.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
+
+#include "llvm/ADT/StringRef.h"
+
+namespace llvm::orc {
+
+/// The naming level a symbol name is expressed in, which determines how it is
+/// mangled before being interned for lookup.
+enum class SymbolNameKind {
+ Verbatim, // Use the name as given, with no mangling.
+ Linker, // An already-decorated linker name; a synonym for Verbatim.
+ IR, // An IR global name; mangled to linker level for the target.
+ C, // A C source name; handled identically to IR.
+};
+
+/// A symbol name together with the naming level (SymbolNameKind) it is
+/// expressed in, so that a Mangler / MangleAndInterner can mangle it to linker
+/// level rather than requiring callers to pre-mangle.
+///
+/// The name is not copied: a SymbolNameSpec must not outlive the string it
+/// refers to.
+///
+/// Implicitly constructible from a StringRef, defaulting to Verbatim, so that
+/// APIs taking a SymbolNameSpec stay drop-in replacements for ones that
+/// previously took an already-mangled StringRef.
+class SymbolNameSpec {
+public:
+ constexpr SymbolNameSpec(StringRef Name,
+ SymbolNameKind Kind = SymbolNameKind::Verbatim)
+ : Name(Name), Kind(Kind) {}
+
+ static constexpr SymbolNameSpec verbatim(StringRef Name) {
+ return {Name, SymbolNameKind::Verbatim};
+ }
+ static constexpr SymbolNameSpec linker(StringRef Name) {
+ return {Name, SymbolNameKind::Linker};
+ }
+ static constexpr SymbolNameSpec ir(StringRef Name) {
+ return {Name, SymbolNameKind::IR};
+ }
+ static constexpr SymbolNameSpec c(StringRef Name) {
+ return {Name, SymbolNameKind::C};
+ }
+
+ constexpr StringRef getName() const { return Name; }
+ constexpr SymbolNameKind getKind() const { return Kind; }
+
+private:
+ StringRef Name;
+ SymbolNameKind Kind;
+};
+
+} // namespace llvm::orc
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
diff --git a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
index 04d24d1d30497..938c8e076eb07 100644
--- a/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/LLJIT.cpp
@@ -1105,7 +1105,7 @@ std::string LLJIT::mangle(StringRef UnmangledName) const {
std::string MangledName;
{
raw_string_ostream MangledNameStream(MangledName);
- Mangler::getNameWithPrefix(MangledNameStream, UnmangledName, DL);
+ llvm::Mangler::getNameWithPrefix(MangledNameStream, UnmangledName, DL);
}
return MangledName;
}
diff --git a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
index ec95b56ef0e95..2fe78d615a5b5 100644
--- a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
@@ -7,92 +7,13 @@
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/Mangling.h"
-#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/IR/Constants.h"
-#include "llvm/IR/Mangler.h"
-#include "llvm/Support/ErrorHandling.h"
#define DEBUG_TYPE "orc"
namespace llvm::orc {
-MangleAndInterner::MangleAndInterner(ExecutionSession &ES, StringRef ABIName)
- : ES(ES), Mode(fromTriple(ES.getTargetTriple(), ABIName)) {}
-
-MangleAndInterner::MangleAndInterner(ExecutionSession &ES, ManglingMode Mode)
- : ES(ES), Mode(Mode) {}
-
-MangleAndInterner::MangleAndInterner(ExecutionSession &ES, const DataLayout &DL)
- : ES(ES), Mode(fromDataLayout(DL)) {}
-
-// TODO: The prefixing rules below, and the mangling-mode derivation in
-// fromDataLayoutStr, duplicate logic that already lives in llvm::Mangler
-// (getNameWithPrefix) and DataLayout (ManglingModeT and its "m:" spec
-// parsing). They are re-implemented here only because those APIs require a
-// full DataLayout, which this class is meant to work without. We should
-// refactor to have one copy of this code, probably best defined in
-// TargetParser, shared between all users.
-SymbolStringPtr MangleAndInterner::operator()(StringRef Name) {
- if (Name.empty())
- return ES.intern(Name);
-
- if (Name.front() == '\1')
- return ES.intern(Name.substr(1));
-
- if (Name[0] == '?' && doNotMangleLeadingQuestionMark())
- return ES.intern(Name);
-
- if (Mode == ManglingMode::MachO || Mode == ManglingMode::WinCOFFX86)
- return ES.intern(("_" + Name).str());
-
- return ES.intern(Name);
-}
-
-MangleAndInterner::ManglingMode
-MangleAndInterner::fromDataLayoutStr(StringRef DLStr) {
- for (StringRef Spec : split(DLStr, '-')) {
- if (!Spec.starts_with("m:"))
- continue;
- auto ModeStr = Spec.drop_front(2);
- assert(ModeStr.size() == 1 &&
- "invalid data layout string from Triple::computeDataLayout");
- switch (ModeStr[0]) {
- case 'e':
- return ManglingMode::ELF;
- case 'l':
- return ManglingMode::GOFF;
- case 'o':
- return ManglingMode::MachO;
- case 'm':
- return ManglingMode::Mips;
- case 'w':
- return ManglingMode::WinCOFF;
- case 'x':
- return ManglingMode::WinCOFFX86;
- case 'a':
- return ManglingMode::XCOFF;
- default:
- llvm_unreachable("Invalid mangling mode from Triple::computeDataLayout");
- }
- }
- return ManglingMode::None;
-}
-
-MangleAndInterner::ManglingMode
-MangleAndInterner::fromTriple(const Triple &TT, StringRef ABIName) {
- return fromDataLayoutStr(TT.computeDataLayout(ABIName));
-}
-
-MangleAndInterner::ManglingMode
-MangleAndInterner::fromDataLayout(const DataLayout &DL) {
- return fromDataLayoutStr(DL.getStringRepresentation());
-}
-
-bool MangleAndInterner::doNotMangleLeadingQuestionMark() const {
- return Mode == ManglingMode::WinCOFF || Mode == ManglingMode::WinCOFFX86;
-}
-
void IRSymbolMapper::add(ExecutionSession &ES, const ManglingOptions &MO,
ArrayRef<GlobalValue *> GVs,
SymbolFlagsMap &SymbolFlags,
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
index 717fc21826aba..33a8a41df1e0f 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
@@ -1,6 +1,7 @@
add_llvm_component_library(LLVMOrcShared
AllocationActions.cpp
MachOObjectFormat.cpp
+ Mangler.cpp
ObjectFormats.cpp
OrcError.cpp
OrcRTBridge.cpp
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
new file mode 100644
index 0000000000000..e66aa2bcdc677
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
@@ -0,0 +1,53 @@
+//===------------- Mangler.cpp -- Linker name mangling for ORC ------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Shared/Mangler.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/TargetParser/Triple.h"
+
+#include <cassert>
+
+#define DEBUG_TYPE "orc"
+
+namespace llvm::orc {
+
+Mangler::ManglingMode Mangler::fromDataLayoutStr(StringRef DLStr) {
+ for (StringRef Spec : split(DLStr, '-')) {
+ if (!Spec.starts_with("m:"))
+ continue;
+ auto ModeStr = Spec.drop_front(2);
+ assert(ModeStr.size() == 1 &&
+ "invalid data layout string from Triple::computeDataLayout");
+ switch (ModeStr[0]) {
+ case 'e':
+ return ManglingMode::ELF;
+ case 'l':
+ return ManglingMode::GOFF;
+ case 'o':
+ return ManglingMode::MachO;
+ case 'm':
+ return ManglingMode::Mips;
+ case 'w':
+ return ManglingMode::WinCOFF;
+ case 'x':
+ return ManglingMode::WinCOFFX86;
+ case 'a':
+ return ManglingMode::XCOFF;
+ default:
+ llvm_unreachable("Invalid mangling mode from Triple::computeDataLayout");
+ }
+ }
+ return ManglingMode::None;
+}
+
+Mangler::ManglingMode Mangler::fromTriple(const Triple &TT, StringRef ABIName) {
+ return fromDataLayoutStr(TT.computeDataLayout(ABIName));
+}
+
+} // namespace llvm::orc
diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index a9271bac9d1c7..7e5f3f2192011 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -33,7 +33,7 @@ add_llvm_unittest(OrcJITTests
LinkGraphLinkingLayerTest.cpp
LookupAndApplyTest.cpp
MachOBuilderTest.cpp
- MangleAndInternerTest.cpp
+ ManglerTest.cpp
MachOPlatformTest.cpp
MapperJITLinkMemoryManagerTest.cpp
MemoryFlagsTest.cpp
diff --git a/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
deleted file mode 100644
index a047985ad1d3b..0000000000000
--- a/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
+++ /dev/null
@@ -1,87 +0,0 @@
-//===---- MangleAndInternerTest.cpp - Unit tests for MangleAndInterner ----===//
-//
-// 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
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ExecutionEngine/Orc/Mangling.h"
-#include "llvm/Support/Error.h"
-
-#include "OrcTestCommon.h"
-
-using namespace llvm;
-using namespace llvm::orc;
-
-namespace {
-
-ExecutionSession makeES(StringRef TT) {
- return ExecutionSession(std::make_unique<UnsupportedExecutorProcessControl>(
- nullptr, nullptr, TT.str()));
-}
-
-struct ManglingCase {
- StringRef Triple;
- StringRef Input;
- StringRef Expected;
-};
-
-} // namespace
-
-TEST(MangleAndInternerTest, FromTripleAcrossFormats) {
- static const ManglingCase Cases[] = {
- // ELF: no prefix.
- {"x86_64-unknown-linux-gnu", "foo", "foo"},
- // MachO: leading underscore.
- {"x86_64-apple-darwin", "foo", "_foo"},
- {"arm64-apple-darwin", "foo", "_foo"},
- // Windows COFF, x86_64: no prefix.
- {"x86_64-pc-windows-msvc", "foo", "foo"},
- // Windows COFF, x86 (32-bit): leading underscore.
- {"i686-pc-windows-msvc", "foo", "_foo"},
- // AIX XCOFF: no prefix.
- {"powerpc64-ibm-aix", "foo", "foo"},
- // z/OS GOFF: no prefix.
- {"s390x-ibm-zos", "foo", "foo"},
- // MIPS O32: no prefix.
- {"mipsel-unknown-linux-gnu", "foo", "foo"},
- };
-
- for (const auto &C : Cases) {
- SCOPED_TRACE(C.Triple);
- ExecutionSession ES = makeES(C.Triple);
- MangleAndInterner Mangle(ES);
- EXPECT_EQ(*Mangle(C.Input), C.Expected);
- cantFail(ES.endSession());
- }
-}
-
-TEST(MangleAndInternerTest, DoNotMangleLeadingBackslash1) {
- ExecutionSession ES = makeES("x86_64-apple-darwin");
- MangleAndInterner Mangle(ES);
- EXPECT_EQ(*Mangle("\1foo"), "foo");
- cantFail(ES.endSession());
-}
-
-TEST(MangleAndInternerTest, WindowsQuestionMarkNotMangled) {
- ExecutionSession ES = makeES("x86_64-pc-windows-msvc");
- MangleAndInterner Mangle(ES);
- EXPECT_EQ(*Mangle("?foo@@YAHXZ"), "?foo@@YAHXZ");
- cantFail(ES.endSession());
-}
-
-TEST(MangleAndInternerTest, MachOQuestionMarkIsMangled) {
- // MachO has no question-mark suppression: gets the usual '_' prefix.
- ExecutionSession ES = makeES("x86_64-apple-darwin");
- MangleAndInterner Mangle(ES);
- EXPECT_EQ(*Mangle("?foo"), "_?foo");
- cantFail(ES.endSession());
-}
-
-TEST(MangleAndInternerTest, ExplicitManglingMode) {
- ExecutionSession ES = makeES("x86_64-unknown-linux-gnu");
- MangleAndInterner Mangle(ES, MangleAndInterner::ManglingMode::MachO);
- EXPECT_EQ(*Mangle("foo"), "_foo");
- cantFail(ES.endSession());
-}
diff --git a/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
new file mode 100644
index 0000000000000..41ec22c432021
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
@@ -0,0 +1,87 @@
+//===-------------- ManglerTest.cpp - Unit tests for Mangler --------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/ExecutionEngine/Orc/Shared/Mangler.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h"
+
+#include "OrcTestCommon.h"
+
+using namespace llvm;
+using namespace llvm::orc;
+
+namespace {
+
+struct ManglingCase {
+ StringRef Triple;
+ StringRef Input;
+ StringRef Expected;
+};
+
+} // namespace
+
+TEST(ManglerTest, FromTripleAcrossFormats) {
+ static const ManglingCase Cases[] = {
+ // ELF: no prefix.
+ {"x86_64-unknown-linux-gnu", "foo", "foo"},
+ // MachO: leading underscore.
+ {"x86_64-apple-darwin", "foo", "_foo"},
+ {"arm64-apple-darwin", "foo", "_foo"},
+ // Windows COFF, x86_64: no prefix.
+ {"x86_64-pc-windows-msvc", "foo", "foo"},
+ // Windows COFF, x86 (32-bit): leading underscore.
+ {"i686-pc-windows-msvc", "foo", "_foo"},
+ // AIX XCOFF: no prefix.
+ {"powerpc64-ibm-aix", "foo", "foo"},
+ // z/OS GOFF: no prefix.
+ {"s390x-ibm-zos", "foo", "foo"},
+ // MIPS O32: no prefix.
+ {"mipsel-unknown-linux-gnu", "foo", "foo"},
+ };
+
+ for (const auto &C : Cases) {
+ SCOPED_TRACE(C.Triple);
+ Mangler Mangle(Triple(C.Triple));
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir(C.Input)), C.Expected);
+ }
+}
+
+TEST(ManglerTest, DoNotMangleLeadingBackslash1) {
+ Mangler Mangle(Triple("x86_64-apple-darwin"));
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("\1foo")), "foo");
+}
+
+TEST(ManglerTest, WindowsQuestionMarkNotMangled) {
+ Mangler Mangle(Triple("x86_64-pc-windows-msvc"));
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("?foo@@YAHXZ")),
+ "?foo@@YAHXZ");
+}
+
+TEST(ManglerTest, MachOQuestionMarkIsMangled) {
+ // MachO has no question-mark suppression: gets the usual '_' prefix.
+ Mangler Mangle(Triple("x86_64-apple-darwin"));
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("?foo")), "_?foo");
+}
+
+TEST(ManglerTest, ExplicitManglingMode) {
+ Mangler Mangle(Mangler::ManglingMode::MachO);
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("foo")), "_foo");
+}
+
+// Use a MachO triple so that mangling ("_" prefix) is observably different from
+// interning verbatim.
+TEST(ManglerTest, SymbolNameSpecKindDispatch) {
+ Mangler Mangle(Triple("x86_64-apple-darwin"));
+
+ // Verbatim and Linker are interned unmodified.
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::verbatim("foo")), "foo");
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::linker("foo")), "foo");
+
+ // IR and C are mangled (leading "_" on MachO).
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("foo")), "_foo");
+ EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::c("foo")), "_foo");
+}
>From 9cab371571f3390908ea8d2c45c4d26927b8ac89 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Tue, 8 Sep 2026 12:01:31 +1000
Subject: [PATCH 2/4] clang-format
---
llvm/include/llvm/ExecutionEngine/Orc/Mangling.h | 1 -
1 file changed, 1 deletion(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
index 5fd664008e23d..46c1b926def7d 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
@@ -51,7 +51,6 @@ class MangleAndInterner {
}
private:
-
ExecutionSession &ES;
Mangler M;
};
>From 66a75b844dcbcb20317509549b9641555dfbed3c Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Tue, 8 Sep 2026 12:41:24 +1000
Subject: [PATCH 3/4] Use SmallString for mangling
---
llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h | 8 ++++++--
1 file changed, 6 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
index c5075214a9155..f711f1d777ae6 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
@@ -13,6 +13,7 @@
#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_MANGLER_H
#define LLVM_EXECUTIONENGINE_ORC_SHARED_MANGLER_H
+#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h"
#include "llvm/Support/Compiler.h"
@@ -65,8 +66,11 @@ class Mangler {
if (Name.getName()[0] == '?' && doNotMangleLeadingQuestionMark())
return H(Name.getName());
- if (Mode == ManglingMode::MachO || Mode == ManglingMode::WinCOFFX86)
- return H(StringRef(("_" + Name.getName()).str()));
+ if (Mode == ManglingMode::MachO || Mode == ManglingMode::WinCOFFX86) {
+ SmallString<1024> MangledName;
+ MangledName.append({StringRef("_"), Name.getName()});
+ return H(StringRef(MangledName));
+ }
return H(Name.getName());
}
>From b334554f5ec16116bb723cd2b5a7e94ae8904d68 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Tue, 8 Sep 2026 15:26:49 +1000
Subject: [PATCH 4/4] Simplify mode enum name, rename namespec arg
---
.../llvm/ExecutionEngine/Orc/Mangling.h | 2 +-
.../llvm/ExecutionEngine/Orc/Shared/Mangler.h | 61 ++++++++-----------
.../ExecutionEngine/Orc/Shared/Mangler.cpp | 20 +++---
.../ExecutionEngine/Orc/ManglerTest.cpp | 2 +-
4 files changed, 38 insertions(+), 47 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
index 46c1b926def7d..f592608ef1557 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
@@ -27,7 +27,7 @@ namespace llvm::orc {
/// ExecutionSession.
class MangleAndInterner {
public:
- using ManglingMode = Mangler::ManglingMode;
+ using ManglingMode = Mangler::Mode;
MangleAndInterner(ExecutionSession &ES, Mangler M)
: ES(ES), M(std::move(M)) {}
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
index f711f1d777ae6..e9a2f268fbaff 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h
@@ -30,49 +30,40 @@ class Mangler {
/// The linker name-mangling scheme for a target, determined by its object
/// format. This captures the platform decoration applied to symbol names
/// (e.g. a leading '_' on MachO), independently of any ExecutionSession.
- enum class ManglingMode {
- None,
- ELF,
- MachO,
- WinCOFF,
- WinCOFFX86,
- GOFF,
- Mips,
- XCOFF
- };
-
- explicit Mangler(ManglingMode Mode) : Mode(Mode) {}
- explicit Mangler(StringRef DLStr) : Mode(fromDataLayoutStr(DLStr)) {}
+ enum class Mode { None, ELF, MachO, WinCOFF, WinCOFFX86, GOFF, Mips, XCOFF };
+
+ explicit Mangler(Mode MM) : MM(MM) {}
+ explicit Mangler(StringRef DLStr) : MM(fromDataLayoutStr(DLStr)) {}
explicit Mangler(const Triple &TT, StringRef ABIName = "")
- : Mode(fromTriple(TT, ABIName)) {}
+ : MM(fromTriple(TT, ABIName)) {}
- /// Calls the given callback with the mangled version of Name as a StringRef.
- /// The mangled name is only valid for the duration of the callback and must
- /// not escape. This allows withMangledNameDo to avoid allocations when
- /// mangling is a no-op.
+ /// Calls the given callback with the mangled version of NameSpec as a
+ /// StringRef. The mangled name is only valid for the duration of the callback
+ /// and must not escape. This allows withMangledNameDo to avoid allocations
+ /// when mangling is a no-op.
template <typename HandlerFn>
decltype(auto) withMangledNameDo(HandlerFn &&H,
- const SymbolNameSpec &Name) const {
- if (Name.getKind() == SymbolNameKind::Verbatim ||
- Name.getKind() == SymbolNameKind::Linker)
- return H(Name.getName());
+ const SymbolNameSpec &NameSpec) const {
+ if (NameSpec.getKind() == SymbolNameKind::Verbatim ||
+ NameSpec.getKind() == SymbolNameKind::Linker)
+ return H(NameSpec.getName());
- if (Name.getName().empty())
- return H(Name.getName());
+ if (NameSpec.getName().empty())
+ return H(NameSpec.getName());
- if (Name.getName()[0] == '\1')
- return H(Name.getName().substr(1));
+ if (NameSpec.getName()[0] == '\1')
+ return H(NameSpec.getName().substr(1));
- if (Name.getName()[0] == '?' && doNotMangleLeadingQuestionMark())
- return H(Name.getName());
+ if (NameSpec.getName()[0] == '?' && doNotMangleLeadingQuestionMark())
+ return H(NameSpec.getName());
- if (Mode == ManglingMode::MachO || Mode == ManglingMode::WinCOFFX86) {
+ if (MM == Mode::MachO || MM == Mode::WinCOFFX86) {
SmallString<1024> MangledName;
- MangledName.append({StringRef("_"), Name.getName()});
+ MangledName.append({StringRef("_"), NameSpec.getName()});
return H(StringRef(MangledName));
}
- return H(Name.getName());
+ return H(NameSpec.getName());
}
/// Construct a mangled version of the given name as a std::string.
@@ -84,13 +75,13 @@ class Mangler {
}
private:
- LLVM_ABI static ManglingMode fromDataLayoutStr(StringRef DLStr);
- LLVM_ABI static ManglingMode fromTriple(const Triple &TT, StringRef ABIName);
+ LLVM_ABI static Mode fromDataLayoutStr(StringRef DLStr);
+ LLVM_ABI static Mode fromTriple(const Triple &TT, StringRef ABIName);
bool doNotMangleLeadingQuestionMark() const {
- return Mode == ManglingMode::WinCOFF || Mode == ManglingMode::WinCOFFX86;
+ return MM == Mode::WinCOFF || MM == Mode::WinCOFFX86;
}
- ManglingMode Mode;
+ Mode MM;
};
} // namespace orc
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
index e66aa2bcdc677..824b3d7053ddd 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Mangler.cpp
@@ -17,7 +17,7 @@
namespace llvm::orc {
-Mangler::ManglingMode Mangler::fromDataLayoutStr(StringRef DLStr) {
+Mangler::Mode Mangler::fromDataLayoutStr(StringRef DLStr) {
for (StringRef Spec : split(DLStr, '-')) {
if (!Spec.starts_with("m:"))
continue;
@@ -26,27 +26,27 @@ Mangler::ManglingMode Mangler::fromDataLayoutStr(StringRef DLStr) {
"invalid data layout string from Triple::computeDataLayout");
switch (ModeStr[0]) {
case 'e':
- return ManglingMode::ELF;
+ return Mode::ELF;
case 'l':
- return ManglingMode::GOFF;
+ return Mode::GOFF;
case 'o':
- return ManglingMode::MachO;
+ return Mode::MachO;
case 'm':
- return ManglingMode::Mips;
+ return Mode::Mips;
case 'w':
- return ManglingMode::WinCOFF;
+ return Mode::WinCOFF;
case 'x':
- return ManglingMode::WinCOFFX86;
+ return Mode::WinCOFFX86;
case 'a':
- return ManglingMode::XCOFF;
+ return Mode::XCOFF;
default:
llvm_unreachable("Invalid mangling mode from Triple::computeDataLayout");
}
}
- return ManglingMode::None;
+ return Mode::None;
}
-Mangler::ManglingMode Mangler::fromTriple(const Triple &TT, StringRef ABIName) {
+Mangler::Mode Mangler::fromTriple(const Triple &TT, StringRef ABIName) {
return fromDataLayoutStr(TT.computeDataLayout(ABIName));
}
diff --git a/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
index 41ec22c432021..ed0aff788cfd0 100644
--- a/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/ManglerTest.cpp
@@ -68,7 +68,7 @@ TEST(ManglerTest, MachOQuestionMarkIsMangled) {
}
TEST(ManglerTest, ExplicitManglingMode) {
- Mangler Mangle(Mangler::ManglingMode::MachO);
+ Mangler Mangle(Mangler::Mode::MachO);
EXPECT_EQ(Mangle.mangledCopy(SymbolNameSpec::ir("foo")), "_foo");
}
More information about the llvm-commits
mailing list