Skip to content

Commit d71a4e0

Browse files
committed
Reland [clang-repl] Introduce Value to capture expression results
This reverts commit 7158fd3. * Fixes endianness issue on big endian machines like PowerPC-bl * Disable tests on platforms that having trouble to support JIT Signed-off-by: Jun Zhang <[email protected]>
1 parent e21a90f commit d71a4e0

File tree

12 files changed

+1286
-29
lines changed

12 files changed

+1286
-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: 200 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,200 @@
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 <cstdint>
37+
// NOTE: Since the REPL itself could also include this runtime, extreme caution
38+
// should be taken when MAKING CHANGES to this file, especially when INCLUDE NEW
39+
// HEADERS, like <string>, <memory> and etc. (That pulls a large number of
40+
// tokens and will impact the runtime performance of the REPL)
41+
42+
namespace llvm {
43+
class raw_ostream;
44+
45+
} // namespace llvm
46+
47+
namespace clang {
48+
49+
class ASTContext;
50+
class Interpreter;
51+
class QualType;
52+
53+
#if __has_attribute(visibility) && \
54+
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
55+
(defined(__MINGW32__) && defined(__clang__)))
56+
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
57+
#define REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
58+
#else
59+
#define REPL_EXTERNAL_VISIBILITY
60+
#endif
61+
#else
62+
#if defined(_WIN32)
63+
#define REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
64+
#endif
65+
#endif
66+
67+
#define REPL_BUILTIN_TYPES \
68+
X(bool, Bool) \
69+
X(char, Char_S) \
70+
X(signed char, SChar) \
71+
X(unsigned char, UChar) \
72+
X(short, Short) \
73+
X(unsigned short, UShort) \
74+
X(int, Int) \
75+
X(unsigned int, UInt) \
76+
X(long, Long) \
77+
X(unsigned long, ULong) \
78+
X(long long, LongLong) \
79+
X(unsigned long long, ULongLong) \
80+
X(float, Float) \
81+
X(double, Double) \
82+
X(long double, LongDouble)
83+
84+
class REPL_EXTERNAL_VISIBILITY Value {
85+
union Storage {
86+
#define X(type, name) type m_##name;
87+
REPL_BUILTIN_TYPES
88+
#undef X
89+
void *m_Ptr;
90+
};
91+
92+
public:
93+
enum Kind {
94+
#define X(type, name) K_##name,
95+
REPL_BUILTIN_TYPES
96+
#undef X
97+
98+
K_Void,
99+
K_PtrOrObj,
100+
K_Unspecified
101+
};
102+
103+
Value() = default;
104+
Value(Interpreter *In, void *Ty);
105+
Value(const Value &RHS);
106+
Value(Value &&RHS) noexcept;
107+
Value &operator=(const Value &RHS);
108+
Value &operator=(Value &&RHS) noexcept;
109+
~Value();
110+
111+
void printType(llvm::raw_ostream &Out) const;
112+
void printData(llvm::raw_ostream &Out) const;
113+
void print(llvm::raw_ostream &Out) const;
114+
void dump() const;
115+
void clear();
116+
117+
ASTContext &getASTContext();
118+
const ASTContext &getASTContext() const;
119+
Interpreter &getInterpreter();
120+
const Interpreter &getInterpreter() const;
121+
QualType getType() const;
122+
123+
bool isValid() const { return ValueKind != K_Unspecified; }
124+
bool isVoid() const { return ValueKind == K_Void; }
125+
bool hasValue() const { return isValid() && !isVoid(); }
126+
bool isManuallyAlloc() const { return IsManuallyAlloc; }
127+
Kind getKind() const { return ValueKind; }
128+
void setKind(Kind K) { ValueKind = K; }
129+
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
130+
131+
void *getPtr() const;
132+
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
133+
134+
#define X(type, name) \
135+
void set##name(type Val) { Data.m_##name = Val; } \
136+
type get##name() const { return Data.m_##name; }
137+
REPL_BUILTIN_TYPES
138+
#undef X
139+
140+
/// \brief Get the value with cast.
141+
//
142+
/// Get the value cast to T. This is similar to reinterpret_cast<T>(value),
143+
/// casting the value of builtins (except void), enums and pointers.
144+
/// Values referencing an object are treated as pointers to the object.
145+
template <typename T> T convertTo() const {
146+
return convertFwd<T>::cast(*this);
147+
}
148+
149+
protected:
150+
bool isPointerOrObjectType() const { return ValueKind == K_PtrOrObj; }
151+
152+
/// \brief Get to the value with type checking casting the underlying
153+
/// stored value to T.
154+
template <typename T> T as() const {
155+
switch (ValueKind) {
156+
default:
157+
return T();
158+
#define X(type, name) \
159+
case Value::K_##name: \
160+
return (T)Data.m_##name;
161+
REPL_BUILTIN_TYPES
162+
#undef X
163+
}
164+
}
165+
166+
// Allow convertTo to be partially specialized.
167+
template <typename T> struct convertFwd {
168+
static T cast(const Value &V) {
169+
if (V.isPointerOrObjectType())
170+
return (T)(uintptr_t)V.as<void *>();
171+
if (!V.isValid() || V.isVoid()) {
172+
return T();
173+
}
174+
return V.as<T>();
175+
}
176+
};
177+
178+
template <typename T> struct convertFwd<T *> {
179+
static T *cast(const Value &V) {
180+
if (V.isPointerOrObjectType())
181+
return (T *)(uintptr_t)V.as<void *>();
182+
return nullptr;
183+
}
184+
};
185+
186+
Interpreter *Interp = nullptr;
187+
void *OpaqueType = nullptr;
188+
Storage Data;
189+
Kind ValueKind = K_Unspecified;
190+
bool IsManuallyAlloc = false;
191+
};
192+
193+
template <> inline void *Value::as() const {
194+
if (isPointerOrObjectType())
195+
return Data.m_Ptr;
196+
return (void *)as<uintptr_t>();
197+
}
198+
199+
} // namespace clang
200+
#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)