[clang] [compiler-rt] [clang-repl] Reimplement value printing using MemoryAccess to support in-process and out-of-process (PR #156649)

via llvm-commits llvm-commits at lists.llvm.org
Mon Sep 8 04:29:46 PDT 2025


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

>From 4a56b9825b7dda9b729bd2a7790526a3a7d286c7 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Tue, 2 Sep 2025 12:08:29 +0530
Subject: [PATCH 1/4] [clang-repl] Reimplement value printing using
 MemoryAccess to support in-process and out-of-process

---
 clang/include/clang/Interpreter/Interpreter.h |  10 +-
 clang/include/clang/Interpreter/Value.h       |  50 ++-
 clang/lib/Interpreter/Interpreter.cpp         |  16 +-
 .../Interpreter/InterpreterValuePrinter.cpp   | 397 ++++++----------
 clang/lib/Interpreter/Value.cpp               | 422 +++++++++++++++++-
 compiler-rt/lib/orc/CMakeLists.txt            |   1 +
 compiler-rt/lib/orc/send_value.cpp            |  27 ++
 7 files changed, 654 insertions(+), 269 deletions(-)
 create mode 100644 compiler-rt/lib/orc/send_value.cpp

diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 8c124aadf1005..6dd480118caa1 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -104,10 +104,7 @@ class Interpreter {
 
   unsigned InitPTUSize = 0;
 
-  // This member holds the last result of the value printing. It's a class
-  // member because we might want to access it after more inputs. If no value
-  // printing happens, it's in an invalid state.
-  Value LastValue;
+  std::unique_ptr<ValueResultManager> ValMgr;
 
   /// Compiler instance performing the incremental compilation.
   std::unique_ptr<CompilerInstance> CI;
@@ -148,7 +145,7 @@ class Interpreter {
 
   llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
   llvm::Error Execute(PartialTranslationUnit &T);
-  llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
+  llvm::Error ParseAndExecute(llvm::StringRef Code);
 
   /// Undo N previous incremental inputs.
   llvm::Error Undo(unsigned N = 1);
@@ -187,9 +184,8 @@ class Interpreter {
   /// @{
 
   std::string ValueDataToString(const Value &V) const;
-  std::string ValueTypeToString(const Value &V) const;
 
-  llvm::Expected<Expr *> convertExprToValue(Expr *E);
+  llvm::Expected<Expr *> convertExprToValue(Expr *E, bool IsOOP = true);
 
   // When we deallocate clang::Value we need to run the destructor of the type.
   // This function forces emission of the needed dtor.
diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h
index b91301e6096eb..b2e72261874f1 100644
--- a/clang/include/clang/Interpreter/Value.h
+++ b/clang/include/clang/Interpreter/Value.h
@@ -32,8 +32,11 @@
 
 #ifndef LLVM_CLANG_INTERPRETER_VALUE_H
 #define LLVM_CLANG_INTERPRETER_VALUE_H
-
+#include "llvm/ADT/FunctionExtras.h"
 #include "llvm/Config/llvm-config.h" // for LLVM_BUILD_LLVM_DYLIB, LLVM_BUILD_SHARED_LIBS
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/MemoryAccess.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
 #include "llvm/Support/Compiler.h"
 #include <cassert>
 #include <cstdint>
@@ -107,7 +110,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
     REPL_BUILTIN_TYPES
 #undef X
 
-    K_Void,
+        K_Void,
     K_PtrOrObj,
     K_Unspecified
   };
@@ -206,5 +209,48 @@ template <> inline void *Value::as() const {
     return Data.m_Ptr;
   return (void *)as<uintptr_t>();
 }
+
+class ValueBuffer {
+public:
+  QualType Ty;
+  virtual ~ValueBuffer() = default;
+  virtual std::string toString() const = 0;
+  virtual bool isValid() const = 0;
+};
+
+class ValueResultManager {
+public:
+  using ValueId = uint64_t;
+  using SendResultFn = llvm::unique_function<void(llvm::Error)>;
+
+  explicit ValueResultManager(ASTContext &Ctx, llvm::orc::MemoryAccess &MemAcc);
+
+  static std::unique_ptr<ValueResultManager>
+  Create(llvm::orc::LLJIT &EE, ASTContext &Ctx, bool IsOutOfProcess = true);
+
+  ValueId registerPendingResult(QualType QT) {
+    ValueId NewID = NextID.fetch_add(1, std::memory_order_relaxed);
+    IdToType.insert({NewID, QT});
+    return NewID;
+  }
+
+  void resetAndDump();
+
+  void deliverResult(SendResultFn SendResult, ValueId ID,
+                     llvm::orc::ExecutorAddr VAddr);
+
+private:
+  std::atomic<ValueId> NextID{1};
+  void Initialize(llvm::orc::LLJIT &EE);
+
+  std::string ValueTypeToString(QualType QT) const;
+
+  mutable std::mutex Mutex;
+  ASTContext &Ctx;
+  llvm::orc::MemoryAccess &MemAcc;
+  std::unique_ptr<ValueBuffer> ValBuf = nullptr;
+  llvm::DenseMap<ValueId, clang::QualType> IdToType;
+};
+
 } // namespace clang
 #endif
diff --git a/clang/lib/Interpreter/Interpreter.cpp b/clang/lib/Interpreter/Interpreter.cpp
index 47995216fac46..7915d005dc8f3 100644
--- a/clang/lib/Interpreter/Interpreter.cpp
+++ b/clang/lib/Interpreter/Interpreter.cpp
@@ -301,6 +301,9 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
         return;
       }
   }
+
+  ValMgr = ValueResultManager::Create(IncrExecutor->GetExecutionEngine(),
+                                      getASTContext());
 }
 
 Interpreter::~Interpreter() {
@@ -323,6 +326,7 @@ Interpreter::~Interpreter() {
 // code them.
 const char *const Runtimes = R"(
     #define __CLANG_REPL__ 1
+
 #ifdef __cplusplus
     #define EXTERN_C extern "C"
     struct __clang_Interpreter_NewTag{} __ci_newtag;
@@ -343,6 +347,8 @@ const char *const Runtimes = R"(
       memcpy(Placement, Src, Size);
     }
 #endif // __cplusplus
+  EXTERN_C void __clang_Interpreter_SendResultValue(void *Ctx, unsigned long long, void*);
+  EXTERN_C void __orc_rt_SendResultValue(unsigned long long, void*);
   EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
   EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
 )";
@@ -571,7 +577,7 @@ llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
   return llvm::Error::success();
 }
 
-llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
+llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code) {
 
   auto PTU = Parse(Code);
   if (!PTU)
@@ -580,12 +586,8 @@ llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
     if (llvm::Error Err = Execute(*PTU))
       return Err;
 
-  if (LastValue.isValid()) {
-    if (!V) {
-      LastValue.dump();
-      LastValue.clear();
-    } else
-      *V = std::move(LastValue);
+  if (ValMgr) {
+    ValMgr->resetAndDump();
   }
   return llvm::Error::success();
 }
diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 54abfa6dbb9d8..83064e022323f 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -337,11 +337,10 @@ std::string Interpreter::ValueDataToString(const Value &V) const {
   return "@" + VoidPtrToString(V.getPtr());
 }
 
-std::string Interpreter::ValueTypeToString(const Value &V) const {
-  ASTContext &Ctx = const_cast<ASTContext &>(V.getASTContext());
-  QualType QT = V.getType();
+std::string ValueResultManager::ValueTypeToString(QualType QT) const {
+  ASTContext &AstCtx = const_cast<ASTContext &>(Ctx);
 
-  std::string QTStr = QualTypeToString(Ctx, QT);
+  std::string QTStr = QualTypeToString(AstCtx, QT);
 
   if (QT->isReferenceType())
     QTStr += " &";
@@ -349,6 +348,32 @@ std::string Interpreter::ValueTypeToString(const Value &V) const {
   return QTStr;
 }
 
+void ValueResultManager::resetAndDump() {
+  if (!ValBuf)
+    return;
+
+  QualType Ty = ValBuf->Ty;
+
+  std::unique_ptr<ValueBuffer> Val = nullptr;
+  ValBuf.swap(Val);
+
+  // Don't even try to print a void or an invalid type, it doesn't make sense.
+  if (Ty->isVoidType() || !Val->isValid())
+    return;
+
+  // We need to get all the results together then print it, since `printType` is
+  // much faster than `printData`.
+  std::string Str;
+  llvm::raw_string_ostream SS(Str);
+
+  SS << "(";
+  SS << ValueTypeToString(Ty);
+  SS << ") ";
+  SS << Val->toString();
+  SS << "\n";
+  llvm::outs() << Str;
+}
+
 llvm::Expected<llvm::orc::ExecutorAddr>
 Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) const {
   assert(CXXRD && "Cannot compile a destructor for a nullptr");
@@ -371,99 +396,126 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) const {
   return AddrOrErr;
 }
 
-enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
+class ExprConverter {
+  ASTContext &Ctx;
 
-class InterfaceKindVisitor
-    : public TypeVisitor<InterfaceKindVisitor, InterfaceKind> {
+public:
+  ExprConverter(ASTContext &Ctx) : Ctx(Ctx) {}
+
+  /// Create (&E) as a void*
+  ExprResult CreateAddressOfVoidPtrExpr(QualType Ty, Expr *ForCast) {
+    QualType VoidPtrTy = Ctx.getPointerType(Ctx.VoidTy);
+
+    // &E
+    Expr *AddrOf = UnaryOperator::Create(
+        Ctx, ForCast, UO_AddrOf, Ctx.getPointerType(Ty), VK_PRValue,
+        OK_Ordinary, SourceLocation(), false, FPOptionsOverride());
+
+    // static_cast<void*>(&E)
+    return CXXStaticCastExpr::Create(
+        Ctx, VoidPtrTy, VK_PRValue, CK_BitCast, AddrOf, nullptr,
+        Ctx.getTrivialTypeSourceInfo(VoidPtrTy), FPOptionsOverride(),
+        SourceLocation(), SourceLocation(), SourceRange());
+  }
 
-  Sema &S;
-  Expr *E;
-  llvm::SmallVectorImpl<Expr *> &Args;
+  /// Create a temporary VarDecl with initializer.
+  VarDecl *createTempVarDecl(QualType Ty, llvm::StringRef BaseName,
+                             Expr *Init) {
+    static unsigned Counter = 0;
+    IdentifierInfo &Id = Ctx.Idents.get((BaseName + Twine(++Counter)).str());
 
-public:
-  InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)
-      : S(S), E(E), Args(Args) {}
+    VarDecl *VD = VarDecl::Create(Ctx, Ctx.getTranslationUnitDecl(),
+                                  SourceLocation(), SourceLocation(), &Id, Ty,
+                                  Ctx.getTrivialTypeSourceInfo(Ty), SC_Auto);
 
-  InterfaceKind computeInterfaceKind(QualType Ty) {
-    return Visit(Ty.getTypePtr());
-  }
+    VD->setInit(Init);
+    VD->setInitStyle(VarDecl::CInit);
+    VD->markUsed(Ctx);
 
-  InterfaceKind VisitRecordType(const RecordType *Ty) {
-    return InterfaceKind::WithAlloc;
+    return VD;
   }
 
-  InterfaceKind VisitMemberPointerType(const MemberPointerType *Ty) {
-    return InterfaceKind::WithAlloc;
+  /// Wrap rvalues in a temporary so they become addressable.
+  Expr *CreateMaterializeTemporaryExpr(Expr *E) {
+    return new (Ctx) MaterializeTemporaryExpr(E->getType(), E,
+                                              /*BoundToLvalueReference=*/true);
   }
 
-  InterfaceKind VisitConstantArrayType(const ConstantArrayType *Ty) {
-    return InterfaceKind::CopyArray;
-  }
+  /// Generic helper: materialize if needed, then &expr as void*.
+  ExprResult makeAddressable(QualType QTy, Expr *E) {
+    if (E->isLValue() || E->isXValue())
+      return CreateAddressOfVoidPtrExpr(QTy, E);
 
-  InterfaceKind VisitFunctionType(const FunctionType *Ty) {
-    HandlePtrType(Ty);
-    return InterfaceKind::NoAlloc;
-  }
+    if (E->isPRValue())
+      return CreateAddressOfVoidPtrExpr(QTy, CreateMaterializeTemporaryExpr(E));
 
-  InterfaceKind VisitPointerType(const PointerType *Ty) {
-    HandlePtrType(Ty);
-    return InterfaceKind::NoAlloc;
+    return ExprError();
   }
 
-  InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
-    ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
-    assert(!AddrOfE.isInvalid() && "Can not create unary expression");
-    Args.push_back(AddrOfE.get());
-    return InterfaceKind::NoAlloc;
+  ExprResult handleBuiltinTypeExpr(const BuiltinType *, QualType QTy, Expr *E) {
+    return makeAddressable(QTy, E);
   }
+  ExprResult handlePointerTypeExpr(const PointerType *, QualType QTy, Expr *E) {
+    return makeAddressable(QTy, E);
+  }
+  ExprResult handleArrayTypeExpr(const ConstantArrayType *, QualType QTy,
+                                 Expr *E) {
+    return makeAddressable(QTy, E);
+  }
+};
 
-  InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
-    if (Ty->isNullPtrType())
-      Args.push_back(E);
-    else if (Ty->isFloatingType())
+class InterfaceKindVisitor : public TypeVisitor<InterfaceKindVisitor, bool> {
+  Sema &S;
+  Expr *E;
+  llvm::SmallVectorImpl<Expr *> &Args;
+  ExprConverter Converter;
+
+public:
+  InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)
+      : S(S), E(E), Args(Args), Converter(S.getASTContext()) {}
+
+  bool transformExpr(QualType Ty) { return Visit(Ty.getTypePtr()); }
+
+  bool VisitBuiltinType(const BuiltinType *Ty) {
+    if (Ty->isNullPtrType()) {
       Args.push_back(E);
-    else if (Ty->isIntegralOrEnumerationType())
-      HandleIntegralOrEnumType(Ty);
-    else if (Ty->isVoidType()) {
-      // Do we need to still run `E`?
+    } else if (Ty->isFloatingType() || Ty->isIntegralOrEnumerationType()) {
+      Args.push_back(
+          Converter.handleBuiltinTypeExpr(Ty, QualType(Ty, 0), E).get());
+    } else if (Ty->isVoidType()) {
+      return false;
     }
-
-    return InterfaceKind::NoAlloc;
+    return true;
   }
 
-  InterfaceKind VisitEnumType(const EnumType *Ty) {
-    HandleIntegralOrEnumType(Ty);
-    return InterfaceKind::NoAlloc;
+  bool VisitPointerType(const PointerType *Ty) {
+    Args.push_back(
+        Converter.handlePointerTypeExpr(Ty, QualType(Ty, 0), E).get());
+    return true;
   }
 
-private:
-  // Force cast these types to the uint that fits the register size. That way we
-  // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
-  void HandleIntegralOrEnumType(const Type *Ty) {
-    ASTContext &Ctx = S.getASTContext();
-    uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
-    QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);
-    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);
-    ExprResult CastedExpr =
-        S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
-    assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
-    Args.push_back(CastedExpr.get());
+  bool VisitConstantArrayType(const ConstantArrayType *Ty) {
+    Args.push_back(Converter.handleArrayTypeExpr(Ty, QualType(Ty, 0), E).get());
+    return true;
   }
 
-  void HandlePtrType(const Type *Ty) {
-    ASTContext &Ctx = S.getASTContext();
-    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
-    ExprResult CastedExpr =
-        S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
-    assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
-    Args.push_back(CastedExpr.get());
+  bool VisitReferenceType(const ReferenceType *Ty) {
+    ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
+    assert(!AddrOfE.isInvalid() && "Cannot create unary expression");
+    Args.push_back(AddrOfE.get());
+    return true;
   }
+
+  bool VisitRecordType(const RecordType *) { return true; }
+  bool VisitMemberPointerType(const MemberPointerType *) { return true; }
+  bool VisitFunctionType(const FunctionType *) { return true; }
+  bool VisitEnumType(const EnumType *) { return true; }
 };
 
-static constexpr llvm::StringRef VPName[] = {
-    "__clang_Interpreter_SetValueNoAlloc",
-    "__clang_Interpreter_SetValueWithAlloc",
-    "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
+enum RunTimeFnTag { OrcSendResult, ClangSendResult };
+
+static constexpr llvm::StringRef RunTimeFnTagName[] = {
+    "__orc_rt_SendResultValue", "__clang_Interpreter_SendResultValue"};
 
 // This synthesizes a call expression to a speciall
 // function that is responsible for generating the Value.
@@ -478,7 +530,7 @@ static constexpr llvm::StringRef VPName[] = {
 //   // 3. If x is a struct, but a rvalue.
 //   new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
 //   xQualType)) (x);
-llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {
+llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E, bool isOOP) {
   Sema &S = getCompilerInstance()->getSema();
   ASTContext &Ctx = S.getASTContext();
 
@@ -500,34 +552,22 @@ llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {
       Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
       return llvm::Error::success();
     };
-    if (llvm::Error Err =
-            LookupInterface(ValuePrintingInfo[NoAlloc], VPName[NoAlloc]))
-      return std::move(Err);
 
-    if (llvm::Error Err =
-            LookupInterface(ValuePrintingInfo[CopyArray], VPName[CopyArray]))
+    if (llvm::Error Err = LookupInterface(ValuePrintingInfo[OrcSendResult],
+                                          RunTimeFnTagName[OrcSendResult]))
       return std::move(Err);
 
-    if (llvm::Error Err =
-            LookupInterface(ValuePrintingInfo[WithAlloc], VPName[WithAlloc]))
+    if (llvm::Error Err = LookupInterface(ValuePrintingInfo[ClangSendResult],
+                                          RunTimeFnTagName[ClangSendResult]))
       return std::move(Err);
-
-    if (Ctx.getLangOpts().CPlusPlus) {
-      if (llvm::Error Err =
-              LookupInterface(ValuePrintingInfo[NewTag], VPName[NewTag]))
-        return std::move(Err);
-    }
   }
 
   llvm::SmallVector<Expr *, 4> AdjustedArgs;
-  // Create parameter `ThisInterp`.
-  AdjustedArgs.push_back(CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this));
-
-  // Create parameter `OutVal`.
-  AdjustedArgs.push_back(
-      CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue));
 
-  // Build `__clang_Interpreter_SetValue*` call.
+  if (!isOOP)
+    // Create parameter `ValMgr`.
+    AdjustedArgs.push_back(
+        CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)ValMgr.get()));
 
   // Get rid of ExprWithCleanups.
   if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
@@ -542,87 +582,22 @@ llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {
     Ty = Ctx.getLValueReferenceType(Ty);
   }
 
-  Expr *TypeArg =
-      CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)Ty.getAsOpaquePtr());
-  // The QualType parameter `OpaqueType`, represented as `void*`.
-  AdjustedArgs.push_back(TypeArg);
+  auto ID = ValMgr->registerPendingResult(Ty);
+
+  AdjustedArgs.push_back(IntegerLiteralExpr(Ctx, ID));
 
   // We push the last parameter based on the type of the Expr. Note we need
   // special care for rvalue struct.
   InterfaceKindVisitor V(S, E, AdjustedArgs);
-  Scope *Scope = nullptr;
   ExprResult SetValueE;
-  InterfaceKind Kind = V.computeInterfaceKind(DesugaredTy);
-  switch (Kind) {
-  case InterfaceKind::WithAlloc:
-    LLVM_FALLTHROUGH;
-  case InterfaceKind::CopyArray: {
-    // __clang_Interpreter_SetValueWithAlloc.
-    ExprResult AllocCall =
-        S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::WithAlloc],
-                        E->getBeginLoc(), AdjustedArgs, E->getEndLoc());
-    if (AllocCall.isInvalid())
-      return llvm::make_error<llvm::StringError>(
-          "Cannot call to " + VPName[WithAlloc],
-          llvm::inconvertibleErrorCode());
-
-    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
-
-    // Force CodeGen to emit destructor.
-    if (auto *RD = Ty->getAsCXXRecordDecl()) {
-      auto *Dtor = S.LookupDestructor(RD);
-      Dtor->addAttr(UsedAttr::CreateImplicit(Ctx));
-      getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
-          DeclGroupRef(Dtor));
-    }
+  Scope *Scope = nullptr;
+  if (!V.transformExpr(DesugaredTy))
+    return E;
 
-    // __clang_Interpreter_SetValueCopyArr.
-    if (Kind == InterfaceKind::CopyArray) {
-      const auto *CATy = cast<ConstantArrayType>(DesugaredTy.getTypePtr());
-      size_t ArrSize = Ctx.getConstantArrayElementCount(CATy);
-
-      if (!Ctx.getLangOpts().CPlusPlus)
-        ArrSize *= Ctx.getTypeSizeInChars(CATy->getBaseElementTypeUnsafe())
-                       .getQuantity();
-
-      Expr *ArrSizeExpr = IntegerLiteralExpr(Ctx, ArrSize);
-      Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
-      SetValueE =
-          S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::CopyArray],
-                          SourceLocation(), Args, SourceLocation());
-      if (SetValueE.isInvalid())
-        return llvm::make_error<llvm::StringError>(
-            "Cannot call to " + VPName[CopyArray],
-            llvm::inconvertibleErrorCode());
-      break;
-    }
-    Expr *Args[] = {AllocCall.get(), ValuePrintingInfo[InterfaceKind::NewTag]};
-    ExprResult CXXNewCall = S.BuildCXXNew(
-        E->getSourceRange(),
-        /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
-        /*PlacementRParen=*/SourceLocation(),
-        /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
-        E->getSourceRange(), E);
-
-    if (CXXNewCall.isInvalid())
-      return llvm::make_error<llvm::StringError>(
-          "Cannot build a call to placement new",
-          llvm::inconvertibleErrorCode());
-
-    SetValueE = S.ActOnFinishFullExpr(CXXNewCall.get(),
-                                      /*DiscardedValue=*/false);
-    break;
-  }
-  // __clang_Interpreter_SetValueNoAlloc.
-  case InterfaceKind::NoAlloc: {
-    SetValueE =
-        S.ActOnCallExpr(Scope, ValuePrintingInfo[InterfaceKind::NoAlloc],
-                        E->getBeginLoc(), AdjustedArgs, E->getEndLoc());
-    break;
-  }
-  default:
-    llvm_unreachable("Unhandled InterfaceKind");
-  }
+  RunTimeFnTag Tag =
+      isOOP ? RunTimeFnTag::OrcSendResult : RunTimeFnTag::ClangSendResult;
+  SetValueE = S.ActOnCallExpr(Scope, ValuePrintingInfo[Tag], E->getBeginLoc(),
+                              AdjustedArgs, E->getEndLoc());
 
   // It could fail, like printing an array type in C. (not supported)
   if (SetValueE.isInvalid())
@@ -630,97 +605,17 @@ llvm::Expected<Expr *> Interpreter::convertExprToValue(Expr *E) {
 
   return SetValueE.get();
 }
-
 } // namespace clang
 
 using namespace clang;
 
 // Temporary rvalue struct that need special care.
 extern "C" {
-REPL_EXTERNAL_VISIBILITY void *
-__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
-                                      void *OpaqueType) {
-  Value &VRef = *(Value *)OutVal;
-  VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
-  return VRef.getPtr();
-}
-
 REPL_EXTERNAL_VISIBILITY void
