[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 00:08:51 PDT 2026
https://github.com/lhames updated https://github.com/llvm/llvm-project/pull/221635
>From e1ed1f777ae4667da1fa61c9874fcb9fe26346df 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/3] [ORC] Add SymbolNameSpec for mangling-aware symbol names
Introduce SymbolNameSpec, a pair of a StringRef and a SymbolNameKind
(Verbatim, Linker, C, IR) describing the scheme a symbol name is
expressed in. Its mangleAndIntern(ES) method interns the name, applying
platform mangling for C / IR names (e.g. "malloc" -> "_malloc" on MachO)
and interning Verbatim / Linker names as-is.
This lets lookup utilities such as recordAddr and recordProxy accept C /
IR source names directly, instead of requiring callers to pre-mangle to
linker-level by hand, which is easy to get wrong.
Linker is currently a synonym for Verbatim, and C for IR; the kinds are
kept distinct to document call-site intent.
Future commits will migrate recordAddr / recordProxy to SymbolNameSpec.
---
.../llvm/ExecutionEngine/Orc/SymbolNameSpec.h | 85 +++++++++++++++++++
.../ExecutionEngine/Orc/CMakeLists.txt | 1 +
.../Orc/SymbolNameSpecTest.cpp | 43 ++++++++++
3 files changed, 129 insertions(+)
create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h
create mode 100644 llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h b/llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h
new file mode 100644
index 0000000000000..961f4837d788d
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h
@@ -0,0 +1,85 @@
+//===- 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 SymbolNameSpec pairs a symbol name with the naming level it is expressed
+// in, so that lookup utilities can accept C / IR source names and mangle them
+// to linker level on the caller's behalf rather than requiring pre-mangled
+// names.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
+#define LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/Mangling.h"
+#include "llvm/Support/ErrorHandling.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 it is expressed in.
+///
+/// The name is not copied: a SymbolNameSpec must not outlive the string it
+/// refers to, and must remain valid until intern() is called on it.
+///
+/// SymbolNameSpec is 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:
+ SymbolNameSpec(StringRef Name, SymbolNameKind Kind = SymbolNameKind::Verbatim)
+ : Name(Name), Kind(Kind) {}
+
+ static SymbolNameSpec verbatim(StringRef Name) {
+ return {Name, SymbolNameKind::Verbatim};
+ }
+ static SymbolNameSpec linker(StringRef Name) {
+ return {Name, SymbolNameKind::Linker};
+ }
+ static SymbolNameSpec ir(StringRef Name) {
+ return {Name, SymbolNameKind::IR};
+ }
+ static SymbolNameSpec c(StringRef Name) { return {Name, SymbolNameKind::C}; }
+
+ StringRef getName() const { return Name; }
+ SymbolNameKind getKind() const { return Kind; }
+
+ /// Mangle (if required by Kind) and intern this name in the context of ES.
+ ///
+ /// C / IR names are mangled for ES's target triple, not for any particular
+ /// JITDylib's platform.
+ SymbolStringPtr mangleAndIntern(ExecutionSession &ES) const {
+ switch (Kind) {
+ case SymbolNameKind::Verbatim:
+ case SymbolNameKind::Linker:
+ return ES.intern(Name);
+ case SymbolNameKind::IR:
+ case SymbolNameKind::C:
+ return MangleAndInterner(ES)(Name);
+ }
+ llvm_unreachable("Unknown SymbolNameKind");
+ }
+
+private:
+ StringRef Name;
+ SymbolNameKind Kind;
+};
+
+} // namespace llvm::orc
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index a9271bac9d1c7..47c9f332a37ce 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -50,6 +50,7 @@ add_llvm_unittest(OrcJITTests
SimplePackedSerializationTest.cpp
SPSProxySpecTest.cpp
SymbolLookupSetTest.cpp
+ SymbolNameSpecTest.cpp
SymbolStringPoolTest.cpp
TaskDispatchTest.cpp
ThreadSafeModuleTest.cpp
diff --git a/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
new file mode 100644
index 0000000000000..ee221f2f4fdba
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
@@ -0,0 +1,43 @@
+//===------ SymbolNameSpecTest.cpp - Unit tests for SymbolNameSpec --------===//
+//
+// 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/SymbolNameSpec.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()));
+}
+
+} // namespace
+
+// Use a MachO triple so that mangling ("_" prefix) is observably different from
+// interning verbatim.
+TEST(SymbolNameSpecTest, KindDispatch) {
+ ExecutionSession ES = makeES("x86_64-apple-darwin");
+
+ // Verbatim interns unmodified.
+ EXPECT_EQ(*SymbolNameSpec::verbatim("foo").mangleAndIntern(ES), "foo");
+
+ // Linker mangles as Verbatim (unmodified).
+ EXPECT_EQ(*SymbolNameSpec::linker("foo").mangleAndIntern(ES), "foo");
+
+ // IR mangles as C (leading "_" on MachO).
+ EXPECT_EQ(*SymbolNameSpec::ir("foo").mangleAndIntern(ES),
+ *SymbolNameSpec::c("foo").mangleAndIntern(ES));
+ EXPECT_EQ(*SymbolNameSpec::c("foo").mangleAndIntern(ES), "_foo");
+
+ cantFail(ES.endSession());
+}
>From ac2fa5cba111dbf10c968c427fb22bd2f5a1c5b7 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Mon, 7 Sep 2026 16:57:38 +1000
Subject: [PATCH 2/3] Move SymbolNameSpec up into Shared so that it can be used
for constants.
---
.../llvm/ExecutionEngine/Orc/Mangling.h | 6 +++
.../Orc/{ => Shared}/SymbolNameSpec.h | 52 +++++++------------
llvm/lib/ExecutionEngine/Orc/Mangling.cpp | 12 +++++
.../ExecutionEngine/Orc/CMakeLists.txt | 1 -
.../Orc/MangleAndInternerTest.cpp | 18 +++++++
.../Orc/SymbolNameSpecTest.cpp | 43 ---------------
6 files changed, 55 insertions(+), 77 deletions(-)
rename llvm/include/llvm/ExecutionEngine/Orc/{ => Shared}/SymbolNameSpec.h (53%)
delete mode 100644 llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
index 650ba1fe8cc54..f2c9b5cb87adc 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/SymbolNameSpec.h"
#include "llvm/ExecutionEngine/Orc/ThreadSafeModule.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Compiler.h"
@@ -42,6 +43,11 @@ class MangleAndInterner {
LLVM_ABI MangleAndInterner(ExecutionSession &ES, const DataLayout &DL);
LLVM_ABI SymbolStringPtr operator()(StringRef Name);
+ /// Mangle and intern according to the spec's SymbolNameKind: Verbatim and
+ /// Linker names are interned as-is; IR and C names are mangled as for the
+ /// StringRef overload.
+ LLVM_ABI SymbolStringPtr operator()(const SymbolNameSpec &Name);
+
private:
static ManglingMode fromDataLayoutStr(StringRef DLStr);
static ManglingMode fromTriple(const Triple &TT, StringRef ABIName);
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
similarity index 53%
rename from llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h
rename to llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
index 961f4837d788d..3f220f2018f42 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/SymbolNameSpec.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
@@ -7,19 +7,18 @@
//===----------------------------------------------------------------------===//
//
// A SymbolNameSpec pairs a symbol name with the naming level it is expressed
-// in, so that lookup utilities can accept C / IR source names and mangle them
-// to linker level on the caller's behalf rather than requiring pre-mangled
-// names.
+// in, so that names can be mangled to linker level on the caller's behalf
+// (see MangleAndInterner) rather than requiring callers to pre-mangle them.
+//
+// This is a lightweight, dependency-free value type so that it can be used to
+// describe interface-name constants in Shared/ headers.
//
//===----------------------------------------------------------------------===//
-#ifndef LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
-#define LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
#include "llvm/ADT/StringRef.h"
-#include "llvm/ExecutionEngine/Orc/Core.h"
-#include "llvm/ExecutionEngine/Orc/Mangling.h"
-#include "llvm/Support/ErrorHandling.h"
namespace llvm::orc {
@@ -35,46 +34,33 @@ enum class SymbolNameKind {
/// A symbol name together with the naming level it is expressed in.
///
/// The name is not copied: a SymbolNameSpec must not outlive the string it
-/// refers to, and must remain valid until intern() is called on it.
+/// refers to.
///
/// SymbolNameSpec is 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:
- SymbolNameSpec(StringRef Name, SymbolNameKind Kind = SymbolNameKind::Verbatim)
+ constexpr SymbolNameSpec(StringRef Name, SymbolNameKind Kind =
+ SymbolNameKind::Verbatim)
: Name(Name), Kind(Kind) {}
- static SymbolNameSpec verbatim(StringRef Name) {
+ static constexpr SymbolNameSpec verbatim(StringRef Name) {
return {Name, SymbolNameKind::Verbatim};
}
- static SymbolNameSpec linker(StringRef Name) {
+ static constexpr SymbolNameSpec linker(StringRef Name) {
return {Name, SymbolNameKind::Linker};
}
- static SymbolNameSpec ir(StringRef Name) {
+ static constexpr SymbolNameSpec ir(StringRef Name) {
return {Name, SymbolNameKind::IR};
}
- static SymbolNameSpec c(StringRef Name) { return {Name, SymbolNameKind::C}; }
-
- StringRef getName() const { return Name; }
- SymbolNameKind getKind() const { return Kind; }
-
- /// Mangle (if required by Kind) and intern this name in the context of ES.
- ///
- /// C / IR names are mangled for ES's target triple, not for any particular
- /// JITDylib's platform.
- SymbolStringPtr mangleAndIntern(ExecutionSession &ES) const {
- switch (Kind) {
- case SymbolNameKind::Verbatim:
- case SymbolNameKind::Linker:
- return ES.intern(Name);
- case SymbolNameKind::IR:
- case SymbolNameKind::C:
- return MangleAndInterner(ES)(Name);
- }
- llvm_unreachable("Unknown SymbolNameKind");
+ 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;
@@ -82,4 +68,4 @@ class SymbolNameSpec {
} // namespace llvm::orc
-#endif // LLVM_EXECUTIONENGINE_ORC_SYMBOLNAMESPEC_H
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_SYMBOLNAMESPEC_H
diff --git a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
index ec95b56ef0e95..cffb2a961826c 100644
--- a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
@@ -49,6 +49,18 @@ SymbolStringPtr MangleAndInterner::operator()(StringRef Name) {
return ES.intern(Name);
}
+SymbolStringPtr MangleAndInterner::operator()(const SymbolNameSpec &Name) {
+ switch (Name.getKind()) {
+ case SymbolNameKind::Verbatim:
+ case SymbolNameKind::Linker:
+ return ES.intern(Name.getName());
+ case SymbolNameKind::IR:
+ case SymbolNameKind::C:
+ return (*this)(Name.getName());
+ }
+ llvm_unreachable("Unknown SymbolNameKind");
+}
+
MangleAndInterner::ManglingMode
MangleAndInterner::fromDataLayoutStr(StringRef DLStr) {
for (StringRef Spec : split(DLStr, '-')) {
diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 47c9f332a37ce..a9271bac9d1c7 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -50,7 +50,6 @@ add_llvm_unittest(OrcJITTests
SimplePackedSerializationTest.cpp
SPSProxySpecTest.cpp
SymbolLookupSetTest.cpp
- SymbolNameSpecTest.cpp
SymbolStringPoolTest.cpp
TaskDispatchTest.cpp
ThreadSafeModuleTest.cpp
diff --git a/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
index a047985ad1d3b..d412bdf05f747 100644
--- a/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
+++ b/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
@@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//
#include "llvm/ExecutionEngine/Orc/Mangling.h"
+#include "llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h"
#include "llvm/Support/Error.h"
#include "OrcTestCommon.h"
@@ -85,3 +86,20 @@ TEST(MangleAndInternerTest, ExplicitManglingMode) {
EXPECT_EQ(*Mangle("foo"), "_foo");
cantFail(ES.endSession());
}
+
+// Use a MachO triple so that mangling ("_" prefix) is observably different from
+// interning verbatim.
+TEST(MangleAndInternerTest, SymbolNameSpecKindDispatch) {
+ ExecutionSession ES = makeES("x86_64-apple-darwin");
+ MangleAndInterner Mangle(ES);
+
+ // Verbatim and Linker are interned unmodified.
+ EXPECT_EQ(*Mangle(SymbolNameSpec::verbatim("foo")), "foo");
+ EXPECT_EQ(*Mangle(SymbolNameSpec::linker("foo")), "foo");
+
+ // IR and C are mangled (leading "_" on MachO).
+ EXPECT_EQ(*Mangle(SymbolNameSpec::ir("foo")), "_foo");
+ EXPECT_EQ(*Mangle(SymbolNameSpec::c("foo")), "_foo");
+
+ cantFail(ES.endSession());
+}
diff --git a/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp b/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
deleted file mode 100644
index ee221f2f4fdba..0000000000000
--- a/llvm/unittests/ExecutionEngine/Orc/SymbolNameSpecTest.cpp
+++ /dev/null
@@ -1,43 +0,0 @@
-//===------ SymbolNameSpecTest.cpp - Unit tests for SymbolNameSpec --------===//
-//
-// 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/SymbolNameSpec.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()));
-}
-
-} // namespace
-
-// Use a MachO triple so that mangling ("_" prefix) is observably different from
-// interning verbatim.
-TEST(SymbolNameSpecTest, KindDispatch) {
- ExecutionSession ES = makeES("x86_64-apple-darwin");
-
- // Verbatim interns unmodified.
- EXPECT_EQ(*SymbolNameSpec::verbatim("foo").mangleAndIntern(ES), "foo");
-
- // Linker mangles as Verbatim (unmodified).
- EXPECT_EQ(*SymbolNameSpec::linker("foo").mangleAndIntern(ES), "foo");
-
- // IR mangles as C (leading "_" on MachO).
- EXPECT_EQ(*SymbolNameSpec::ir("foo").mangleAndIntern(ES),
- *SymbolNameSpec::c("foo").mangleAndIntern(ES));
- EXPECT_EQ(*SymbolNameSpec::c("foo").mangleAndIntern(ES), "_foo");
-
- cantFail(ES.endSession());
-}
>From 56d8c495512d3869315d50c4648f807b0aa8eed3 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Mon, 7 Sep 2026 17:08:35 +1000
Subject: [PATCH 3/3] clang-format
---
llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
index 3f220f2018f42..239c5555a4563 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/SymbolNameSpec.h
@@ -41,8 +41,8 @@ enum class SymbolNameKind {
/// ones that previously took an already-mangled StringRef.
class SymbolNameSpec {
public:
- constexpr SymbolNameSpec(StringRef Name, SymbolNameKind Kind =
- SymbolNameKind::Verbatim)
+ constexpr SymbolNameSpec(StringRef Name,
+ SymbolNameKind Kind = SymbolNameKind::Verbatim)
: Name(Name), Kind(Kind) {}
static constexpr SymbolNameSpec verbatim(StringRef Name) {
More information about the llvm-commits
mailing list