[llvm] [ORC] Add Value support for capturing runtime JITed code results in clang-repl. (PR #145263)

via llvm-commits llvm-commits at lists.llvm.org
Mon Jun 23 00:07:56 PDT 2025


https://github.com/SahilPatidar updated https://github.com/llvm/llvm-project/pull/145263

>From a9d3041ebbefa1c23bba0048908aaeb09f68afa8 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 20 Jun 2025 12:29:17 +0530
Subject: [PATCH 1/9] [ORC] Add `Value` support for capturing runtime JITed
 code results in clang-repl

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h   | 223 ++++++++++++++++++
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp |  48 ++++
 2 files changed, 271 insertions(+)
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
 create mode 100644 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
new file mode 100644
index 0000000000000..a813e1549b486
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -0,0 +1,223 @@
+//===------------------------- Value.h --------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Value printing runtime raw value and type info.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_VALUE_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_VALUE_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorSymbolDef.h"
+
+namespace llvm {
+namespace orc {
+
+#define BUILTIN_TYPES                                                          \
+  X(bool, Bool)                                                                \
+  X(char, Char_S)                                                              \
+  X(signed char, SChar)                                                        \
+  X(unsigned char, Char_U)                                                     \
+  X(unsigned char, UChar)                                                      \
+  X(short, Short)                                                              \
+  X(unsigned short, UShort)                                                    \
+  X(int, Int)                                                                  \
+  X(unsigned int, UInt)                                                        \
+  X(long, Long)                                                                \
+  X(unsigned long, ULong)                                                      \
+  X(long long, LongLong)                                                       \
+  X(unsigned long long, ULongLong)                                             \
+  X(float, Float)                                                              \
+  X(double, Double)                                                            \
+  X(long double, LongDouble)
+
+class Value {
+public:
+  union Storage {
+#define X(type, name) type m_##name;
+    BUILTIN_TYPES
+#undef X
+    ExecutorSymbolDef m_Ptr;
+  };
+
+  enum Kind {
+#define X(type, name) K_##name,
+    BUILTIN_TYPES
+#undef X
+
+        K_Void,
+    K_PtrOrObj,
+    K_Unspecified
+  };
+
+  Value() = default;
+  explicit Value(ExecutorAddr OpaqueType);
+  Value(const Value &RHS);
+  Value(Value &&RHS);
+    Value() = default;
+  Value(ExecutorAddr OpaqueType);
+  Value(const Value &RHS);
+  Value(Value &&RHS) noexcept;
+  Value &operator=(const Value &RHS);
+  Value &operator=(Value &&RHS) noexcept;
+  ~Value();
+
+  template <typename T> static Value from(ExecutorAddr Ty, T result);
+
+  ExecutorAddr getOpaqueType() const { return OpaqueType; }
+
+#define X(type, name)                                                          \
+  void set##name(type Val) { Data.m_##name = Val; }                            \
+  type get##name() const { return Data.m_##name; }
+  BUILTIN_TYPES
+#undef X
+  void setPtrOrObj(void *Ptr) {
+    Data.m_Ptr = ExecutorSymbolDef::fromPtr(Ptr);
+  }
+  void setPtrOrObj(ExecutorSymbolDef Ptr) {
+    Data.m_Ptr = Ptr;
+  }
+  ExecutorSymbolDef getPtrOrObj() const {
+    assert(ValueKind == K_PtrOrObj);
+    return Data.m_Ptr;
+  }
+
+  Kind getKind() const { return ValueKind; }
+  void setKind(Kind K) { ValueKind = K; }
+
+  bool isValid() const { return ValueKind != K_Unspecified; }
+  bool isVoid() const { return ValueKind == K_Void; }
+  bool hasValue() const { return isValid() && !isVoid(); }
+  explicit operator bool() const { return isValid(); }
+
+private:
+  ExecutorAddr OpaqueType;
+  Storage Data;
+  Kind ValueKind = K_Unspecified;
+};
+
+namespace shared {
+
+struct SPSStorage {
+  union {
+#define X(type, name) type m_##name;
+    BUILTIN_TYPES
+#undef X
+    SPSExecutorSymbolDef m_Ptr;
+  };
+};
+
+using SPSValue = SPSTuple<SPSExecutorAddr, int32_t, SPSStorage>;
+
+template <> class SPSSerializationTraits<SPSValue, Value> {
+public:
+  static size_t size(const Value &V) {
+    size_t total = 0;
+
+    total += SPSArgList<SPSExecutorAddr>::size(V.getOpaqueType());
+
+    total += SPSArgList<int32_t>::size(static_cast<int32_t>(V.getKind()));
+
+    switch (V.getKind()) {
+#define X(type, name)                                                          \
+  case Value::K_##name:                                                        \
+    total += SPSArgList<type>::size(V.get##name());                            \
+    break;
+      BUILTIN_TYPES
+#undef X
+
+    case Value::K_PtrOrObj:
+      total += SPSArgList<SPSExecutorSymbolDef>::size(V.getPtrOrObj());
+      break;
+
+    case Value::K_Void:
+    case Value::K_Unspecified:
+      break;
+    }
+
+    return total;
+  }
+
+  static bool serialize(SPSOutputBuffer &OB, const Value &V) {
+    if (!SPSArgList<SPSExecutorAddr>::serialize(OB, V.getOpaqueType()))
+      return false;
+
+    if (!SPSArgList<int32_t>::serialize(OB, static_cast<int32_t>(V.getKind())))
+      return false;
+
+    switch (V.getKind()) {
+#define X(type, name)                                                          \
+  case Value::K_##name:                                                        \
+    if (!SPSArgList<type>::serialize(OB, V.get##name()))                       \
+      return false;                                                            \
+    break;
+      BUILTIN_TYPES
+#undef X
+
+    case Value::K_PtrOrObj:
+      if (!SPSArgList<SPSExecutorSymbolDef>::serialize(OB, V.getPtrOrObj()))
+        return false;
+      break;
+
+    case Value::K_Void:
+    case Value::K_Unspecified:
+      // No payload to serialize
+      break;
+    }
+
+    return true;
+  }
+
+  static bool deserialize(SPSInputBuffer &IB, Value &V) {
+    ExecutorAddr OpaqueTy;
+    if (!SPSArgList<SPSExecutorAddr>::deserialize(IB, OpaqueTy))
+      return false;
+
+    int32_t KindInt;
+    if (!SPSArgList<int32_t>::deserialize(IB, KindInt))
+      return false;
+
+    Value::Kind K = static_cast<Value::Kind>(KindInt);
+    V = Value(OpaqueTy);
+    V.setKind(K);
+
+    switch (K) {
+#define X(type, name)                                                          \
+  case Value::K_##name: {                                                      \
+    type T{};                                                                  \
+    if (!SPSArgList<type>::deserialize(IB, T))                                 \
+      return false;                                                            \
+    V.set##name(T);                                                            \
+    break;                                                                     \
+  }
+      BUILTIN_TYPES
+#undef X
+
+    case Value::K_PtrOrObj: {
+      ExecutorSymbolDef Sym;
+      if (!SPSArgList<SPSExecutorSymbolDef>::deserialize(IB, Sym))
+        return false;
+      V.setPtrOrObj(Sym);
+      break;
+    }
+
+    case Value::K_Void:
+    case Value::K_Unspecified:
+      // No payload to deserialize
+      break;
+    }
+
+    return true;
+  }
+};
+
+} // end namespace shared
+} // end namespace orc
+} // end namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_SHARED_VALUE_H
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
new file mode 100644
index 0000000000000..eeffca8a5234f
--- /dev/null
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -0,0 +1,48 @@
+//===------- SymbolStringPool.cpp - SymbolStringPool implementation -------===//
+//
+// 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/Value.h"
+
+namespace llvm::orc {
+
+template <typename T> Value Value::from(ExecutorAddr Ty, T result) {
+  Value Val(Ty);
+  Val.setValue<T>(result);
+  return Val;
+}
+
+template <typename T> void setValue(T Val) {
+  using DecayedT = std::decay_t<T>;
+  if constexpr (std::is_void_v<DecayedT>) {
+    ValueKind = K_Void;
+  }
+#define X(type, name)                                                          \
+  else if constexpr (std::is_same_v<DecayedT, type>) {                         \
+    set##name(Val);                                                            \
+    ValueKind = K_##name;                                                      \
+  }
+  BUILTIN_TYPES
+#undef X
+  else {
+    static_assert(std::is_trivially_copyable_v<T> || std::is_pointer_v<T>,
+                  "Unsupported type for setValue");
+
+    if constexpr (std::is_function_v<T>) {
+      setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
+    } else if constexpr (std::is_pointer_v<T> || std::is_array_v<T>) {
+      setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
+    } else if constexpr (std::is_class_v<T> || std::is_union_v<T>) {
+      setPtrOrObj(ExecutorSymbolDef::fromPtr<void *>(&Val));
+    } else {
+      static_assert(!std::is_same_v<T, T>, "Unsupported non-builtin type");
+    }
+    ValueKind = K_PtrOrObj;
+  }
+}
+
+} // end namespace llvm::orc
\ No newline at end of file

>From 9d2d1b92a2eda87d9b82adc6addf72961cfafe48 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Fri, 20 Jun 2025 12:44:25 +0530
Subject: [PATCH 2/9] Fix minor issue and restrict support to pointer types
 only

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h   | 13 +++++-------
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp | 20 +++++++++++--------
 2 files changed, 17 insertions(+), 16 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index a813e1549b486..ad4e071536890 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -6,7 +6,8 @@
 //
 //===----------------------------------------------------------------------===//
 //
-// Value printing runtime raw value and type info.
+// Value class for capturing raw runtime values along with their type
+// information.
 //
 //===----------------------------------------------------------------------===//
 
@@ -59,7 +60,7 @@ class Value {
   explicit Value(ExecutorAddr OpaqueType);
   Value(const Value &RHS);
   Value(Value &&RHS);
-    Value() = default;
+  Value() = default;
   Value(ExecutorAddr OpaqueType);
   Value(const Value &RHS);
   Value(Value &&RHS) noexcept;
@@ -76,12 +77,8 @@ class Value {
   type get##name() const { return Data.m_##name; }
   BUILTIN_TYPES
 #undef X
-  void setPtrOrObj(void *Ptr) {
-    Data.m_Ptr = ExecutorSymbolDef::fromPtr(Ptr);
-  }
-  void setPtrOrObj(ExecutorSymbolDef Ptr) {
-    Data.m_Ptr = Ptr;
-  }
+  void setPtrOrObj(void *Ptr) { Data.m_Ptr = ExecutorSymbolDef::fromPtr(Ptr); }
+  void setPtrOrObj(ExecutorSymbolDef Ptr) { Data.m_Ptr = Ptr; }
   ExecutorSymbolDef getPtrOrObj() const {
     assert(ValueKind == K_PtrOrObj);
     return Data.m_Ptr;
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
index eeffca8a5234f..0f39cecddc7e8 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -1,4 +1,4 @@
-//===------- SymbolStringPool.cpp - SymbolStringPool implementation -------===//
+//===---------=------- Value.cpp - Value implementation -------------------===//
 //
 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
 // See https://llvm.org/LICENSE.txt for license information.
@@ -29,15 +29,19 @@ template <typename T> void setValue(T Val) {
   BUILTIN_TYPES
 #undef X
   else {
-    static_assert(std::is_trivially_copyable_v<T> || std::is_pointer_v<T>,
+    // static_assert(std::is_trivially_copyable_v<T> || std::is_pointer_v<T>,
+    //               "Unsupported type for setValue");
+    static_assert(std::is_pointer_v<T>,
                   "Unsupported type for setValue");
 
-    if constexpr (std::is_function_v<T>) {
-      setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
-    } else if constexpr (std::is_pointer_v<T> || std::is_array_v<T>) {
-      setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
-    } else if constexpr (std::is_class_v<T> || std::is_union_v<T>) {
-      setPtrOrObj(ExecutorSymbolDef::fromPtr<void *>(&Val));
+    // if constexpr (std::is_function_v<T>) {
+    //   setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
+    // } else if constexpr (std::is_pointer_v<T> || std::is_array_v<T>) {
+    //   setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
+    // } else if constexpr (std::is_class_v<T> || std::is_union_v<T>) {
+      //   setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
+    if constexpr (std::is_pointer_v<T>) {
+        setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
     } else {
       static_assert(!std::is_same_v<T, T>, "Unsupported non-builtin type");
     }

>From b05011067a4c9f1a5fcafff74d92f4052f7686eb Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 21 Jun 2025 11:05:50 +0530
Subject: [PATCH 3/9] Minor clean up

---
 llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h | 4 ----
 1 file changed, 4 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index ad4e071536890..417ec2f881682 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -59,10 +59,6 @@ class Value {
   Value() = default;
   explicit Value(ExecutorAddr OpaqueType);
   Value(const Value &RHS);
-  Value(Value &&RHS);
-  Value() = default;
-  Value(ExecutorAddr OpaqueType);
-  Value(const Value &RHS);
   Value(Value &&RHS) noexcept;
   Value &operator=(const Value &RHS);
   Value &operator=(Value &&RHS) noexcept;

>From cce1705544e34cd9b43bef9a53a36343c0cc1e0b Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 21 Jun 2025 12:26:11 +0530
Subject: [PATCH 4/9] Continue cleanup and refactor

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h      |  3 ++-
 .../ExecutionEngine/Orc/Shared/CMakeLists.txt    |  1 +
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp    | 16 ++++++++--------
 3 files changed, 11 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index 417ec2f881682..bf581cda120d4 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -56,7 +56,7 @@ class Value {
     K_Unspecified
   };
 
-  Value() = default;
+  Value() = delete;
   explicit Value(ExecutorAddr OpaqueType);
   Value(const Value &RHS);
   Value(Value &&RHS) noexcept;
@@ -65,6 +65,7 @@ class Value {
   ~Value();
 
   template <typename T> static Value from(ExecutorAddr Ty, T result);
+  template <typename T> void setValue(T Val);
 
   ExecutorAddr getOpaqueType() const { return OpaqueType; }
 
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
index 792b0cc8251cc..87ae10bf5cf6e 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/CMakeLists.txt
@@ -6,6 +6,7 @@ add_llvm_component_library(LLVMOrcShared
   OrcRTBridge.cpp
   SimpleRemoteEPCUtils.cpp
   SymbolStringPool.cpp
+  Value.cpp
   ADDITIONAL_HEADER_DIRS
   ${LLVM_MAIN_INCLUDE_DIR}/llvm/ExecutionEngine/Orc
 
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
index 0f39cecddc7e8..d8c465ea24dbb 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -16,36 +16,36 @@ template <typename T> Value Value::from(ExecutorAddr Ty, T result) {
   return Val;
 }
 
-template <typename T> void setValue(T Val) {
+template <typename T> void Value::setValue(T Val) {
   using DecayedT = std::decay_t<T>;
   if constexpr (std::is_void_v<DecayedT>) {
-    ValueKind = K_Void;
+    ValueKind = Value::K_Void;
   }
 #define X(type, name)                                                          \
   else if constexpr (std::is_same_v<DecayedT, type>) {                         \
     set##name(Val);                                                            \
-    ValueKind = K_##name;                                                      \
+    ValueKind = Value::K_##name;                                               \
   }
+
   BUILTIN_TYPES
 #undef X
   else {
     // static_assert(std::is_trivially_copyable_v<T> || std::is_pointer_v<T>,
     //               "Unsupported type for setValue");
-    static_assert(std::is_pointer_v<T>,
-                  "Unsupported type for setValue");
+    static_assert(std::is_pointer_v<T>, "Unsupported type for setValue");
 
     // if constexpr (std::is_function_v<T>) {
     //   setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
     // } else if constexpr (std::is_pointer_v<T> || std::is_array_v<T>) {
     //   setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
     // } else if constexpr (std::is_class_v<T> || std::is_union_v<T>) {
-      //   setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
+    //   setPtrOrObj(ExecutorSymbolDef::fromPtr(&Val));
     if constexpr (std::is_pointer_v<T>) {
-        setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
+      setPtrOrObj(ExecutorSymbolDef::fromPtr(Val));
     } else {
       static_assert(!std::is_same_v<T, T>, "Unsupported non-builtin type");
     }
-    ValueKind = K_PtrOrObj;
+    ValueKind = Value::K_PtrOrObj;
   }
 }
 

>From 5c7b508110a1241312645aa1f510678ea9e04bf6 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 21 Jun 2025 16:37:09 +0530
Subject: [PATCH 5/9] Add handling for 'long' type

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h   | 10 +++---
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp | 33 ++++++++++++++++---
 2 files changed, 34 insertions(+), 9 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index bf581cda120d4..a8c7776d08d42 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -29,13 +29,13 @@ namespace orc {
   X(unsigned short, UShort)                                                    \
   X(int, Int)                                                                  \
   X(unsigned int, UInt)                                                        \
-  X(long, Long)                                                                \
-  X(unsigned long, ULong)                                                      \
   X(long long, LongLong)                                                       \
   X(unsigned long long, ULongLong)                                             \
-  X(float, Float)                                                              \
-  X(double, Double)                                                            \
-  X(long double, LongDouble)
+  // X(long, Long)                                                                \
+  // X(unsigned long, ULong)                                                      \
+  // X(float, Float)                                                              \
+  // X(double, Double)                                                            \
+  // X(long double, LongDouble)
 
 class Value {
 public:
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
index d8c465ea24dbb..c1916fcfb5e9f 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -16,10 +16,36 @@ template <typename T> Value Value::from(ExecutorAddr Ty, T result) {
   return Val;
 }
 
+template <typename T>
+struct LongEquivalentType {
+  static_assert(sizeof(T) == 0, "LongEquivalentType is only defined for long and unsigned long");
+};
+
+template <> struct LongEquivalentType<long> {
+  static_assert(sizeof(long) == 4 || sizeof(long) == 8,
+                "'long' must be either 4 or 8 bytes");
+
+  using type = std::conditional_t<sizeof(long) == 4, int32_t, int64_t>;
+};
+
+template <> struct LongEquivalentType<unsigned long> {
+  static_assert(sizeof(unsigned long) == 4 || sizeof(unsigned long) == 8,
+                "'unsigned long' must be either 4 or 8 bytes");
+
+  using type =
+      std::conditional_t<sizeof(unsigned long) == 4, uint32_t, uint64_t>;
+};
+
+template <typename T>
+using NormalizedIntType = typename LongEquivalentType<T>::type;
+
 template <typename T> void Value::setValue(T Val) {
   using DecayedT = std::decay_t<T>;
-  if constexpr (std::is_void_v<DecayedT>) {
-    ValueKind = Value::K_Void;
+
+  if constexpr (std::is_same_v<DecayedT, long> || std::is_same_v<DecayedT, unsigned long>) {
+    using CanonicalType = typename LongEquivalentType<DecayedT>::type;
+    setValue(static_cast<CanonicalType>(Val));
+    return;
   }
 #define X(type, name)                                                          \
   else if constexpr (std::is_same_v<DecayedT, type>) {                         \
@@ -28,10 +54,9 @@ template <typename T> void Value::setValue(T Val) {
   }
 
   BUILTIN_TYPES
+
 #undef X
   else {
-    // static_assert(std::is_trivially_copyable_v<T> || std::is_pointer_v<T>,
-    //               "Unsupported type for setValue");
     static_assert(std::is_pointer_v<T>, "Unsupported type for setValue");
 
     // if constexpr (std::is_function_v<T>) {

>From f6ba0187934c302c03714322a12d030cb2892fce Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 23 Jun 2025 10:15:56 +0530
Subject: [PATCH 6/9] refactor: move m_Ptr out of union to fix deleted default
 constructor error

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h   |  8 ++--
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp | 37 ++++++++++++++++---
 2 files changed, 37 insertions(+), 8 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index a8c7776d08d42..a316d473f75e1 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -39,10 +39,12 @@ namespace orc {
 
 class Value {
 public:
-  union Storage {
+  struct Storage {
+    union {
 #define X(type, name) type m_##name;
-    BUILTIN_TYPES
+      BUILTIN_TYPES
 #undef X
+    };
     ExecutorSymbolDef m_Ptr;
   };
 
@@ -56,7 +58,7 @@ class Value {
     K_Unspecified
   };
 
-  Value() = delete;
+  Value() = default;
   explicit Value(ExecutorAddr OpaqueType);
   Value(const Value &RHS);
   Value(Value &&RHS) noexcept;
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
index c1916fcfb5e9f..7854010a53917 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -10,15 +10,41 @@
 
 namespace llvm::orc {
 
+Value::Value(ExecutorAddr OpaqueType) : OpaqueType(OpaqueType) {}
+
+Value::Value(const Value &RHS)
+    : OpaqueType(RHS.OpaqueType), Data(RHS.Data), ValueKind(RHS.ValueKind) {}
+
+Value::Value(Value &&RHS) noexcept {
+  OpaqueType = std::exchange(RHS.OpaqueType, ExecutorAddr());
+  Data = RHS.Data;
+  ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
+}
+
+Value &Value::operator=(const Value &RHS) {
+  OpaqueType = RHS.OpaqueType;
+  Data = RHS.Data;
+  ValueKind = RHS.ValueKind;
+  return *this;
+}
+
+Value &Value::operator=(Value &&RHS) noexcept {
+  OpaqueType = std::exchange(RHS.OpaqueType, ExecutorAddr());
+  ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
+  Data = RHS.Data;
+  return *this;
+}
+
 template <typename T> Value Value::from(ExecutorAddr Ty, T result) {
-  Value Val(Ty);
+  Value Val(Ty, result);
   Val.setValue<T>(result);
   return Val;
 }
 
-template <typename T>
-struct LongEquivalentType {
-  static_assert(sizeof(T) == 0, "LongEquivalentType is only defined for long and unsigned long");
+template <typename T> struct LongEquivalentType {
+  static_assert(
+      sizeof(T) == 0,
+      "LongEquivalentType is only defined for long and unsigned long");
 };
 
 template <> struct LongEquivalentType<long> {
@@ -42,7 +68,8 @@ using NormalizedIntType = typename LongEquivalentType<T>::type;
 template <typename T> void Value::setValue(T Val) {
   using DecayedT = std::decay_t<T>;
 
-  if constexpr (std::is_same_v<DecayedT, long> || std::is_same_v<DecayedT, unsigned long>) {
+  if constexpr (std::is_same_v<DecayedT, long> ||
+                std::is_same_v<DecayedT, unsigned long>) {
     using CanonicalType = typename LongEquivalentType<DecayedT>::type;
     setValue(static_cast<CanonicalType>(Val));
     return;

>From 7b06a487bb401d8dd0eda03c85c870217bc2ff32 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 23 Jun 2025 10:30:08 +0530
Subject: [PATCH 7/9] Set destructor to default

---
 llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index a316d473f75e1..834d3744268fa 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -64,7 +64,7 @@ class Value {
   Value(Value &&RHS) noexcept;
   Value &operator=(const Value &RHS);
   Value &operator=(Value &&RHS) noexcept;
-  ~Value();
+  ~Value() = default;
 
   template <typename T> static Value from(ExecutorAddr Ty, T result);
   template <typename T> void setValue(T Val);

>From 27ad1e5642ccf14ca8b460a10a1e7a18b157a364 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 23 Jun 2025 11:00:08 +0530
Subject: [PATCH 8/9] Add ValueResultManager for result handling

---
 .../Orc/Shared/ValueResultManager.h           | 77 +++++++++++++++++++
 1 file changed, 77 insertions(+)
 create mode 100644 llvm/include/llvm/ExecutionEngine/Orc/Shared/ValueResultManager.h

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/ValueResultManager.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/ValueResultManager.h
new file mode 100644
index 0000000000000..582c4a54f690c
--- /dev/null
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/ValueResultManager.h
@@ -0,0 +1,77 @@
+//===--- ValueResultManager.h - ValueResultManager implementation -----*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Implements ValueResultManager for tracking runtime Values and their handlers.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_EXECUTIONENGINE_ORC_SHARED_VALUERESULTMANAGER_H
+#define LLVM_EXECUTIONENGINE_ORC_SHARED_VALUERESULTMANAGER_H
+
+#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
+#include "llvm/ExecutionEngine/Orc/Shared/Value.h"
+#include <atomic>
+#include <future>
+#include <mutex>
+#include <unordered_map>
+
+namespace llvm {
+namespace orc {
+
+class ValueResultManager {
+public:
+  using ValueID = uint64_t;
+  using ResultCallback = unique_function<void(Value)>;
+  using SendResultFn = unique_function<void(shared::WrapperFunctionResult)>;
+
+  ValueResultManager() = default;
+
+  ValueID createPendingResult(ResultCallback Callback) {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    ValueID NewID = NextID++;
+    Callbacks.emplace(NewID, std::move(Callback));
+    return NewID;
+  }
+
+  std::pair<ValueID, std::future<Value>> createPendingResult() {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    ValueID NewID = NextID++;
+    std::promise<Value> P;
+    auto F = P.get_future();
+    Promises.emplace(NewID, std::move(P));
+    return {NewID, std::move(F)};
+  }
+
+  void notify(SendResultFn SendResult, ValueID ID, Value V) {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    if (auto It = Callbacks.find(ID); It != Callbacks.end()) {
+      It->second(std::move(V));
+      Callbacks.erase(It);
+      return;
+    }
+
+    // if (auto It = Promises.find(ID); It != Promises.end()) {
+    //   It->second.set_value(std::move(V));
+    //   Promises.erase(It);
+    //   return;
+    // }
+  }
+
+private:
+  std::atomic<ValueID> NextID{1};
+
+  std::mutex Mutex;
+  std::unordered_map<ValueID, ResultCallback> Callbacks;
+  std::unordered_map<ValueID, std::promise<Value>> Promises;
+};
+
+} // namespace orc
+} // namespace llvm
+
+#endif // LLVM_EXECUTIONENGINE_ORC_VALUERESULTMANAGER_H

>From 33d794b89df2d61e80d158e228125b430b56f3d8 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 23 Jun 2025 12:37:16 +0530
Subject: [PATCH 9/9] Fix long/long long type normalization

---
 .../llvm/ExecutionEngine/Orc/Shared/Value.h   | 18 ++++-----
 llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp | 38 +++++++++++--------
 2 files changed, 32 insertions(+), 24 deletions(-)

diff --git a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
index 834d3744268fa..796dd74ef3aba 100644
--- a/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
+++ b/llvm/include/llvm/ExecutionEngine/Orc/Shared/Value.h
@@ -22,15 +22,15 @@ namespace orc {
 #define BUILTIN_TYPES                                                          \
   X(bool, Bool)                                                                \
   X(char, Char_S)                                                              \
-  X(signed char, SChar)                                                        \
-  X(unsigned char, Char_U)                                                     \
-  X(unsigned char, UChar)                                                      \
-  X(short, Short)                                                              \
-  X(unsigned short, UShort)                                                    \
-  X(int, Int)                                                                  \
-  X(unsigned int, UInt)                                                        \
-  X(long long, LongLong)                                                       \
-  X(unsigned long long, ULongLong)                                             \
+  X(int8_t, SChar)                                                             \
+  X(uint8_t, Char_U)                                                           \
+  X(uint8_t, UChar)                                                            \
+  X(int16_t, Short)                                                            \
+  X(uint16_t, UShort)                                                          \
+  X(int32_t, Int)                                                              \
+  X(uint32_t, UInt)                                                            \
+  X(int64_t, LongLong)                                                         \
+  X(uint64_t, ULongLong)                                                       \
   // X(long, Long)                                                                \
   // X(unsigned long, ULong)                                                      \
   // X(float, Float)                                                              \
diff --git a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
index 7854010a53917..cf75edd693433 100644
--- a/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
+++ b/llvm/lib/ExecutionEngine/Orc/Shared/Value.cpp
@@ -41,26 +41,32 @@ template <typename T> Value Value::from(ExecutorAddr Ty, T result) {
   return Val;
 }
 
+template <typename T, typename I32, typename I64> struct MapToFixedWidth {
+  static_assert(sizeof(T) == 4 || sizeof(T) == 8,
+                "Unsupported size for integer type (must be 4 or 8 bytes)");
+  using type = std::conditional_t<sizeof(T) == 4, I32, I64>;
+};
+
 template <typename T> struct LongEquivalentType {
   static_assert(
       sizeof(T) == 0,
-      "LongEquivalentType is only defined for long and unsigned long");
+      "LongEquivalentType is only defined for specific integral types");
 };
 
-template <> struct LongEquivalentType<long> {
-  static_assert(sizeof(long) == 4 || sizeof(long) == 8,
-                "'long' must be either 4 or 8 bytes");
+template <>
+struct LongEquivalentType<long> : MapToFixedWidth<long, int32_t, int64_t> {};
 
-  using type = std::conditional_t<sizeof(long) == 4, int32_t, int64_t>;
-};
+template <>
+struct LongEquivalentType<unsigned long>
+    : MapToFixedWidth<unsigned long, uint32_t, uint64_t> {};
 
-template <> struct LongEquivalentType<unsigned long> {
-  static_assert(sizeof(unsigned long) == 4 || sizeof(unsigned long) == 8,
-                "'unsigned long' must be either 4 or 8 bytes");
+template <>
+struct LongEquivalentType<long long>
+    : MapToFixedWidth<long long, int32_t, int64_t> {};
 
-  using type =
-      std::conditional_t<sizeof(unsigned long) == 4, uint32_t, uint64_t>;
-};
+template <>
+struct LongEquivalentType<unsigned long long>
+    : MapToFixedWidth<unsigned long long, uint32_t, uint64_t> {};
 
 template <typename T>
 using NormalizedIntType = typename LongEquivalentType<T>::type;
@@ -69,9 +75,11 @@ template <typename T> void Value::setValue(T Val) {
   using DecayedT = std::decay_t<T>;
 
   if constexpr (std::is_same_v<DecayedT, long> ||
-                std::is_same_v<DecayedT, unsigned long>) {
-    using CanonicalType = typename LongEquivalentType<DecayedT>::type;
-    setValue(static_cast<CanonicalType>(Val));
+                std::is_same_v<DecayedT, unsigned long> ||
+                std::is_same_v<DecayedT, long long> ||
+                std::is_same_v<DecayedT, unsigned long long>) {
+    using CanonicalType = NormalizedIntType<DecayedT>;
+    setValue<CanonicalType>(static_cast<CanonicalType>(Val));
     return;
   }
 #define X(type, name)                                                          \



More information about the llvm-commits mailing list