-__clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType,
-                                    ...) {
-  Value &VRef = *(Value *)OutVal;
-  Interpreter *I = static_cast<Interpreter *>(This);
-  VRef = Value(I, OpaqueType);
-  if (VRef.isVoid())
-    return;
-
-  va_list args;
-  va_start(args, /*last named param*/ OpaqueType);
-
-  QualType QT = VRef.getType();
-  if (VRef.getKind() == Value::K_PtrOrObj) {
-    VRef.setPtr(va_arg(args, void *));
-  } else {
-    if (const auto *ED = QT->getAsEnumDecl())
-      QT = ED->getIntegerType();
-    switch (QT->castAs<BuiltinType>()->getKind()) {
-    default:
-      llvm_unreachable("unknown type kind!");
-      break;
-      // Types shorter than int are resolved as int, else va_arg has UB.
-    case BuiltinType::Bool:
-      VRef.setBool(va_arg(args, int));
-      break;
-    case BuiltinType::Char_S:
-      VRef.setChar_S(va_arg(args, int));
-      break;
-    case BuiltinType::SChar:
-      VRef.setSChar(va_arg(args, int));
-      break;
-    case BuiltinType::Char_U:
-      VRef.setChar_U(va_arg(args, unsigned));
-      break;
-    case BuiltinType::UChar:
-      VRef.setUChar(va_arg(args, unsigned));
-      break;
-    case BuiltinType::Short:
-      VRef.setShort(va_arg(args, int));
-      break;
-    case BuiltinType::UShort:
-      VRef.setUShort(va_arg(args, unsigned));
-      break;
-    case BuiltinType::Int:
-      VRef.setInt(va_arg(args, int));
-      break;
-    case BuiltinType::UInt:
-      VRef.setUInt(va_arg(args, unsigned));
-      break;
-    case BuiltinType::Long:
-      VRef.setLong(va_arg(args, long));
-      break;
-    case BuiltinType::ULong:
-      VRef.setULong(va_arg(args, unsigned long));
-      break;
-    case BuiltinType::LongLong:
-      VRef.setLongLong(va_arg(args, long long));
-      break;
-    case BuiltinType::ULongLong:
-      VRef.setULongLong(va_arg(args, unsigned long long));
-      break;
-      // Types shorter than double are resolved as double, else va_arg has UB.
-    case BuiltinType::Float:
-      VRef.setFloat(va_arg(args, double));
-      break;
-    case BuiltinType::Double:
-      VRef.setDouble(va_arg(args, double));
-      break;
-    case BuiltinType::LongDouble:
-      VRef.setLongDouble(va_arg(args, long double));
-      break;
-      // See REPL_BUILTIN_TYPES.
-    }
-  }
-  va_end(args);
+__clang_Interpreter_SendResultValue(void *Ctx, uint64_t Id, void *Addr) {
+  static_cast<ValueResultManager *>(Ctx)->deliverResult(
+      [](llvm::Error Err) { llvm::cantFail(std::move(Err)); }, Id,
+      llvm::orc::ExecutorAddr::fromPtr(Addr));
 }
 }
 
diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp
index d4c9d51ffcb61..8136dee622c96 100644
--- a/clang/lib/Interpreter/Value.cpp
+++ b/clang/lib/Interpreter/Value.cpp
@@ -11,12 +11,27 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "clang/Interpreter/Value.h"
+#include "clang/AST/Type.h"
+
 #include "InterpreterUtils.h"
 #include "clang/AST/ASTContext.h"
 #include "clang/AST/Type.h"
 #include "clang/Interpreter/Interpreter.h"
+#include "clang/Interpreter/Value.h"
 #include "llvm/ADT/StringExtras.h"
+
+#include "llvm/ExecutionEngine/Orc/Core.h"
+#include "llvm/ExecutionEngine/Orc/ExecutorProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/SelfExecutorProcessControl.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+#include "llvm/ExecutionEngine/Orc/Shared/OrcRTBridge.h"
+
+#include <atomic>
+#include <future>
+#include <mutex>
+#include <unordered_map>
+
 #include <cassert>
 #include <utility>
 
@@ -251,7 +266,7 @@ const ASTContext &Value::getASTContext() const {
 void Value::dump() const { print(llvm::outs()); }
 
 void Value::printType(llvm::raw_ostream &Out) const {
-  Out << Interp->ValueTypeToString(*this);
+  // Out << Interp->ValueTypeToString(*this);
 }
 
 void Value::printData(llvm::raw_ostream &Out) const {
@@ -279,4 +294,407 @@ void Value::print(llvm::raw_ostream &Out) const {
   Out << Str;
 }
 
+class BuiltinValueBuffer : public ValueBuffer {
+public:
+  std::vector<char> raw;
+  BuiltinValueBuffer(QualType _Ty) { Ty = _Ty; }
+  template <typename T> T as() const {
+    T v{};
+    assert(raw.size() >= sizeof(T) && "Buffer too small for type!");
+    memcpy(&v, raw.data(), sizeof(T));
+    return v;
+  }
+  std::string toString() const override {
+    if (Ty->isCharType()) {
+      unsigned char c = as<unsigned char>();
+      switch (c) {
+      case '\n':
+        return "'\\n'";
+      case '\t':
+        return "'\\t'";
+      case '\r':
+        return "'\\r'";
+      case '\'':
+        return "'\\''";
+      case '\\':
+        return "'\\'";
+      default:
+        if (std::isprint(c))
+          return std::string("'") + static_cast<char>(c) + "'";
+        else {
+          return llvm::formatv("'\\x{0:02X}'", c).str();
+        }
+      }
+    }
+    if (auto *BT = Ty.getCanonicalType()->getAs<BuiltinType>()) {
+
+      auto formatFloating = [](auto Val, char Suffix = '\0') -> std::string {
+        std::string Out;
+        llvm::raw_string_ostream SS(Out);
+
+        if (std::isnan(Val) || std::isinf(Val)) {
+          SS << llvm::format("%g", Val);
+          return SS.str();
+        }
+        if (Val == static_cast<decltype(Val)>(static_cast<int64_t>(Val)))
+          SS << llvm::format("%.1f", Val);
+        else if (std::abs(Val) < 1e-4 || std::abs(Val) > 1e6 || Suffix == 'f')
+          SS << llvm::format("%#.6g", Val);
+        else if (Suffix == 'L')
+          SS << llvm::format("%#.12Lg", Val);
+        else
+          SS << llvm::format("%#.8g", Val);
+
+        if (Suffix != '\0')
+          SS << Suffix;
+        return SS.str();
+      };
+
+      std::string Str;
+      llvm::raw_string_ostream SS(Str);
+      switch (BT->getKind()) {
+      default:
+        return "{ error: unknown builtin type '" +
+               std::to_string(BT->getKind()) + " '}";
+      case clang::BuiltinType::Bool:
+        SS << ((as<bool>()) ? "true" : "false");
+        return Str;
+      case clang::BuiltinType::Short:
+        SS << as<short>();
+        return Str;
+      case clang::BuiltinType::UShort:
+        SS << as<unsigned short>();
+        return Str;
+      case clang::BuiltinType::Int:
+        SS << as<int>();
+        return Str;
+      case clang::BuiltinType::UInt:
+        SS << as<unsigned int>();
+        return Str;
+      case clang::BuiltinType::Long:
+        SS << as<long>();
+        return Str;
+      case clang::BuiltinType::ULong:
+        SS << as<unsigned long>();
+        return Str;
+      case clang::BuiltinType::LongLong:
+        SS << as<long long>();
+        return Str;
+      case clang::BuiltinType::ULongLong:
+        SS << as<unsigned long long>();
+        return Str;
+      case clang::BuiltinType::Float:
+        return formatFloating(as<float>(), /*suffix=*/'f');
+
+      case clang::BuiltinType::Double:
+        return formatFloating(as<double>());
+
+      case clang::BuiltinType::LongDouble:
+        return formatFloating(as<long double>(), /*suffix=*/'L');
+      }
+    }
+
+    return "";
+  }
+
+  bool isValid() const override { return !raw.empty(); }
+};
+
+class ArrayValueBuffer : public ValueBuffer {
+public:
+  std::vector<std::unique_ptr<ValueBuffer>> Elements;
+  ArrayValueBuffer(QualType EleTy) { Ty = EleTy; }
+  std::string toString() const override {
+    std::ostringstream OS;
+    OS << "{";
+    for (size_t i = 0; i < Elements.size(); ++i) {
+      OS << Elements[i]->toString();
+      if (i + 1 < Elements.size())
+        OS << ",";
+    }
+    OS << "}";
+    return OS.str();
+  }
+
+  bool isValid() const override { return !Elements.empty(); }
+};
+
+static std::string escapeString(const std::vector<char> &Raw) {
+  std::string Out;
+  for (char c : Raw) {
+    switch (c) {
+    case '\n':
+      Out += "\\n";
+      break;
+    case '\t':
+      Out += "\\t";
+      break;
+    case '\r':
+      Out += "\\r";
+      break;
+    case '\"':
+      Out += "\\\"";
+      break;
+    case '\\':
+      Out += "\\\\";
+      break;
+    default:
+      if (std::isprint(static_cast<unsigned char>(c)))
+        Out.push_back(c);
+      else {
+        char buf[5];
+        snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(c));
+        Out += buf;
+      }
+      break;
+    }
+  }
+  return Out;
+}
+
+class PointerValueBuffer : public ValueBuffer {
+public:
+  uint64_t Address = 0;
+  std::unique_ptr<ValueBuffer> Pointee; // optional, used only for char*
+
+  PointerValueBuffer(QualType _Ty, uint64_t Addr = 0) : Address(Addr) {
+    Ty = _Ty;
+  }
+
+  std::string toString() const override {
+    auto PtrTy = dyn_cast<PointerType>(Ty.getTypePtr());
+    if (!PtrTy)
+      return "";
+
+    auto PointeeTy = PtrTy->getPointeeType();
+
+    // char* -> print string literal
+    if (PointeeTy->isCharType() && Pointee) {
+      if (auto *BE = static_cast<BuiltinValueBuffer *>(Pointee.get()))
+        return "\"" + escapeString(BE->raw) + "\"";
+    }
+
+    if (Address == 0)
+      return "nullptr";
+
+    std::ostringstream OS;
+    OS << "0x" << std::hex << Address;
+    return OS.str();
+  }
+
+  bool isValid() const override { return Address != 0; }
+};
+
+class ReaderDispatcher {
+private:
+  ASTContext &Ctx;
+  llvm::orc::MemoryAccess &MA;
+
+public:
+  ReaderDispatcher(ASTContext &Ctx, llvm::orc::MemoryAccess &MA)
+      : Ctx(Ctx), MA(MA) {}
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  read(QualType QT, llvm::orc::ExecutorAddr Addr);
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  readBuiltin(QualType Ty, llvm::orc::ExecutorAddr Addr);
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  readPointer(QualType Ty, llvm::orc::ExecutorAddr Addr);
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  readArray(QualType Ty, llvm::orc::ExecutorAddr Addr);
+
+  // TODO: record, function, etc.
+};
+
+class TypeReadVisitor
+    : public TypeVisitor<TypeReadVisitor,
+                         llvm::Expected<std::unique_ptr<ValueBuffer>>> {
+  ReaderDispatcher &Dispatcher;
+  llvm::orc::ExecutorAddr Addr;
+
+public:
+  TypeReadVisitor(ReaderDispatcher &D, llvm::orc::ExecutorAddr A)
+      : Dispatcher(D), Addr(A) {}
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>> VisitType(const Type *T) {
+    return llvm::make_error<llvm::StringError>(
+        "Unsupported type in ReaderDispatcher", llvm::inconvertibleErrorCode());
+  }
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  VisitBuiltinType(const BuiltinType *BT) {
+    return Dispatcher.readBuiltin(QualType(BT, 0), Addr);
+  }
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  VisitPointerType(const PointerType *PT) {
+    return Dispatcher.readPointer(QualType(PT, 0), Addr);
+  }
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  VisitConstantArrayType(const ConstantArrayType *AT) {
+    return Dispatcher.readArray(QualType(AT, 0), Addr);
+  }
+
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  VisitRecordType(const RecordType *RT) {
+    return llvm::make_error<llvm::StringError>(
+        "RecordType reading not yet implemented",
+        llvm::inconvertibleErrorCode());
+  }
+};
+
+llvm::Expected<std::unique_ptr<ValueBuffer>>
+ReaderDispatcher::read(QualType QT, llvm::orc::ExecutorAddr Addr) {
+  TypeReadVisitor V(*this, Addr);
+  return V.Visit(QT.getTypePtr());
+}
+
+llvm::Expected<std::unique_ptr<ValueBuffer>>
+ReaderDispatcher::readBuiltin(QualType Ty, llvm::orc::ExecutorAddr Addr) {
+  auto Size = Ctx.getTypeSizeInChars(Ty).getQuantity();
+  auto ResOrErr = MA.readBuffers({llvm::orc::ExecutorAddrRange(Addr, Size)});
+  if (!ResOrErr)
+    return ResOrErr.takeError();
+
+  auto Buf = std::make_unique<BuiltinValueBuffer>(Ty);
+  const auto &Res = *ResOrErr;
+  std::vector<char> ElemBuf(Size);
+  std::memcpy(ElemBuf.data(), Res.back().data(), Size);
+  Buf->raw = std::move(ElemBuf);
+  return std::move(Buf);
+}
+
+llvm::Expected<std::unique_ptr<ValueBuffer>>
+ReaderDispatcher::readArray(QualType Ty, llvm::orc::ExecutorAddr Addr) {
+  const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(Ty);
+  if (!CAT)
+    return llvm::make_error<llvm::StringError>("Not a ConstantArrayType",
+                                               llvm::inconvertibleErrorCode());
+
+  QualType ElemTy = CAT->getElementType();
+  size_t ElemSize = Ctx.getTypeSizeInChars(ElemTy).getQuantity();
+
+  auto Buf = std::make_unique<ArrayValueBuffer>(Ty);
+
+  for (size_t i = 0; i < CAT->getZExtSize(); ++i) {
+    auto ElemAddr = Addr + i * ElemSize;
+    auto ElemBufOrErr = read(ElemTy, ElemAddr);
+    if (!ElemBufOrErr)
+      return ElemBufOrErr.takeError();
+    Buf->Elements.push_back(std::move(*ElemBufOrErr));
+  }
+
+  return std::move(Buf);
+}
+
+llvm::Expected<std::unique_ptr<ValueBuffer>>
+ReaderDispatcher::ReaderDispatcher::readPointer(QualType Ty,
+                                                llvm::orc::ExecutorAddr Addr) {
+  auto PtrTy = dyn_cast<PointerType>(Ty.getTypePtr());
+  if (!PtrTy)
+    return llvm::make_error<llvm::StringError>("Not a PointerType",
+                                               llvm::inconvertibleErrorCode());
+
+  auto AddrOrErr = MA.readUInt64s({Addr});
+  if (!AddrOrErr)
+    return AddrOrErr.takeError();
+
+  uint64_t PtrValAddr = AddrOrErr->back();
+  if (PtrValAddr == 0)
+    return std::make_unique<PointerValueBuffer>(Ty); // null pointer
+
+  llvm::orc::ExecutorAddr PointeeAddr(PtrValAddr);
+  auto PtrBuf = std::make_unique<PointerValueBuffer>(Ty, PtrValAddr);
+
+  QualType PointeeTy = PtrTy->getPointeeType();
+  if (PointeeTy->isCharType()) {
+    std::string S;
+    for (size_t i = 0; i < 1024; ++i) {
+      auto CRes = MA.readUInt8s({PointeeAddr + i});
+      if (!CRes)
+        return CRes.takeError();
+      char c = static_cast<char>(CRes->back());
+      if (c == '\0')
+        break;
+      S.push_back(c);
+    }
+    auto Buf = std::make_unique<BuiltinValueBuffer>(PointeeTy);
+    Buf->raw.assign(S.begin(), S.end());
+    PtrBuf->Pointee = std::move(Buf);
+  }
+  // else {
+  //   auto BufOrErr = read(PointeeTy, PointeeAddr);
+  //   if (!BufOrErr)
+  //     return BufOrErr.takeError();
+  //   PtrBuf->Pointee = std::move(*BufOrErr);
+  // }
+  return std::move(PtrBuf);
+}
+
+ValueResultManager::ValueResultManager(ASTContext &Ctx,
+                                       llvm::orc::MemoryAccess &MA)
+    : Ctx(Ctx), MemAcc(MA) {}
+
+std::unique_ptr<ValueResultManager>
+ValueResultManager::Create(llvm::orc::LLJIT &EE, ASTContext &Ctx, bool IsOop) {
+  auto &ES = EE.getExecutionSession();
+  auto &EPC = ES.getExecutorProcessControl();
+  auto VRMgr = std::make_unique<ValueResultManager>(Ctx, EPC.getMemoryAccess());
+  if (IsOop)
+    VRMgr->Initialize(EE);
+  return VRMgr;
+}
+
+void ValueResultManager::Initialize(llvm::orc::LLJIT &EE) {
+  auto &ES = EE.getExecutionSession();
+
+  llvm::orc::ExecutionSession::JITDispatchHandlerAssociationMap Handlers;
+  using OrcSendResultFn =
+      llvm::orc::shared::SPSError(uint64_t, llvm::orc::shared::SPSExecutorAddr);
+
+  const char *SendValFnTag = "___orc_rt_SendResultValue_tag";
+#ifndef __APPLE__
+  ++SendValFnTag;
+#endif
+  Handlers[ES.intern(SendValFnTag)] = ES.wrapAsyncWithSPS<OrcSendResultFn>(
+      this, &ValueResultManager::deliverResult);
+
+  llvm::cantFail(ES.registerJITDispatchHandlers(*EE.getPlatformJITDylib(),
+                                                std::move(Handlers)));
+}
+
+void ValueResultManager::deliverResult(SendResultFn SendResult, ValueId ID,
+                                       llvm::orc::ExecutorAddr Addr) {
+  QualType Ty;
+
+  {
+    std::lock_guard<std::mutex> Lock(Mutex);
+    auto It = IdToType.find(ID);
+    if (It == IdToType.end()) {
+      SendResult(llvm::make_error<llvm::StringError>(
+          "Unknown ValueId in deliverResult", llvm::inconvertibleErrorCode()));
+    }
+    Ty = It->second;
+    IdToType.erase(It);
+  }
+
+  ReaderDispatcher Runner(Ctx, MemAcc);
+  auto BufOrErr = Runner.read(Ty, Addr);
+
+  ValBuf.reset();
+  if (!BufOrErr) {
+    SendResult(BufOrErr.takeError());
+    return;
+  }
+
+  // Store the successfully read value buffer
+  ValBuf.swap(*BufOrErr);
+
+  SendResult(llvm::Error::success());
+  return;
+}
 } // namespace clang
