[llvm] [orc-rt] Add Mangling.h with platform symbol name mangling (PR #222315)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed Sep 9 05:36:02 PDT 2026


https://github.com/lhames created https://github.com/llvm/llvm-project/pull/222315

This implements a cut-down version of the LLVM equivalent (in llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h): SymbolNameSpec pairs a name with a kind (assembly, C). Mangling functions (withMangledNameDo, mangledCopy) apply mangling to SymbolNameSpecs based on the symbol name kind.

These utilities will be used to report symbols (e.g. controller interface symbols) in the platform's native mangling, so that linking against them requires no special handling.

>From 44d53fb34b3bab625dfa418b5abcaa83c7b68ac1 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at apple.com>
Date: Tue, 8 Sep 2026 16:07:44 +1000
Subject: [PATCH] [orc-rt] Add Mangling.h with platform symbol name mangling

This implements a cut-down version of the LLVM equivalent (in
llvm/include/llvm/ExecutionEngine/Orc/Shared/Mangler.h): SymbolNameSpec pairs
a name with a kind (assembly, C). Mangling functions (withMangledNameDo,
mangledCopy) apply mangling to SymbolNameSpecs based on the symbol name kind.

These utilities will be used to report symbols (e.g. controller interface
symbols) in the platform's native mangling, so that linking against them
requires no special handling.
---
 orc-rt/include/CMakeLists.txt             |   1 +
 orc-rt/include/orc-rt/support/Mangling.h  | 107 ++++++++++++++++++++++
 orc-rt/test/unit/CMakeLists.txt           |   1 +
 orc-rt/test/unit/support/ManglingTest.cpp |  36 ++++++++
 4 files changed, 145 insertions(+)
 create mode 100644 orc-rt/include/orc-rt/support/Mangling.h
 create mode 100644 orc-rt/test/unit/support/ManglingTest.cpp

diff --git a/orc-rt/include/CMakeLists.txt b/orc-rt/include/CMakeLists.txt
index 732076c494a5c..60b004f8a1aa5 100644
--- a/orc-rt/include/CMakeLists.txt
+++ b/orc-rt/include/CMakeLists.txt
@@ -41,6 +41,7 @@ set(ORC_RT_HEADERS
     orc-rt/support/IntervalSet.h
     orc-rt/support/LockedAccess.h
     orc-rt/support/MacroUtils.h
+    orc-rt/support/Mangling.h
     orc-rt/support/MemoryFlags.h
     orc-rt/support/Proxy.h
     orc-rt/support/RTTI.h
diff --git a/orc-rt/include/orc-rt/support/Mangling.h b/orc-rt/include/orc-rt/support/Mangling.h
new file mode 100644
index 0000000000000..3b686848ab8c4
--- /dev/null
+++ b/orc-rt/include/orc-rt/support/Mangling.h
@@ -0,0 +1,107 @@
+//===------------ Mangling.h - Name mangling for ORC RT ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Mangling of symbol names to the linker-level names used by the platform.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef ORC_RT_SUPPORT_MANGLING_H
+#define ORC_RT_SUPPORT_MANGLING_H
+
+#include <cstring>
+#include <memory>
+#include <string>
+#include <string_view>
+
+namespace orc_rt {
+
+/// The level a symbol name is written at, which determines whether the platform
+/// decorates it.
+///
+/// Linker names are linker-level already and are used as written. C names are
+/// C identifiers, and may be decorated: on Darwin they gain a leading
+/// underscore.
+enum class SymbolNameKind { Linker, C };
+
+/// Pairs a symbol name with the kind of name it is, so that mangling can be
+/// applied where -- and only where -- the platform calls for it.
+///
+/// This does not own the name: it holds a string_view. It is intended for
+/// passing names to APIs that mangle them immediately, and for arrays built
+/// from string literals. Holding one alongside a name with a shorter lifetime
+/// leaves a dangling view.
+class SymbolNameSpec {
+public:
+  constexpr SymbolNameSpec(std::string_view Name, SymbolNameKind Kind) noexcept
+      : Name(Name), Kind(Kind) {}
+
+  /// Returns a spec for a name that is already linker-level.
+  static constexpr SymbolNameSpec linker(std::string_view Name) noexcept {
+    return SymbolNameSpec(Name, SymbolNameKind::Linker);
+  }
+
+  /// Returns a spec for a C identifier, to be decorated by the platform.
+  static constexpr SymbolNameSpec c(std::string_view Name) noexcept {
+    return SymbolNameSpec(Name, SymbolNameKind::C);
+  }
+
+  constexpr std::string_view name() const noexcept { return Name; }
+  constexpr SymbolNameKind kind() const noexcept { return Kind; }
+
+private:
+  std::string_view Name;
+  SymbolNameKind Kind = SymbolNameKind::Linker;
+};
+
+/// Mangles NameSpec and passes the result to H, returning whatever H returns.
+///
+/// The mangled name is passed rather than returned so that the common case --
+/// a name short enough to build in a stack buffer -- needs no allocation. The
+/// string_view H receives is valid only for the duration of the call.
+template <typename HandlerT>
+decltype(auto) withMangledNameDo(HandlerT &&H,
+                                 const SymbolNameSpec &NameSpec) noexcept {
+#if defined(__APPLE__)
+  if (NameSpec.kind() == SymbolNameKind::Linker || NameSpec.name().empty())
+    return H(NameSpec.name());
+
+  constexpr size_t InlineStorageSize = 1024;
+  char InlineStorage[InlineStorageSize];
+  char *Buffer = InlineStorage;
+  std::unique_ptr<char[]> BigBuffer;
+  size_t NewNameSize = NameSpec.name().size() + 1;
+
+  // The buffer holds the underscore, the name, and a NUL, so it needs
+  // name().size() + 2 bytes.
+  if (NameSpec.name().size() + 2 > InlineStorageSize) {
+    BigBuffer = std::make_unique<char[]>(NewNameSize + 1);
+    Buffer = &BigBuffer[0];
+  }
+  Buffer[0] = '_';
+  memcpy(&Buffer[1], NameSpec.name().data(), NameSpec.name().size());
+  Buffer[NewNameSize] = '\0';
+
+  return H(std::string_view(Buffer, NewNameSize));
+#else
+  // No mangling.
+  return H(NameSpec.name());
+#endif
+}
+
+/// Returns the mangled form of NameSpec as a std::string.
+///
+/// Prefer withMangledNameDo where the name does not need to outlive the call.
+inline std::string mangledCopy(const SymbolNameSpec &NameSpec) noexcept {
+  return withMangledNameDo(
+      [](std::string_view MangledName) { return std::string(MangledName); },
+      NameSpec);
+}
+
+} // namespace orc_rt
+
+#endif // ORC_RT_SUPPORT_MANGLING_H
diff --git a/orc-rt/test/unit/CMakeLists.txt b/orc-rt/test/unit/CMakeLists.txt
index 9ac4fa440e72e..60671be1927c0 100644
--- a/orc-rt/test/unit/CMakeLists.txt
+++ b/orc-rt/test/unit/CMakeLists.txt
@@ -41,6 +41,7 @@ add_orc_rt_unittest(SupportTests
   support/LockedAccessTest.cpp
   support/LoggingTest.cpp
   support/MacroUtilsTest.cpp
+  support/ManglingTest.cpp
   support/MemoryFlagsTest.cpp
   support/ProxyTest.cpp
   support/RTTITest.cpp
diff --git a/orc-rt/test/unit/support/ManglingTest.cpp b/orc-rt/test/unit/support/ManglingTest.cpp
new file mode 100644
index 0000000000000..bacf62662ffe4
--- /dev/null
+++ b/orc-rt/test/unit/support/ManglingTest.cpp
@@ -0,0 +1,36 @@
+//===- ManglingTest.cpp ---------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Tests for orc-rt's Mangling.h APIs.
+//
+//===----------------------------------------------------------------------===//
+
+#include "orc-rt/support/Mangling.h"
+#include "gtest/gtest.h"
+
+using namespace orc_rt;
+
+TEST(ManglingTest, LinkerManglingIsIdentity) {
+  EXPECT_EQ(mangledCopy(SymbolNameSpec::linker("")), "");
+  EXPECT_EQ(mangledCopy(SymbolNameSpec::linker("foo")), "foo");
+}
+
+TEST(ManglingTest, EmptyManglesToEmpty) {
+  EXPECT_EQ(mangledCopy(SymbolNameSpec::c("")), "");
+}
+
+#if defined(__APPLE__)
+TEST(ManglingTest, DarwinShortNameMangling) {
+  EXPECT_EQ(mangledCopy(SymbolNameSpec::c("foo")), "_foo");
+}
+
+TEST(ManglingTest, DarwinLongNameMangling) {
+  std::string LongName(4096, 'x');
+  EXPECT_EQ(mangledCopy(SymbolNameSpec::c(LongName)), "_" + LongName);
+}
+#endif // defined(__APPLE__)



More information about the llvm-commits mailing list