Skip to content

Commit 5111286

Browse files
committed
Reland "Reland [clang-repl] Introduce Value to capture expression results"
This reverts commit 094ab47. Reland with changing `ParseAndExecute` to `Parse` in `Interpreter::create`. This avoid creating JIT instance everytime even if we don't really need them. This should fixes failures like https://lab.llvm.org/buildbot/#/builders/38/builds/11955 The original reverted patch also causes GN bot fails on M1. (https://lab.llvm.org/buildbot/#/builders/38/builds/11955) However, we can't reproduce it so let's reland it and see what happens. See discussions here: https://reviews.llvm.org/rGd71a4e02277a64a9dece591cdf2b34f15c3b19a0
1 parent 09011c4 commit 5111286

File tree

12 files changed

+1290
-29
lines changed

12 files changed

+1290
-29
lines changed

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 31 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -14,14 +14,15 @@
1414
#ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H
1515
#define LLVM_CLANG_INTERPRETER_INTERPRETER_H
1616

17-
#include "clang/Interpreter/PartialTranslationUnit.h"
18-
17+
#include "clang/AST/Decl.h"
1918
#include "clang/AST/GlobalDecl.h"
19+
#include "clang/Interpreter/PartialTranslationUnit.h"
20+
#include "clang/Interpreter/Value.h"
2021

22+
#include "llvm/ADT/DenseMap.h"
2123
#include "llvm/ExecutionEngine/JITSymbol.h"
2224
#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
2325
#include "llvm/Support/Error.h"
24-
2526
#include <memory>
2627
#include <vector>
2728

@@ -54,24 +55,26 @@ class Interpreter {
5455
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err);
5556

5657
llvm::Error CreateExecutor();
58+
unsigned InitPTUSize = 0;
59+
60+
// This member holds the last result of the value printing. It's a class
61+
// member because we might want to access it after more inputs. If no value
62+
// printing happens, it's in an invalid state.
63+
Value LastValue;
5764

5865
public:
5966
~Interpreter();
6067
static llvm::Expected<std::unique_ptr<Interpreter>>
6168
create(std::unique_ptr<CompilerInstance> CI);
69+
const ASTContext &getASTContext() const;
70+
ASTContext &getASTContext();
6271
const CompilerInstance *getCompilerInstance() const;
6372
llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine();
6473

6574
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
6675
llvm::Error Execute(PartialTranslationUnit &T);
67-
llvm::Error ParseAndExecute(llvm::StringRef Code) {
68-
auto PTU = Parse(Code);
69-
if (!PTU)
70-
return PTU.takeError();
71-
if (PTU->TheModule)
72-
return Execute(*PTU);
73-
return llvm::Error::success();
74-
}
76+
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
77+
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
7578

7679
/// Undo N previous incremental inputs.
7780
llvm::Error Undo(unsigned N = 1);
@@ -92,6 +95,23 @@ class Interpreter {
9295
/// file.
9396
llvm::Expected<llvm::orc::ExecutorAddr>
9497
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
98+
99+
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray };
100+
101+
const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
102+
return ValuePrintingInfo;
103+
}
104+
105+
Expr *SynthesizeExpr(Expr *E);
106+
107+
private:
108+
size_t getEffectivePTUSize() const;
109+
110+
bool FindRuntimeInterface();
111+
112+
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
113+
114+
llvm::SmallVector<Expr *, 3> ValuePrintingInfo;
95115
};
96116
} // namespace clang
97117