diff --git a/compiler-rt/lib/orc/CMakeLists.txt b/compiler-rt/lib/orc/CMakeLists.txt
index b8d1b03b788c9..1addf77794a94 100644
--- a/compiler-rt/lib/orc/CMakeLists.txt
+++ b/compiler-rt/lib/orc/CMakeLists.txt
@@ -8,6 +8,7 @@ set(ORC_COMMON_SOURCES
   log_error_to_stderr.cpp
   run_program_wrapper.cpp
   resolve.cpp
+  send_value.cpp
   )
 
 # Common implementation headers will go here.
diff --git a/compiler-rt/lib/orc/send_value.cpp b/compiler-rt/lib/orc/send_value.cpp
new file mode 100644
index 0000000000000..31834439e6895
--- /dev/null
+++ b/compiler-rt/lib/orc/send_value.cpp
@@ -0,0 +1,27 @@
+//===- send_value.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
+//
+//===----------------------------------------------------------------------===//
+
+#include "common.h"
+#include "jit_dispatch.h"
+#include "wrapper_function_utils.h"
+#include "debug.h"
+
+using namespace orc_rt;
+
+ORC_RT_JIT_DISPATCH_TAG(__orc_rt_SendResultValue_tag)
+
+ORC_RT_INTERFACE void __orc_rt_SendResultValue(uint64_t ResultId, void *V) {
+  Error OptErr = Error::success();
+  if (auto Err = WrapperFunction<SPSError(uint64_t, SPSExecutorAddr)>::call(
+          JITDispatch(&__orc_rt_SendResultValue_tag), OptErr, ResultId,
+          ExecutorAddr::fromPtr(V))) {
+    cantFail(std::move(OptErr));
+    cantFail(std::move(Err));
+  }
+  consumeError(std::move(OptErr));
+}

>From ab676fd6002cd6a95cb3bbb45aa459dc80609d87 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Wed, 3 Sep 2025 17:11:34 +0530
Subject: [PATCH 2/4] Fix issues and add ValueToString helper

---
 clang/include/clang/Interpreter/Interpreter.h |   2 +-
 clang/include/clang/Interpreter/Value.h       |  64 +++-
 .../Interpreter/InterpreterValuePrinter.cpp   | 285 +++++++++++-------
 clang/lib/Interpreter/Value.cpp               | 218 ++------------
 4 files changed, 251 insertions(+), 318 deletions(-)

