[llvm] [ORC] Start decoupling MangleAndInterner from DataLayout. (PR #214398)

Lang Hames via llvm-commits llvm-commits at lists.llvm.org
Wed Aug 5 21:25:28 PDT 2026


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

Previously MangleAndInterner held a DataLayout reference and mangled names via Mangler::getNameWithPrefix. Replace the stored DataLayout with an internal ManglingMode enum and mangle from that directly, so the class no longer needs to hold a DataLayout.

Add two DataLayout-free constructors: one taking an ExecutionSession and an optional ABI name (deriving the mode from the session's target triple), and one taking an explicit ManglingMode. The existing DataLayout constructor is retained, now deriving the mode from the DataLayout.

This lets MangleAndInterner be used where no DataLayout is available (e.g. from a bare ExecutionSession).

Adds MangleAndInternerTest covering the triple- and mode-based construction paths.

>From cee3a2346092987ee68461adec205bf8c2dc5280 Mon Sep 17 00:00:00 2001
From: Lang Hames <lhames at gmail.com>
Date: Tue, 4 Aug 2026 23:08:03 +1000
Subject: [PATCH] [ORC] Start decoupling MangleAndInterner from DataLayout.

Previously MangleAndInterner held a DataLayout reference and mangled names
via Mangler::getNameWithPrefix. Replace the stored DataLayout with an
internal ManglingMode enum and mangle from that directly, so the class no
longer needs to hold a DataLayout.

Add two DataLayout-free constructors: one taking an ExecutionSession and an
optional ABI name (deriving the mode from the session's target triple), and
one taking an explicit ManglingMode. The existing DataLayout constructor is
retained, now deriving the mode from the DataLayout.

This lets MangleAndInterner be used where no DataLayout is available (e.g.
from a bare ExecutionSession).

Adds MangleAndInternerTest covering the triple- and mode-based construction
paths.
---
 .../llvm/ExecutionEngine/Orc/Mangling.h       | 27 ++++--
 llvm/lib/ExecutionEngine/Orc/Mangling.cpp     | 85 +++++++++++++++---
 .../ExecutionEngine/Orc/CMakeLists.txt        |  1 +
 .../Orc/MangleAndInternerTest.cpp             | 87 +++++++++++++++++++
 4 files changed, 185 insertions(+), 15 deletions(-)
 create mode 100644 llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
index bfae136e52034..650ba1fe8cc54 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Mangling.h
@@ -18,20 +18,38 @@
 #include "llvm/IR/Module.h"
 #include "llvm/Support/Compiler.h"
 #include "llvm/Support/MemoryBuffer.h"
+#include "llvm/TargetParser/Triple.h"
 
-namespace llvm {
-namespace orc {
+namespace llvm::orc {
 
 /// Mangles symbol names then uniques them in the context of an
 /// ExecutionSession.
 class MangleAndInterner {
 public:
+  enum class ManglingMode {
+    None,
+    ELF,
+    MachO,
+    WinCOFF,
+    WinCOFFX86,
+    GOFF,
+    Mips,
+    XCOFF
+  };
+
+  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);
 
 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;
-  const DataLayout &DL;
+  ManglingMode Mode;
 };
 
 /// Maps IR global values to their linker symbol names / flags.
@@ -57,7 +75,6 @@ class IRSymbolMapper {
       SymbolNameToDefinitionMap *SymbolToDefinition = nullptr);
 };
 
-} // End namespace orc
-} // End namespace llvm
+} // namespace llvm::orc
 
 #endif // LLVM_EXECUTIONENGINE_ORC_MANGLING_H
diff --git a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
index fdff0e6af7aab..ec95b56ef0e95 100644
--- a/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Mangling.cpp
@@ -7,24 +7,90 @@
 //===----------------------------------------------------------------------===//
 
 #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 {
-namespace 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), DL(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) {
-  std::string MangledName;
-  {
-    raw_string_ostream MangledNameStream(MangledName);
-    Mangler::getNameWithPrefix(MangledNameStream, Name, DL);
+  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 ES.intern(MangledName);
+  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,
@@ -79,5 +145,4 @@ void IRSymbolMapper::add(ExecutionSession &ES, const ManglingOptions &MO,
   }
 }
 
-} // End namespace orc.
-} // End namespace llvm.
+} // namespace llvm::orc
diff --git a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
index 65c68eaaa6e7b..5b990f02f648b 100644
--- a/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
+++ b/llvm/unittests/ExecutionEngine/Orc/CMakeLists.txt
@@ -35,6 +35,7 @@ add_llvm_unittest(OrcJITTests
   LinkGraphLinkingLayerTest.cpp
   LookupAndRecordAddrsTest.cpp
   MachOBuilderTest.cpp
+  MangleAndInternerTest.cpp
   MachOPlatformTest.cpp
   MapperJITLinkMemoryManagerTest.cpp
   MemoryFlagsTest.cpp
diff --git a/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp b/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
new file mode 100644
index 0000000000000..a047985ad1d3b
--- /dev/null
+++ b/llvm/unittests/ExecutionEngine/Orc/MangleAndInternerTest.cpp
@@ -0,0 +1,87 @@
+//===---- 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());
+}



More information about the llvm-commits mailing list