[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