diff --git a/clang/include/clang/Interpreter/Interpreter.h b/clang/include/clang/Interpreter/Interpreter.h
index 6dd480118caa1..c1e7ca48c0961 100644
--- a/clang/include/clang/Interpreter/Interpreter.h
+++ b/clang/include/clang/Interpreter/Interpreter.h
@@ -185,7 +185,7 @@ class Interpreter {
 
   std::string ValueDataToString(const Value &V) const;
 
-  llvm::Expected<Expr *> convertExprToValue(Expr *E, bool IsOOP = true);
+  llvm::Expected<Expr *> convertExprToValue(Expr *E, bool IsOOP = false);
 
   // When we deallocate clang::Value we need to run the destructor of the type.
   // This function forces emission of the needed dtor.
diff --git a/clang/include/clang/Interpreter/Value.h b/clang/include/clang/Interpreter/Value.h
index b2e72261874f1..dda8c6bbf09aa 100644
--- a/clang/include/clang/Interpreter/Value.h
+++ b/clang/include/clang/Interpreter/Value.h
@@ -212,10 +212,68 @@ template <> inline void *Value::as() const {
 
 class ValueBuffer {
 public:
+  enum Kind { K_Builtin, K_Array, K_Pointer, K_Unknown };
   QualType Ty;
+  Kind K;
+  ValueBuffer(Kind K = K_Unknown) : K(K) {}
   virtual ~ValueBuffer() = default;
-  virtual std::string toString() const = 0;
-  virtual bool isValid() const = 0;
+  bool isUnknown() const { return K == K_Unknown; }
+  bool isBuiltin() const { return K == K_Builtin; }
+  bool isArray() const { return K == K_Array; }
+  bool isPointer() const { return K == K_Pointer; }
+  static bool classof(const ValueBuffer *) { return true; }
+};
+
+class BuiltinValueBuffer;
+class ArrayValueBuffer;
+class PointerValueBuffer;
+
+class BuiltinValueBuffer : public ValueBuffer {
+public:
+  std::vector<uint8_t> raw;
+  BuiltinValueBuffer(QualType _Ty) : ValueBuffer(K_Builtin) { Ty = _Ty; }
+  template <typename T> T as() const {
+    T v{};
+    // assert(raw.size() >= sizeof(T) && "Buffer too small for type!");
+    memcpy(&v, raw.data(), sizeof(T));
+    return v;
+  }
+  static bool classof(const ValueBuffer *B) { return B->isBuiltin(); }
+};
+
+class ArrayValueBuffer : public ValueBuffer {
+public:
+  std::vector<std::unique_ptr<ValueBuffer>> Elements;
+  ArrayValueBuffer(QualType EleTy) : ValueBuffer(K_Array) { Ty = EleTy; }
+
+  static bool classof(const ValueBuffer *B) { return B->isArray(); }
+};
+
+class PointerValueBuffer : public ValueBuffer {
+public:
+  uint64_t Address = 0;
+  std::unique_ptr<ValueBuffer> Pointee; // optional, used only for char*
+
+  PointerValueBuffer(QualType _Ty, uint64_t Addr = 0)
+      : ValueBuffer(K_Pointer), Address(Addr) {
+    Ty = _Ty;
+  }
+
+  static bool classof(const ValueBuffer *B) { return B->isPointer(); }
+};
+
+class ValueToString {
+private:
+  ASTContext &Ctx;
+
+public:
+  ValueToString(ASTContext &Ctx) : Ctx(Ctx) {}
+  std::string toString(const ValueBuffer *);
+
+private:
+  std::string BuiltinToString(const BuiltinValueBuffer &B);
+  std::string PointerToString(const PointerValueBuffer &P);
+  std::string ArrayToString(const ArrayValueBuffer &A);
 };
 
 class ValueResultManager {
@@ -226,7 +284,7 @@ class ValueResultManager {
   explicit ValueResultManager(ASTContext &Ctx, llvm::orc::MemoryAccess &MemAcc);
 
   static std::unique_ptr<ValueResultManager>
-  Create(llvm::orc::LLJIT &EE, ASTContext &Ctx, bool IsOutOfProcess = true);
+  Create(llvm::orc::LLJIT &EE, ASTContext &Ctx, bool IsOutOfProcess = false);
 
   ValueId registerPendingResult(QualType QT) {
     ValueId NewID = NextID.fetch_add(1, std::memory_order_relaxed);
diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 83064e022323f..7faae1ecaa9d9 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -96,12 +96,15 @@ static std::string QualTypeToString(ASTContext &Ctx, QualType QT) {
   return GetFullTypeName(Ctx, NonRefTy);
 }
 
-static std::string EnumToString(const Value &V) {
+static std::string EnumToString(ASTContext &Ctx, QualType QT, uint64_t Data) {
   std::string Str;
   llvm::raw_string_ostream SS(Str);
-  ASTContext &Ctx = const_cast<ASTContext &>(V.getASTContext());
 
-  uint64_t Data = V.convertTo<uint64_t>();
+  QualType DesugaredTy = QT.getDesugaredType(Ctx);
+  const EnumType *EnumTy = DesugaredTy.getNonReferenceType()->getAs<EnumType>();
+  assert(EnumTy && "Fail to cast to enum type");
+
+  EnumDecl *ED = EnumTy->getDecl();
   bool IsFirst = true;
   llvm::APSInt AP = Ctx.MakeIntValue(Data, V.getType());
 
@@ -120,12 +123,13 @@ static std::string EnumToString(const Value &V) {
   return Str;
 }
 
-static std::string FunctionToString(const Value &V, const void *Ptr) {
+static std::string FunctionToString(ASTContext &Ctx, QualType QT,
+                                    const void *Ptr) {
   std::string Str;
   llvm::raw_string_ostream SS(Str);
   SS << "Function @" << Ptr;
 
-  const DeclContext *PTU = V.getASTContext().getTranslationUnitDecl();
+  const DeclContext *PTU = Ctx.getTranslationUnitDecl();
   // Find the last top-level-stmt-decl. This is a forward iterator but the
   // partial translation unit should not be large.
   const TopLevelStmtDecl *TLSD = nullptr;
@@ -154,84 +158,85 @@ static std::string FunctionToString(const Value &V, const void *Ptr) {
   return Str;
 }
 
-static std::string VoidPtrToString(const void *Ptr) {
-  std::string Str;
-  llvm::raw_string_ostream SS(Str);
-  SS << Ptr;
-  return Str;
-}
-
-static std::string CharPtrToString(const char *Ptr) {
-  if (!Ptr)
-    return "0";
-
-  std::string Result = "\"";
-  Result += Ptr;
-  Result += '"';
-  return Result;
+static std::string escapeString(const std::vector<uint8_t> &Raw) {
+  std::string Out;
+  for (char c : Raw) {
+    switch (c) {
+    case '\n':
+      Out += "\\n";
+      break;
+    case '\t':
+      Out += "\\t";
+      break;
+    case '\r':
+      Out += "\\r";
+      break;
+    case '\"':
+      Out += "\\\"";
+      break;
+    case '\\':
+      Out += "\\\\";
+      break;
+    default:
+      if (std::isprint(static_cast<unsigned char>(c)))
+        Out.push_back(c);
+      else {
+        char buf[5];
+        snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(c));
+        Out += buf;
+      }
+      break;
+    }
+  }
+  return Out;
 }
 
 namespace clang {
 
-struct ValueRef : public Value {
-  ValueRef(const Interpreter *In, void *Ty) : Value(In, Ty) {
-    // Tell the base class to not try to deallocate if it manages the value.
-    IsManuallyAlloc = false;
-  }
-};
-
-std::string Interpreter::ValueDataToString(const Value &V) const {
-  Sema &S = getCompilerInstance()->getSema();
-  ASTContext &Ctx = S.getASTContext();
-
-  QualType QT = V.getType();
+std::string Interpreter::ValueDataToString(const Value &V) const { return ""; }
+
+std::string ValueToString::toString(const ValueBuffer *Buf) {
+  if (const BuiltinValueBuffer *B = llvm::dyn_cast<BuiltinValueBuffer>(Buf))
+    return BuiltinToString(*B);
+  else if (const ArrayValueBuffer *A = llvm::dyn_cast<ArrayValueBuffer>(Buf))
+    return ArrayToString(*A);
+  else if (const PointerValueBuffer *P =
+               llvm::dyn_cast<PointerValueBuffer>(Buf))
+    return PointerToString(*P);
+  return "";
+}
 
-  if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(QT)) {
-    QualType ElemTy = CAT->getElementType();
-    size_t ElemCount = Ctx.getConstantArrayElementCount(CAT);
-    const Type *BaseTy = CAT->getBaseElementTypeUnsafe();
-    size_t ElemSize = Ctx.getTypeSizeInChars(BaseTy).getQuantity();
+std::string ValueToString::BuiltinToString(const BuiltinValueBuffer &B) {
+  if (B.raw.empty())
+    return ""; // No data in buffer
 
-    // Treat null terminated char arrays as strings basically.
-    if (ElemTy->isCharType()) {
-      char last = *(char *)(((uintptr_t)V.getPtr()) + ElemCount * ElemSize - 1);
-      if (last == '\0')
-        return CharPtrToString((char *)V.getPtr());
-    }
+  QualType QT = B.Ty;
+  QualType DesugaredTy = QT.getDesugaredType(Ctx);
+  QualType NonRefTy = DesugaredTy.getNonReferenceType();
 
-    std::string Result = "{ ";
-    for (unsigned Idx = 0, N = CAT->getZExtSize(); Idx < N; ++Idx) {
-      ValueRef InnerV = ValueRef(this, ElemTy.getAsOpaquePtr());
-      if (ElemTy->isBuiltinType()) {
-        // Single dim arrays, advancing.
-        uintptr_t Offset = (uintptr_t)V.getPtr() + Idx * ElemSize;
-        InnerV.setRawBits((void *)Offset, ElemSize * 8);
-      } else {
-        // Multi dim arrays, position to the next dimension.
-        size_t Stride = ElemCount / N;
-        uintptr_t Offset = ((uintptr_t)V.getPtr()) + Idx * Stride * ElemSize;
-        InnerV.setPtr((void *)Offset);
+  if (NonRefTy->isCharType()) {
+    unsigned char c = B.as<unsigned char>();
+    switch (c) {
+    case '\n':
+      return "'\\n'";
+    case '\t':
+      return "'\\t'";
+    case '\r':
+      return "'\\r'";
+    case '\'':
+      return "'\\''";
+    case '\\':
+      return "'\\'";
+    case '\0':
+      return "";
+    default:
+      if (std::isprint(c))
+        return std::string("'") + static_cast<char>(c) + "'";
+      else {
+        return llvm::formatv("'\\x{0:02X}'", c).str();
       }
-
-      Result += ValueDataToString(InnerV);
-
-      // Skip the \0 if the char types
-      if (Idx < N - 1)
-        Result += ", ";
     }
-    Result += " }";
-    return Result;
   }
-
-  QualType DesugaredTy = QT.getDesugaredType(Ctx);
-  QualType NonRefTy = DesugaredTy.getNonReferenceType();
-
-  // FIXME: Add support for user defined printers.
-  // LookupResult R = LookupUserDefined(S, QT);
-  // if (!R.empty())
-  //   return CallUserSpecifiedPrinter(R, V);
-
-  // If it is a builtin type dispatch to the builtin overloads.
   if (auto *BT = DesugaredTy.getCanonicalType()->getAs<BuiltinType>()) {
 
     auto formatFloating = [](auto Val, char Suffix = '\0') -> std::string {
@@ -263,78 +268,117 @@ std::string Interpreter::ValueDataToString(const Value &V) const {
       return "{ error: unknown builtin type '" + std::to_string(BT->getKind()) +
              " '}";
     case clang::BuiltinType::Bool:
-      SS << ((V.getBool()) ? "true" : "false");
-      return Str;
-    case clang::BuiltinType::Char_S:
-      SS << '\'' << V.getChar_S() << '\'';
-      return Str;
-    case clang::BuiltinType::SChar:
-      SS << '\'' << V.getSChar() << '\'';
-      return Str;
-    case clang::BuiltinType::Char_U:
-      SS << '\'' << V.getChar_U() << '\'';
-      return Str;
-    case clang::BuiltinType::UChar:
-      SS << '\'' << V.getUChar() << '\'';
+      SS << ((B.as<bool>()) ? "true" : "false");
       return Str;
     case clang::BuiltinType::Short:
-      SS << V.getShort();
+      SS << B.as<short>();
       return Str;
     case clang::BuiltinType::UShort:
-      SS << V.getUShort();
+      SS << B.as<unsigned short>();
       return Str;
     case clang::BuiltinType::Int:
-      SS << V.getInt();
+      SS << B.as<int>();
       return Str;
     case clang::BuiltinType::UInt:
-      SS << V.getUInt();
+      SS << B.as<unsigned int>();
       return Str;
     case clang::BuiltinType::Long:
-      SS << V.getLong();
+      SS << B.as<long>();
       return Str;
     case clang::BuiltinType::ULong:
-      SS << V.getULong();
+      SS << B.as<unsigned long>();
       return Str;
     case clang::BuiltinType::LongLong:
-      SS << V.getLongLong();
+      SS << B.as<long long>();
       return Str;
     case clang::BuiltinType::ULongLong:
-      SS << V.getULongLong();
+      SS << B.as<unsigned long long>();
       return Str;
     case clang::BuiltinType::Float:
-      return formatFloating(V.getFloat(), /*suffix=*/'f');
+      return formatFloating(B.as<float>(), /*suffix=*/'f');
 
     case clang::BuiltinType::Double:
-      return formatFloating(V.getDouble());
+      return formatFloating(B.as<double>());
 
     case clang::BuiltinType::LongDouble:
-      return formatFloating(V.getLongDouble(), /*suffix=*/'L');
+      return formatFloating(B.as<long double>(), /*suffix=*/'L');
     }
   }
 
+  if (NonRefTy->isEnumeralType())
+    return EnumToString(Ctx, QT, B.as<uint64_t>());
+
+  return "";
+}
+
+std::string ValueToString::PointerToString(const PointerValueBuffer &P) {
+
+  QualType QT = P.Ty;
+  QualType DesugaredTy = QT.getDesugaredType(Ctx);
+  QualType NonRefTy = DesugaredTy.getNonReferenceType();
+
+  auto PtrTy = dyn_cast<PointerType>(QT.getTypePtr());
+  if (!PtrTy)
+    return "";
+
+  auto PointeeTy = PtrTy->getPointeeType();
+
+  // char* -> print string literal
+  if (PointeeTy->isCharType() && P.Pointee) {
+    if (auto *BE = static_cast<BuiltinValueBuffer *>(P.Pointee.get()))
+      return "\"" + escapeString(BE->raw) + "\"";
+  }
+
+  if (P.Address == 0)
+    return "nullptr";
+
   if ((NonRefTy->isPointerType() || NonRefTy->isMemberPointerType()) &&
       NonRefTy->getPointeeType()->isFunctionProtoType())
-    return FunctionToString(V, V.getPtr());
+    return FunctionToString(Ctx, QT, (void *)P.Address);
 
   if (NonRefTy->isFunctionType())
-    return FunctionToString(V, &V);
+    return FunctionToString(Ctx, QT, (void *)P.Address);
 
-  if (NonRefTy->isEnumeralType())
-    return EnumToString(V);
-
-  if (NonRefTy->isNullPtrType())
-    return "nullptr\n";
-
-  // FIXME: Add support for custom printers in C.
-  if (NonRefTy->isPointerType()) {
-    if (NonRefTy->getPointeeType()->isCharType())
-      return CharPtrToString((char *)V.getPtr());
+  std::ostringstream OS;
+  OS << "@0x" << std::hex << P.Address;
+  return OS.str();
+}
 
-    return VoidPtrToString(V.getPtr());
+std::string ValueToString::ArrayToString(const ArrayValueBuffer &A) {
+  if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(A.Ty)) {
+    QualType ElemTy = CAT->getElementType();
+    std::ostringstream OS;
+    // Treat null terminated char arrays as strings basically.
+    if (ElemTy->isCharType() && !A.Elements.empty()) {
+      if (const auto *B =
+              llvm::dyn_cast<BuiltinValueBuffer>(A.Elements.back().get())) {
+        char last = (char)B->raw.back();
+        if (last != '\0')
+          goto not_a_string;
+      }
+      OS << "\"";
+      for (size_t i = 0; i < A.Elements.size(); ++i) {
+        if (const auto *B =
+                llvm::dyn_cast<BuiltinValueBuffer>(A.Elements[i].get())) {
+          OS << static_cast<char>(B->raw.back());
+        }
+      }
+      OS << "\"";
+      return OS.str();
+    }
+  }
+not_a_string:
+  std::ostringstream OS;
+
+  OS << "{ ";
+  for (size_t i = 0; i < A.Elements.size(); ++i) {
+    OS << this->toString(A.Elements[i].get());
+    if (i + 1 < A.Elements.size())
+      OS << ", ";
   }
 
-  // Fall back to printing just the address of the unknown object.
-  return "@" + VoidPtrToString(V.getPtr());
+  OS << " }";
+  return OS.str();
 }
 
 std::string ValueResultManager::ValueTypeToString(QualType QT) const {
@@ -358,18 +402,18 @@ void ValueResultManager::resetAndDump() {
   ValBuf.swap(Val);
 
   // Don't even try to print a void or an invalid type, it doesn't make sense.
-  if (Ty->isVoidType() || !Val->isValid())
+  if (Ty->isVoidType() || (!Val || (Val && Val->isUnknown())))
     return;
 
   // We need to get all the results together then print it, since `printType` is
   // much faster than `printData`.
   std::string Str;
   llvm::raw_string_ostream SS(Str);
-
+  ValueToString ValToStr(Ctx);
   SS << "(";
   SS << ValueTypeToString(Ty);
   SS << ") ";
-  SS << Val->toString();
+  SS << ValToStr.toString(Val.get());
   SS << "\n";
   llvm::outs() << Str;
 }
@@ -435,7 +479,7 @@ class ExprConverter {
     return VD;
   }
 
-  /// Wrap rvalues in a temporary so they become addressable.
+  /// Wrap rvalues in a temporary (var) so they become addressable.
   Expr *CreateMaterializeTemporaryExpr(Expr *E) {
     return new (Ctx) MaterializeTemporaryExpr(E->getType(), E,
                                               /*BoundToLvalueReference=*/true);
@@ -462,6 +506,9 @@ class ExprConverter {
                                  Expr *E) {
     return makeAddressable(QTy, E);
   }
+  ExprResult handleEnumTypeExpr(const EnumType *, QualType QTy, Expr *E) {
+    return makeAddressable(QTy, E);
+  }
 };
 
 class InterfaceKindVisitor : public TypeVisitor<InterfaceKindVisitor, bool> {
@@ -506,10 +553,14 @@ class InterfaceKindVisitor : public TypeVisitor<InterfaceKindVisitor, bool> {
     return true;
   }
 
+  bool VisitEnumType(const EnumType *Ty) {
+    Args.push_back(Converter.handleEnumTypeExpr(Ty, QualType(Ty, 0), E).get());
+    return true;
+  }
+
   bool VisitRecordType(const RecordType *) { return true; }
   bool VisitMemberPointerType(const MemberPointerType *) { return true; }
   bool VisitFunctionType(const FunctionType *) { return true; }
-  bool VisitEnumType(const EnumType *) { return true; }
 };
 
 enum RunTimeFnTag { OrcSendResult, ClangSendResult };
diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp
index 8136dee622c96..3ac741c83c808 100644
--- a/clang/lib/Interpreter/Value.cpp
+++ b/clang/lib/Interpreter/Value.cpp
@@ -294,197 +294,6 @@ void Value::print(llvm::raw_ostream &Out) const {
   Out << Str;
 }
 
-class BuiltinValueBuffer : public ValueBuffer {
-public:
-  std::vector<char> raw;
-  BuiltinValueBuffer(QualType _Ty) { Ty = _Ty; }
-  template <typename T> T as() const {
-    T v{};
-    assert(raw.size() >= sizeof(T) && "Buffer too small for type!");
-    memcpy(&v, raw.data(), sizeof(T));
-    return v;
-  }
-  std::string toString() const override {
-    if (Ty->isCharType()) {
-      unsigned char c = as<unsigned char>();
-      switch (c) {
-      case '\n':
-        return "'\\n'";
-      case '\t':
-        return "'\\t'";
-      case '\r':
-        return "'\\r'";
-      case '\'':
-        return "'\\''";
-      case '\\':
-        return "'\\'";
-      default:
-        if (std::isprint(c))
-          return std::string("'") + static_cast<char>(c) + "'";
-        else {
-          return llvm::formatv("'\\x{0:02X}'", c).str();
-        }
-      }
-    }
-    if (auto *BT = Ty.getCanonicalType()->getAs<BuiltinType>()) {
-
-      auto formatFloating = [](auto Val, char Suffix = '\0') -> std::string {
-        std::string Out;
-        llvm::raw_string_ostream SS(Out);
-
-        if (std::isnan(Val) || std::isinf(Val)) {
-          SS << llvm::format("%g", Val);
-          return SS.str();
-        }
-        if (Val == static_cast<decltype(Val)>(static_cast<int64_t>(Val)))
-          SS << llvm::format("%.1f", Val);
-        else if (std::abs(Val) < 1e-4 || std::abs(Val) > 1e6 || Suffix == 'f')
-          SS << llvm::format("%#.6g", Val);
-        else if (Suffix == 'L')
-          SS << llvm::format("%#.12Lg", Val);
-        else
-          SS << llvm::format("%#.8g", Val);
-
-        if (Suffix != '\0')
-          SS << Suffix;
-        return SS.str();
-      };
-
-      std::string Str;
-      llvm::raw_string_ostream SS(Str);
-      switch (BT->getKind()) {
-      default:
-        return "{ error: unknown builtin type '" +
-               std::to_string(BT->getKind()) + " '}";
-      case clang::BuiltinType::Bool:
-        SS << ((as<bool>()) ? "true" : "false");
-        return Str;
-      case clang::BuiltinType::Short:
-        SS << as<short>();
-        return Str;
-      case clang::BuiltinType::UShort:
-        SS << as<unsigned short>();
-        return Str;
-      case clang::BuiltinType::Int:
-        SS << as<int>();
-        return Str;
-      case clang::BuiltinType::UInt:
-        SS << as<unsigned int>();
-        return Str;
-      case clang::BuiltinType::Long:
-        SS << as<long>();
-        return Str;
-      case clang::BuiltinType::ULong:
-        SS << as<unsigned long>();
-        return Str;
-      case clang::BuiltinType::LongLong:
-        SS << as<long long>();
-        return Str;
-      case clang::BuiltinType::ULongLong:
-        SS << as<unsigned long long>();
-        return Str;
-      case clang::BuiltinType::Float:
-        return formatFloating(as<float>(), /*suffix=*/'f');
-
-      case clang::BuiltinType::Double:
-        return formatFloating(as<double>());
-
-      case clang::BuiltinType::LongDouble:
-        return formatFloating(as<long double>(), /*suffix=*/'L');
-      }
-    }
-
-    return "";
-  }
-
-  bool isValid() const override { return !raw.empty(); }
-};
-
-class ArrayValueBuffer : public ValueBuffer {
-public:
-  std::vector<std::unique_ptr<ValueBuffer>> Elements;
-  ArrayValueBuffer(QualType EleTy) { Ty = EleTy; }
-  std::string toString() const override {
-    std::ostringstream OS;
-    OS << "{";
-    for (size_t i = 0; i < Elements.size(); ++i) {
-      OS << Elements[i]->toString();
-      if (i + 1 < Elements.size())
-        OS << ",";
-    }
-    OS << "}";
-    return OS.str();
-  }
-
-  bool isValid() const override { return !Elements.empty(); }
-};
-
-static std::string escapeString(const std::vector<char> &Raw) {
-  std::string Out;
-  for (char c : Raw) {
-    switch (c) {
-    case '\n':
-      Out += "\\n";
-      break;
-    case '\t':
-      Out += "\\t";
-      break;
-    case '\r':
-      Out += "\\r";
-      break;
-    case '\"':
-      Out += "\\\"";
-      break;
-    case '\\':
-      Out += "\\\\";
-      break;
-    default:
-      if (std::isprint(static_cast<unsigned char>(c)))
-        Out.push_back(c);
-      else {
-        char buf[5];
-        snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(c));
-        Out += buf;
-      }
-      break;
-    }
-  }
-  return Out;
-}
-
-class PointerValueBuffer : public ValueBuffer {
-public:
-  uint64_t Address = 0;
-  std::unique_ptr<ValueBuffer> Pointee; // optional, used only for char*
-
-  PointerValueBuffer(QualType _Ty, uint64_t Addr = 0) : Address(Addr) {
-    Ty = _Ty;
-  }
-
-  std::string toString() const override {
-    auto PtrTy = dyn_cast<PointerType>(Ty.getTypePtr());
-    if (!PtrTy)
-      return "";
-
-    auto PointeeTy = PtrTy->getPointeeType();
-
-    // char* -> print string literal
-    if (PointeeTy->isCharType() && Pointee) {
-      if (auto *BE = static_cast<BuiltinValueBuffer *>(Pointee.get()))
-        return "\"" + escapeString(BE->raw) + "\"";
-    }
-
-    if (Address == 0)
-      return "nullptr";
-
-    std::ostringstream OS;
-    OS << "0x" << std::hex << Address;
-    return OS.str();
-  }
-
-  bool isValid() const override { return Address != 0; }
-};
-
 class ReaderDispatcher {
 private:
   ASTContext &Ctx;
@@ -539,6 +348,11 @@ class TypeReadVisitor
     return Dispatcher.readArray(QualType(AT, 0), Addr);
   }
 
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  VisitEnumType(const EnumType *ET) {
+    return Dispatcher.readBuiltin(QualType(ET, 0), Addr);
+  }
+
   llvm::Expected<std::unique_ptr<ValueBuffer>>
   VisitRecordType(const RecordType *RT) {
     return llvm::make_error<llvm::StringError>(
@@ -562,7 +376,7 @@ ReaderDispatcher::readBuiltin(QualType Ty, llvm::orc::ExecutorAddr Addr) {
 
   auto Buf = std::make_unique<BuiltinValueBuffer>(Ty);
   const auto &Res = *ResOrErr;
-  std::vector<char> ElemBuf(Size);
+  std::vector<uint8_t> ElemBuf(Size);
   std::memcpy(ElemBuf.data(), Res.back().data(), Size);
   Buf->raw = std::move(ElemBuf);
   return std::move(Buf);
@@ -598,12 +412,20 @@ ReaderDispatcher::ReaderDispatcher::readPointer(QualType Ty,
   if (!PtrTy)
     return llvm::make_error<llvm::StringError>("Not a PointerType",
                                                llvm::inconvertibleErrorCode());
+  unsigned PtrWidth = Ctx.getTypeSizeInChars(Ty).getQuantity();
+  uint64_t PtrValAddr = 0;
+  if (PtrWidth == 32) {
+    auto AddrOrErr = MA.readUInt32s({Addr});
+    if (!AddrOrErr)
+      return AddrOrErr.takeError();
+    PtrValAddr = AddrOrErr->back();
+  } else {
+    auto AddrOrErr = MA.readUInt64s({Addr});
+    if (!AddrOrErr)
+      return AddrOrErr.takeError();
+    PtrValAddr = AddrOrErr->back();
+  }
 
-  auto AddrOrErr = MA.readUInt64s({Addr});
-  if (!AddrOrErr)
-    return AddrOrErr.takeError();
-
-  uint64_t PtrValAddr = AddrOrErr->back();
   if (PtrValAddr == 0)
     return std::make_unique<PointerValueBuffer>(Ty); // null pointer
 
@@ -624,6 +446,8 @@ ReaderDispatcher::ReaderDispatcher::readPointer(QualType Ty,
     }
     auto Buf = std::make_unique<BuiltinValueBuffer>(PointeeTy);
     Buf->raw.assign(S.begin(), S.end());
+    if (S.empty())
+      Buf->raw.push_back('\0'); // represent ""
     PtrBuf->Pointee = std::move(Buf);
   }
   // else {

>From e8ce46b065b240dbc4bf1da22b1d5c107778b027 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Sat, 6 Sep 2025 12:02:16 +0530
Subject: [PATCH 3/4] Rebased

---
 clang/lib/Interpreter/InterpreterValuePrinter.cpp | 9 ++-------
 1 file changed, 2 insertions(+), 7 deletions(-)

diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 7faae1ecaa9d9..492fbe36bc963 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -100,15 +100,10 @@ static std::string EnumToString(ASTContext &Ctx, QualType QT, uint64_t Data) {
   std::string Str;
   llvm::raw_string_ostream SS(Str);
 
-  QualType DesugaredTy = QT.getDesugaredType(Ctx);
-  const EnumType *EnumTy = DesugaredTy.getNonReferenceType()->getAs<EnumType>();
-  assert(EnumTy && "Fail to cast to enum type");
-
-  EnumDecl *ED = EnumTy->getDecl();
   bool IsFirst = true;
-  llvm::APSInt AP = Ctx.MakeIntValue(Data, V.getType());
+  llvm::APSInt AP = Ctx.MakeIntValue(Data, QT);
 
-  auto *ED = V.getType()->castAsEnumDecl();
+  auto *ED = QT->castAsEnumDecl();
   for (auto I = ED->enumerator_begin(), E = ED->enumerator_end(); I != E; ++I) {
     if (I->getInitVal() == AP) {
       if (!IsFirst)

>From a5d7d9e4d8d9cdabe878542fa83a53381d708d71 Mon Sep 17 00:00:00 2001
From: SahilPatidar <patidarsahil2001 at gmail.com>
Date: Mon, 8 Sep 2025 16:54:10 +0530
Subject: [PATCH 4/4] Fix some issues

---
 .../Interpreter/InterpreterValuePrinter.cpp   | 225 ++++++++++--------
 clang/lib/Interpreter/Value.cpp               |  53 +++--
 2 files changed, 158 insertions(+), 120 deletions(-)

diff --git a/clang/lib/Interpreter/InterpreterValuePrinter.cpp b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
index 492fbe36bc963..508ae0bf71d9f 100644
--- a/clang/lib/Interpreter/InterpreterValuePrinter.cpp
+++ b/clang/lib/Interpreter/InterpreterValuePrinter.cpp
@@ -136,7 +136,8 @@ static std::string FunctionToString(ASTContext &Ctx, QualType QT,
   // *OpaqueType, void *Val);
   const FunctionDecl *FD = nullptr;
   if (auto *InterfaceCall = llvm::dyn_cast<CallExpr>(TLSD->getStmt())) {
-    const auto *Arg = InterfaceCall->getArg(/*Val*/ 3);
+    const auto *Arg = InterfaceCall->getArg(InterfaceCall->getNumArgs() - 1);
+
     // Get rid of cast nodes.
     while (const CastExpr *CastE = llvm::dyn_cast<CastExpr>(Arg))
       Arg = CastE->getSubExpr();
@@ -156,32 +157,32 @@ static std::string FunctionToString(ASTContext &Ctx, QualType QT,
 static std::string escapeString(const std::vector<uint8_t> &Raw) {
   std::string Out;
   for (char c : Raw) {
-    switch (c) {
-    case '\n':
-      Out += "\\n";
-      break;
-    case '\t':
-      Out += "\\t";
-      break;
-    case '\r':
-      Out += "\\r";
-      break;
-    case '\"':
-      Out += "\\\"";
-      break;
-    case '\\':
-      Out += "\\\\";
-      break;
-    default:
-      if (std::isprint(static_cast<unsigned char>(c)))
-        Out.push_back(c);
-      else {
-        char buf[5];
-        snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(c));
-        Out += buf;
-      }
-      break;
+    // switch (c) {
+    // case '\n':
+    //   Out += "\\n";
+    //   break;
+    // case '\t':
+    //   Out += "\\t";
+    //   break;
+    // case '\r':
+    //   Out += "\\r";
+    //   break;
+    // case '\"':
+    //   Out += "\\\"";
+    //   break;
+    // case '\\':
+    //   Out += "\\\\";
+    //   break;
+    // default:
+    if (std::isprint(static_cast<unsigned char>(c)))
+      Out.push_back(c);
+    else {
+      char buf[5];
+      snprintf(buf, sizeof(buf), "\\x%02X", static_cast<unsigned char>(c));
+      Out += buf;
     }
+    // break;
+    // }
   }
   return Out;
 }
@@ -212,16 +213,16 @@ std::string ValueToString::BuiltinToString(const BuiltinValueBuffer &B) {
   if (NonRefTy->isCharType()) {
     unsigned char c = B.as<unsigned char>();
     switch (c) {
-    case '\n':
-      return "'\\n'";
-    case '\t':
-      return "'\\t'";
-    case '\r':
-      return "'\\r'";
-    case '\'':
-      return "'\\''";
-    case '\\':
-      return "'\\'";
+    // case '\n':
+    //   return "'\\n'";
+    // case '\t':
+    //   return "'\\t'";
+    // case '\r':
+    //   return "'\\r'";
+    // case '\'':
+    //   return "'\\''";
+    // case '\\':
+    //   return "'\\'";
     case '\0':
       return "";
     default:
@@ -312,16 +313,19 @@ std::string ValueToString::PointerToString(const PointerValueBuffer &P) {
   QualType DesugaredTy = QT.getDesugaredType(Ctx);
   QualType NonRefTy = DesugaredTy.getNonReferenceType();
 
-  auto PtrTy = dyn_cast<PointerType>(QT.getTypePtr());
-  if (!PtrTy)
-    return "";
+  if (auto PtrTy = dyn_cast<PointerType>(QT.getTypePtr())) {
+    if (!PtrTy)
+      return "";
+
+    auto PointeeTy = PtrTy->getPointeeType();
 
-  auto PointeeTy = PtrTy->getPointeeType();
+    // char* -> print string literal
+    if (PointeeTy->isCharType() && P.Pointee) {
+      if (auto *BE = static_cast<BuiltinValueBuffer *>(P.Pointee.get()))
+        return "\"" + escapeString(BE->raw) + "\"";
+    }
 
-  // char* -> print string literal
-  if (PointeeTy->isCharType() && P.Pointee) {
-    if (auto *BE = static_cast<BuiltinValueBuffer *>(P.Pointee.get()))
-      return "\"" + escapeString(BE->raw) + "\"";
+    return std::to_string(P.Address);
   }
 
   if (P.Address == 0)
@@ -334,6 +338,9 @@ std::string ValueToString::PointerToString(const PointerValueBuffer &P) {
   if (NonRefTy->isFunctionType())
     return FunctionToString(Ctx, QT, (void *)P.Address);
 
+  if (NonRefTy->isNullPtrType())
+    return "nullptr\n";
+
   std::ostringstream OS;
   OS << "@0x" << std::hex << P.Address;
   return OS.str();
@@ -342,24 +349,26 @@ std::string ValueToString::PointerToString(const PointerValueBuffer &P) {
 std::string ValueToString::ArrayToString(const ArrayValueBuffer &A) {
   if (const ConstantArrayType *CAT = Ctx.getAsConstantArrayType(A.Ty)) {
     QualType ElemTy = CAT->getElementType();
-    std::ostringstream OS;
     // Treat null terminated char arrays as strings basically.
     if (ElemTy->isCharType() && !A.Elements.empty()) {
       if (const auto *B =
               llvm::dyn_cast<BuiltinValueBuffer>(A.Elements.back().get())) {
-        char last = (char)B->raw.back();
+        char last = (char)B->raw.front();
         if (last != '\0')
           goto not_a_string;
       }
-      OS << "\"";
+      std::string Res;
+      Res += "\"";
       for (size_t i = 0; i < A.Elements.size(); ++i) {
         if (const auto *B =
                 llvm::dyn_cast<BuiltinValueBuffer>(A.Elements[i].get())) {
-          OS << static_cast<char>(B->raw.back());
+          char c = static_cast<char>(B->raw.back());
+          if (c != '\0')
+            Res += c;
         }
       }
-      OS << "\"";
-      return OS.str();
+      Res += "\"";
+      return Res;
     }
   }
 not_a_string:
@@ -436,73 +445,90 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) const {
 }
 
 class ExprConverter {
+  Sema &S;
   ASTContext &Ctx;
 
 public:
-  ExprConverter(ASTContext &Ctx) : Ctx(Ctx) {}
+  ExprConverter(Sema &S, ASTContext &Ctx) : S(S), Ctx(Ctx) {}
 
   /// Create (&E) as a void*
-  ExprResult CreateAddressOfVoidPtrExpr(QualType Ty, Expr *ForCast) {
+  ExprResult CreateAddressOfVoidPtrExpr(QualType Ty, Expr *ForCast,
+                                        bool takeAddr = false) {
     QualType VoidPtrTy = Ctx.getPointerType(Ctx.VoidTy);
 
     // &E
-    Expr *AddrOf = UnaryOperator::Create(
-        Ctx, ForCast, UO_AddrOf, Ctx.getPointerType(Ty), VK_PRValue,
-        OK_Ordinary, SourceLocation(), false, FPOptionsOverride());
+    Expr *AddrOf = ForCast;
+    if (takeAddr) {
+      AddrOf = UnaryOperator::Create(
+          Ctx, ForCast, UO_AddrOf, Ctx.getPointerType(Ty), VK_PRValue,
+          OK_Ordinary, SourceLocation(), false, FPOptionsOverride());
+    }
 
+    TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
+    ExprResult CastedExpr =
+        S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), AddrOf);
+    assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
+    return CastedExpr.get();
     // static_cast<void*>(&E)
-    return CXXStaticCastExpr::Create(
-        Ctx, VoidPtrTy, VK_PRValue, CK_BitCast, AddrOf, nullptr,
-        Ctx.getTrivialTypeSourceInfo(VoidPtrTy), FPOptionsOverride(),
-        SourceLocation(), SourceLocation(), SourceRange());
-  }
-
-  /// Create a temporary VarDecl with initializer.
-  VarDecl *createTempVarDecl(QualType Ty, llvm::StringRef BaseName,
-                             Expr *Init) {
-    static unsigned Counter = 0;
-    IdentifierInfo &Id = Ctx.Idents.get((BaseName + Twine(++Counter)).str());
-
-    VarDecl *VD = VarDecl::Create(Ctx, Ctx.getTranslationUnitDecl(),
-                                  SourceLocation(), SourceLocation(), &Id, Ty,
-                                  Ctx.getTrivialTypeSourceInfo(Ty), SC_Auto);
-
-    VD->setInit(Init);
-    VD->setInitStyle(VarDecl::CInit);
-    VD->markUsed(Ctx);
-
-    return VD;
+    // return CXXStaticCastExpr::Create(
+    //     Ctx, VoidPtrTy, VK_PRValue, CK_BitCast, AddrOf, nullptr,
+    //     Ctx.getTrivialTypeSourceInfo(VoidPtrTy), FPOptionsOverride(),
+    //     SourceLocation(), SourceLocation(), SourceRange());
   }
 
   /// Wrap rvalues in a temporary (var) so they become addressable.
   Expr *CreateMaterializeTemporaryExpr(Expr *E) {
-    return new (Ctx) MaterializeTemporaryExpr(E->getType(), E,
-                                              /*BoundToLvalueReference=*/true);
+    return S.CreateMaterializeTemporaryExpr(E->getType(), E,
+                                            /*BoundToLvalueReference=*/true);
   }
 
-  /// Generic helper: materialize if needed, then &expr as void*.
-  ExprResult makeAddressable(QualType QTy, Expr *E) {
+  ExprResult makeScalarAddressable(QualType Ty, Expr *E) {
     if (E->isLValue() || E->isXValue())
-      return CreateAddressOfVoidPtrExpr(QTy, E);
-
-    if (E->isPRValue())
-      return CreateAddressOfVoidPtrExpr(QTy, CreateMaterializeTemporaryExpr(E));
-
-    return ExprError();
+      return CreateAddressOfVoidPtrExpr(Ty, E, /*takeAddr=*/true);
+    return CreateAddressOfVoidPtrExpr(Ty, CreateMaterializeTemporaryExpr(E),
+                                      /*takeAddr=*/true);
   }
 
   ExprResult handleBuiltinTypeExpr(const BuiltinType *, QualType QTy, Expr *E) {
-    return makeAddressable(QTy, E);
+    return makeScalarAddressable(QTy, E);
   }
+
+  ExprResult handleEnumTypeExpr(const EnumType *, QualType QTy, Expr *E) {
+    return makeScalarAddressable(QTy, E);
+  }
+
   ExprResult handlePointerTypeExpr(const PointerType *, QualType QTy, Expr *E) {
-    return makeAddressable(QTy, E);
+    // Pointer expressions always evaluate to a pointer value.
+    // No need to take address or materialize.
+    return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/false);
   }
+
   ExprResult handleArrayTypeExpr(const ConstantArrayType *, QualType QTy,
                                  Expr *E) {
-    return makeAddressable(QTy, E);
+    if (isa<StringLiteral>(E)) {
+      if (Ctx.getLangOpts().CPlusPlus)
+        return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/true);
+      return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/false);
+    }
+
+    if (E->isLValue() || E->isXValue())
+      return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/true);
+    return CreateAddressOfVoidPtrExpr(QTy, E,
+                                      /*takeAddr=*/false);
   }
-  ExprResult handleEnumTypeExpr(const EnumType *, QualType QTy, Expr *E) {
-    return makeAddressable(QTy, E);
+
+  ExprResult handleFunctionTypeExpr(const FunctionType *, QualType QTy,
+                                    Expr *E) {
+    if (Ctx.getLangOpts().CPlusPlus)
+      return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/true);
+    return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/false);
+  }
+
+  ExprResult handleAnyObjectExpr(const Type *, QualType QTy, Expr *E) {
+    if (E->isLValue() || E->isXValue())
+      return CreateAddressOfVoidPtrExpr(QTy, E, /*takeAddr=*/true);
+    return CreateAddressOfVoidPtrExpr(QTy, CreateMaterializeTemporaryExpr(E),
+                                      /*takeAddr=*/true);
   }
 };
 
@@ -514,10 +540,15 @@ class InterfaceKindVisitor : public TypeVisitor<InterfaceKindVisitor, bool> {
 
 public:
   InterfaceKindVisitor(Sema &S, Expr *E, llvm::SmallVectorImpl<Expr *> &Args)
-      : S(S), E(E), Args(Args), Converter(S.getASTContext()) {}
+      : S(S), E(E), Args(Args), Converter(S, S.getASTContext()) {}
 
   bool transformExpr(QualType Ty) { return Visit(Ty.getTypePtr()); }
 
+  bool VisitType(const Type *T) {
+    Args.push_back(Converter.handleAnyObjectExpr(T, QualType(T, 0), E).get());
+    return true;
+  }
+
   bool VisitBuiltinType(const BuiltinType *Ty) {
     if (Ty->isNullPtrType()) {
       Args.push_back(E);
@@ -548,14 +579,16 @@ class InterfaceKindVisitor : public TypeVisitor<InterfaceKindVisitor, bool> {
     return true;
   }
 
+  bool VisitFunctionType(const FunctionType *Ty) {
+    Args.push_back(
+        Converter.handleFunctionTypeExpr(Ty, QualType(Ty, 0), E).get());
+    return true;
+  }
+
   bool VisitEnumType(const EnumType *Ty) {
     Args.push_back(Converter.handleEnumTypeExpr(Ty, QualType(Ty, 0), E).get());
     return true;
   }
-
-  bool VisitRecordType(const RecordType *) { return true; }
-  bool VisitMemberPointerType(const MemberPointerType *) { return true; }
-  bool VisitFunctionType(const FunctionType *) { return true; }
 };
 
 enum RunTimeFnTag { OrcSendResult, ClangSendResult };
diff --git a/clang/lib/Interpreter/Value.cpp b/clang/lib/Interpreter/Value.cpp
index 3ac741c83c808..f3c89b620b505 100644
--- a/clang/lib/Interpreter/Value.cpp
+++ b/clang/lib/Interpreter/Value.cpp
@@ -315,6 +315,9 @@ class ReaderDispatcher {
   llvm::Expected<std::unique_ptr<ValueBuffer>>
   readArray(QualType Ty, llvm::orc::ExecutorAddr Addr);
 
+  llvm::Expected<std::unique_ptr<ValueBuffer>>
+  readOtherObject(QualType Ty, llvm::orc::ExecutorAddr Addr);
+
   // TODO: record, function, etc.
 };
 
@@ -329,8 +332,7 @@ class TypeReadVisitor
       : Dispatcher(D), Addr(A) {}
 
   llvm::Expected<std::unique_ptr<ValueBuffer>> VisitType(const Type *T) {
-    return llvm::make_error<llvm::StringError>(
-        "Unsupported type in ReaderDispatcher", llvm::inconvertibleErrorCode());
+    return Dispatcher.readOtherObject(QualType(T, 0), Addr);
   }
 
   llvm::Expected<std::unique_ptr<ValueBuffer>>
@@ -352,13 +354,6 @@ class TypeReadVisitor
   VisitEnumType(const EnumType *ET) {
     return Dispatcher.readBuiltin(QualType(ET, 0), Addr);
   }
-
-  llvm::Expected<std::unique_ptr<ValueBuffer>>
-  VisitRecordType(const RecordType *RT) {
-    return llvm::make_error<llvm::StringError>(
-        "RecordType reading not yet implemented",
-        llvm::inconvertibleErrorCode());
-  }
 };
 
 llvm::Expected<std::unique_ptr<ValueBuffer>>
@@ -412,20 +407,20 @@ ReaderDispatcher::ReaderDispatcher::readPointer(QualType Ty,
   if (!PtrTy)
     return llvm::make_error<llvm::StringError>("Not a PointerType",
                                                llvm::inconvertibleErrorCode());
-  unsigned PtrWidth = Ctx.getTypeSizeInChars(Ty).getQuantity();
-  uint64_t PtrValAddr = 0;
-  if (PtrWidth == 32) {
-    auto AddrOrErr = MA.readUInt32s({Addr});
-    if (!AddrOrErr)
-      return AddrOrErr.takeError();
-    PtrValAddr = AddrOrErr->back();
-  } else {
-    auto AddrOrErr = MA.readUInt64s({Addr});
-    if (!AddrOrErr)
-      return AddrOrErr.takeError();
-    PtrValAddr = AddrOrErr->back();
-  }
-
+  // unsigned PtrWidth = Ctx.getTypeSizeInChars(Ty).getQuantity();
+  // uint64_t PtrValAddr = 0;
+  // if (PtrWidth == 32) {
+  //   auto AddrOrErr = MA.readUInt32s({Addr});
+  //   if (!AddrOrErr)
+  //     return AddrOrErr.takeError();
+  //   PtrValAddr = AddrOrErr->back();
+  // } else {
+  //   auto AddrOrErr = MA.readUInt64s({Addr});
+  //   if (!AddrOrErr)
+  //     return AddrOrErr.takeError();
+  //   PtrValAddr = AddrOrErr->back();
+  // }
+  uint64_t PtrValAddr = Addr.getValue();
   if (PtrValAddr == 0)
     return std::make_unique<PointerValueBuffer>(Ty); // null pointer
 
@@ -459,6 +454,16 @@ ReaderDispatcher::ReaderDispatcher::readPointer(QualType Ty,
   return std::move(PtrBuf);
 }
 
+llvm::Expected<std::unique_ptr<ValueBuffer>>
+ReaderDispatcher::readOtherObject(QualType Ty, llvm::orc::ExecutorAddr Addr) {
+  unsigned PtrWidth = Ctx.getTypeSizeInChars(Ty).getQuantity();
+  uint64_t PtrValAddr = Addr.getValue();
+  if (PtrValAddr == 0)
+    return std::make_unique<PointerValueBuffer>(Ty); // null pointer
+
+  return std::make_unique<PointerValueBuffer>(Ty, PtrValAddr);
+}
+
 ValueResultManager::ValueResultManager(ASTContext &Ctx,
                                        llvm::orc::MemoryAccess &MA)
     : Ctx(Ctx), MemAcc(MA) {}
@@ -502,7 +507,7 @@ void ValueResultManager::deliverResult(SendResultFn SendResult, ValueId ID,
       SendResult(llvm::make_error<llvm::StringError>(
           "Unknown ValueId in deliverResult", llvm::inconvertibleErrorCode()));
     }
-    Ty = It->second;
+    Ty = It->second.getCanonicalType();
     IdToType.erase(It);
   }
 



More information about the llvm-commits mailing list