Lines changed: 202 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,202 @@
1+
//===--- Value.h - Definition of interpreter value --------------*- C++ -*-===//
2+
//
3+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4+
// See https://llvm.org/LICENSE.txt for license information.
5+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6+
//
7+
//===----------------------------------------------------------------------===//
8+
//
9+
// Value is a lightweight struct that is used for carrying execution results in
10+
// clang-repl. It's a special runtime that acts like a messager between compiled
11+
// code and interpreted code. This makes it possible to exchange interesting
12+
// information between the compiled & interpreted world.
13+
//
14+
// A typical usage is like the below:
15+
//
16+
// Value V;
17+
// Interp.ParseAndExecute("int x = 42;");
18+
// Interp.ParseAndExecute("x", &V);
19+
// V.getType(); // <-- Yields a clang::QualType.
20+
// V.getInt(); // <-- Yields 42.
21+
//
22+
// The current design is still highly experimental and nobody should rely on the
23+
// API being stable because we're hopefully going to make significant changes to
24+
// it in the relatively near future. For example, Value also intends to be used
25+
// as an exchange token for JIT support enabling remote execution on the embed
26+
// devices where the JIT infrastructure cannot fit. To support that we will need
27+
// to split the memory storage in a different place and perhaps add a resource
28+
// header is similar to intrinsics headers which have stricter performance
29+
// constraints.
30+
//
31+
//===----------------------------------------------------------------------===//
32+
33+
#ifndef LLVM_CLANG_INTERPRETER_VALUE_H
34+
#define LLVM_CLANG_INTERPRETER_VALUE_H
35+
36+
#include "llvm/Support/Compiler.h"
37+
#include <cstdint>
38+
39+
// NOTE: Since the REPL itself could also include this runtime, extreme caution
40+
// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW
41+
// HEADERS, like <string>, <memory> and etc. (That pulls a large number of
42+
// tokens and will impact the runtime performance of the REPL)
43+
44+
namespace llvm {
45+
class raw_ostream;
46+
47+
} // namespace llvm
48+
49+
namespace clang {
50+
51+
class ASTContext;
52+
class Interpreter;
53+
class QualType;
54+
55+
#if __has_attribute(visibility) && \
56+
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
57+
(defined(__MINGW32__) && defined(__clang__)))
58+
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
59+
#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
60+
#else
61+
#define REPL_EXTERNAL_VISIBILITY
62+
#endif
63+
#else
64+
#if defined(_WIN32)
65+
#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
66+
#endif
67+
#endif
68+
69+
#define REPL_BUILTIN_TYPES \
70+
X(bool, Bool) \
71+
X(char, Char_S) \
72+
X(signed char, SChar) \
73+
X(unsigned char, UChar) \
74+
X(short, Short) \
75+
X(unsigned short, UShort) \
76+
X(int, Int) \
77+
X(unsigned int, UInt) \
78+
X(long, Long) \
79+
X(unsigned long, ULong) \
80+
X(long long, LongLong) \
81+
X(unsigned long long, ULongLong) \
82+
X(float, Float) \
83+
X(double, Double) \
84+
X(long double, LongDouble)
85+
86+
class REPL_EXTERNAL_VISIBILITY Value {
87+
union Storage {
88+
#define X(type, name) type m_##name;
89+
REPL_BUILTIN_TYPES
90+
#undef X
91+
void *m_Ptr;
92+
};
93+
94+
public:
95+
enum Kind {
96+
#define X(type, name) K_##name,
97+
REPL_BUILTIN_TYPES
98+
#undef X
99+
100+
K_Void,
101+
K_PtrOrObj,
102+
K_Unspecified
103+
};
104+
105+
Value() = default;
106+
Value(Interpreter *In, void *Ty);
107+
Value(const Value &RHS);
108+
Value(Value &&RHS) noexcept;
109+
Value &operator=(const Value &RHS);
110+
Value &operator=(Value &&RHS) noexcept;
111+
~Value();
112+
113+
void printType(llvm::raw_ostream &Out) const;
114+
void printData(llvm::raw_ostream &Out) const;
115+
void print(llvm::raw_ostream &Out) const;
116+
void dump() const;
117+
void clear();
118+
119+
ASTContext &getASTContext();
120+
const ASTContext &getASTContext() const;
121+
Interpreter &getInterpreter();
122+
const Interpreter &getInterpreter() const;
123+
QualType getType() const;
124+
125+
bool isValid() const { return ValueKind != K_Unspecified; }
126+
bool isVoid() const { return ValueKind == K_Void; }
127+
bool hasValue() const { return isValid() && !isVoid(); }
128+
bool isManuallyAlloc() const { return IsManuallyAlloc; }
129+
Kind getKind() const { return ValueKind; }
130+
void setKind(Kind K) { ValueKind = K; }
131+
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
132+
133+
void *getPtr() const;
134+
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
135+
136+
#define X(type, name) \
137+
void set##name(type Val) { Data.m_##name = Val; } \
138+
type get##name() const { return Data.m_##name; }
139+
REPL_BUILTIN_TYPES
140+
#undef X
141+
142+
/// \brief Get the value with cast.
143+
//
144+
/// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
145+
/// casting the value of builtins (except void), enums and pointers.
146+
/// Values referencing an object are treated as pointers to the object.
147+
template <typename T> T convertTo() const {
148+
return convertFwd<T>::cast(*this);
149+
}
150+
151+
protected:
152+
bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; }
153+
154+
/// \brief Get to the value with type checking casting the underlying
155+
/// stored value to T.
156+
template <typename T> T as() const {
157+
switch (ValueKind) {
158+
default:
159+
return T();
160+
#define X(type, name) \
161+
case Value::K_##name: \
162+
return (T)Data.m_##name;
163+
REPL_BUILTIN_TYPES
164+
#undef X
165+
}
166+
}
167+
168+
// Allow convertTo to be partially specialized.
169+
template <typename T> struct convertFwd {
170+
static T cast(const Value &V) {
171+
if (V.isPointerOrObjectType())
172+
return (T)(uintptr_t)V.as<void *>();
173+
if (!V.isValid() || V.isVoid()) {
174+
return T();
175+
}
176+
return V.as<T>();
177+
}
178+
};
179+
180+
template <typename T> struct convertFwd<T *> {
181+
static T *cast(const Value &V) {
182+
if (V.isPointerOrObjectType())
183+
return (T *)(uintptr_t)V.as<void *>();
184+
return nullptr;
185+
}
186+
};
187+
188+
Interpreter *Interp = nullptr;
189+
void *OpaqueType = nullptr;
190+
Storage Data;
191+
Kind ValueKind = K_Unspecified;
192+
bool IsManuallyAlloc = false;
193+
};
194+
195+
template <> inline void *Value::as() const {
196+
if (isPointerOrObjectType())
197+
return Data.m_Ptr;
198+
return (void *)as<uintptr_t>();
199+
}
200+
201+
} // namespace clang
202+
#endif

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,8 @@ add_clang_library(clangInterpreter
1414
IncrementalExecutor.cpp
1515
IncrementalParser.cpp
1616
Interpreter.cpp
17+
InterpreterUtils.cpp
18+
Value.cpp
1719

1820
DEPENDS
1921
intrinsics_gen

0 commit comments

Comments
 (0)