Skip to content

Commit 05c3bb8

Browse files
committed
[clang-repl] Implement value printing of custom types.
Differential revision: https://reviews.llvm.org/D146809
1 parent 71c2a13 commit 05c3bb8

23 files changed

+1606
-39
lines changed

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,8 @@ class ThreadSafeContext;
3636
namespace clang {
3737

3838
class CompilerInstance;
39+
40+
namespace caas {
3941
class IncrementalExecutor;
4042
class IncrementalParser;
4143

@@ -105,6 +107,7 @@ class Interpreter {
105107
llvm::Expected<llvm::orc::LLJIT &> getExecutionEngine();
106108

107109
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
110+
llvm::Error ExecuteModule(std::unique_ptr<llvm::Module> &M);
108111
llvm::Error Execute(PartialTranslationUnit &T);
109112
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
110113
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
@@ -137,6 +140,8 @@ class Interpreter {
137140

138141
Expr *SynthesizeExpr(Expr *E);
139142

143+
std::unique_ptr<llvm::Module> GenModule();
144+
140145
private:
141146
size_t getEffectivePTUSize() const;
142147

@@ -146,6 +151,7 @@ class Interpreter {
146151

147152
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
148153
};
154+
} // namespace caas
149155
} // namespace clang
150156

151157
#endif // LLVM_CLANG_INTERPRETER_INTERPRETER_H

clang/include/clang/Interpreter/PartialTranslationUnit.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,7 @@ namespace clang {
2424

2525
class TranslationUnitDecl;
2626

27+
namespace caas {
2728
/// The class keeps track of various objects created as part of processing
2829
/// incremental inputs.
2930
struct PartialTranslationUnit {
@@ -32,6 +33,7 @@ struct PartialTranslationUnit {
3233
/// The llvm IR produced for the input.
3334
std::unique_ptr<llvm::Module> TheModule;
3435
};
36+
} // namespace caas
3537
} // namespace clang
3638

3739
#endif // LLVM_CLANG_INTERPRETER_PARTIALTRANSLATIONUNIT_H

clang/include/clang/Interpreter/Value.h

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -49,9 +49,11 @@ class raw_ostream;
4949
namespace clang {
5050

5151
class ASTContext;
52-
class Interpreter;
5352
class QualType;
5453

54+
namespace caas {
55+
class Interpreter;
56+
5557
#if defined(_WIN32)
5658
// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
5759
// at runtime. On Windows, this requires them to be exported from any of the
@@ -137,6 +139,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
137139
void setOpaqueType(void *Ty) { OpaqueType = Ty; }
138140

139141
void *getPtr() const;
142+
void **getPtrAddress() const;
140143
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
141144

142145
#define X(type, name) \
@@ -203,6 +206,6 @@ template <> inline void *Value::as() const {
203206
return Data.m_Ptr;
204207
return (void *)as<uintptr_t>();
205208
}
206-
209+
} // namespace caas
207210
} // namespace clang
208211
#endif

clang/lib/Headers/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ set(core_files
3434
tgmath.h
3535
unwind.h
3636
varargs.h
37+
__clang_interpreter_runtime_printvalue.h
3738
)
3839

3940
set(arm_common_files
Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
//===--- __clang_interpreter_runtime_printvalue.h ---*- C++
2+
//-*-===//
3+
//
4+
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
5+
// See https://llvm.org/LICENSE.txt for license information.
6+
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
7+
//
8+
//===----------------------------------------------------------------------===//
9+
//
10+
// This file defines runtime functions used to print STL components in
11+
// clang-repl. They are very heavy so we should only include it once and on
12+
// demand.
13+
//
14+
//===----------------------------------------------------------------------===//
15+
#ifndef LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
16+
#define LLVM_CLANG_INTERPRETER_RUNTIME_PRINT_VALUE_H
17+
18+
#if !defined(__CLANG_REPL__)
19+
#error "This file should only be included by clang-repl!"
20+
#endif
21+
22+
#include <memory>
23+
#include <string>
24+
#include <tuple>
25+
#include <type_traits>
26+
#include <vector>
27+
28+
// FIXME: We should include it somewhere instead of duplicating it...
29+
#if __has_attribute(visibility) && \
30+
(!(defined(_WIN32) || defined(__CYGWIN__)) || \
31+
(defined(__MINGW32__) && defined(__clang__)))
32+
#if defined(LLVM_BUILD_LLVM_DYLIB) || defined(LLVM_BUILD_SHARED_LIBS)
33+
#define __REPL_EXTERNAL_VISIBILITY __attribute__((visibility("default")))
34+
#else
35+
#define __REPL_EXTERNAL_VISIBILITY
36+
#endif
37+
#else
38+
#if defined(_WIN32)
39+
#define __REPL_EXTERNAL_VISIBILITY __declspec(dllexport)
40+
#endif
41+
#endif
42+
43+
// Fallback.
44+
template <class T,
45+
typename std::enable_if<!std::is_pointer<T>::value>::type * = nullptr>
46+
inline std::string PrintValueRuntime(const T &) {
47+
return "{not representable}";
48+
}
49+
50+
#ifndef __DECL_PRINT_VALUE_RUNTIME
51+
#define __DECL_PRINT_VALUE_RUNTIME(type) \
52+
__REPL_EXTERNAL_VISIBILITY std::string PrintValueRuntime(const type *__Ptr)
53+
__DECL_PRINT_VALUE_RUNTIME(void);
54+
__DECL_PRINT_VALUE_RUNTIME(void *);
55+
__DECL_PRINT_VALUE_RUNTIME(bool);
56+
__DECL_PRINT_VALUE_RUNTIME(char);
57+
__DECL_PRINT_VALUE_RUNTIME(signed char);
58+
__DECL_PRINT_VALUE_RUNTIME(short);
59+
__DECL_PRINT_VALUE_RUNTIME(unsigned short);
60+
__DECL_PRINT_VALUE_RUNTIME(int);
61+
__DECL_PRINT_VALUE_RUNTIME(unsigned int);
62+
__DECL_PRINT_VALUE_RUNTIME(long);
63+
__DECL_PRINT_VALUE_RUNTIME(long long);
64+
__DECL_PRINT_VALUE_RUNTIME(unsigned long);
65+
__DECL_PRINT_VALUE_RUNTIME(unsigned long long);
66+
__DECL_PRINT_VALUE_RUNTIME(float);
67+
__DECL_PRINT_VALUE_RUNTIME(double);
68+
__DECL_PRINT_VALUE_RUNTIME(long double);
69+
__DECL_PRINT_VALUE_RUNTIME(char *const);
70+
__DECL_PRINT_VALUE_RUNTIME(char *);
71+
#endif
72+
73+
namespace __repl_runtime_detail {
74+
75+
// Custom void_t implementation for C++11 compatibility
76+
template <typename... Ts> struct __repl_void_impl { typedef void type; };
77+
78+
// Helper to deduce the type of the expression 'std::begin(std::declval<T &>())'
79+
template <typename T>
80+
using __repl_begin_result = decltype(std::begin(std::declval<T &>()));
81+
82+
// Helper to deduce the type of the expression 'std::end(std::declval<T &>())'
83+
template <typename T>
84+
using __repl_end_result = decltype(std::end(std::declval<T &>()));
85+
86+
// Type trait to check if a type is iterable
87+
template <typename T, typename = void>
88+
struct __is_iterable : std::false_type {};
89+
90+
template <typename T>
91+
struct __is_iterable<T, typename __repl_void_impl<__repl_begin_result<T>,
92+
__repl_end_result<T>>::type>
93+
: std::true_type {};
94+
95+
// Type trait to check if a type is std::pair
96+
template <typename T> struct __is_pair : std::false_type {};
97+
98+
template <typename T, typename U>
99+
struct __is_pair<std::pair<T, U>> : std::true_type {};
100+
101+
// Type trait to check if a type is std::map (or any associative container with
102+
// mapped_type)
103+
template <typename T, typename = void> struct __is_map : std::false_type {};
104+
105+
template <typename T>
106+
struct __is_map<T, typename __repl_void_impl<typename T::mapped_type>::type>
107+
: std::true_type {};
108+
109+
// The type of the elements is std::pair, and the container is a map like type.
110+
template <
111+
typename Container, typename Elt,
112+
typename std::enable_if<__is_pair<Elt>::value && __is_map<Container>::value,
113+
bool>::type = true>
114+
std::string __PrintCollectionElt(const Elt &Val) {
115+
return PrintValueRuntime(&Val.first) + " => " +
116+
PrintValueRuntime(&Val.second);
117+
}
118+
119+
// The type of the elements is std::pair, and the container isn't a map-like
120+
// type.
121+
template <typename Container, typename Elt,
122+
typename std::enable_if<__is_pair<Elt>::value &&
123+
!__is_map<Container>::value,
124+
bool>::type = true>
125+
std::string __PrintCollectionElt(const Elt &Val) {
126+
return TuplePairPrintValue(&Val);
127+
}
128+
129+
template <typename Container, typename Elt,
130+
typename std::enable_if<!__is_pair<Elt>::value, bool>::type = true>
131+
std::string __PrintCollectionElt(const Elt &Val) {
132+
return PrintValueRuntime(&Val);
133+
}
134+
135+
template <class Tuple, std::size_t N = std::tuple_size<Tuple>(),
136+
std::size_t TupleSize = std::tuple_size<Tuple>()>
137+
struct __TupleLikePrinter {
138+
static std::string print(const Tuple *T) {
139+
constexpr std::size_t EltNum = TupleSize - N;
140+
std::string Str;
141+
// Not the first element.
142+
if (EltNum != 0)
143+
Str += ", ";
144+
Str += PrintValueRuntime(&std::get<EltNum>(*T));
145+
// If N+1 is not smaller than the size of the tuple,
146+
// reroute the call to the printing function to the
147+
// no-op specialisation to stop recursion.
148+
constexpr std::size_t Nm1 = N - 1;
149+
Str += __TupleLikePrinter<Tuple, Nm1>::print((const Tuple *)T);
150+
return Str;
151+
}
152+
};
153+
154+
template <class Tuple, std::size_t TupleSize>
155+
struct __TupleLikePrinter<Tuple, 0, TupleSize> {
156+
static std::string print(const Tuple *T) { return ""; }
157+
};
158+
159+
template <class T> inline std::string TuplePairPrintValue(const T *Val) {
160+
std::string Str("{ ");
161+
Str += __TupleLikePrinter<T>::print(Val);
162+
Str += " }";
163+
return Str;
164+
}
165+
166+
struct __StdVectorBool {
167+
bool Value;
168+
__StdVectorBool(bool V) : Value(V) {}
169+
};
170+
template <typename T>
171+
std::string __PrintCollectionElt(const __StdVectorBool &Val) {
172+
return PrintValueRuntime(&Val.Value);
173+
}
174+
175+
} // namespace __repl_runtime_detail
176+
177+
template <typename Container,
178+
typename std::enable_if<
179+
__repl_runtime_detail::__is_iterable<Container>::value,
180+
bool>::type = true>
181+
inline std::string PrintValueRuntime(const Container *C) {
182+
std::string Str("{ ");
183+
184+
for (auto Beg = C->begin(), End = C->end(); Beg != End; Beg++) {
185+
if (Beg != C->begin())
186+
Str += ", ";
187+
Str += __repl_runtime_detail::__PrintCollectionElt<Container>(*Beg);
188+
}
189+
Str += " }";
190+
return Str;
191+
}
192+
193+
template <typename T, size_t N>
194+
inline std::string PrintValueRuntime(const T (*Obj)[N]) {
195+
if (N == 0)
196+
return "{}";
197+
198+
std::string Str = "{ ";
199+
for (size_t Idx = 0; Idx < N; ++Idx) {
200+
Str += PrintValueRuntime(*Obj + Idx);
201+
if (Idx < N - 1)
202+
Str += ", ";
203+
}
204+
return Str + " }";
205+
}
206+
207+
template <size_t N> inline std::string PrintValueRuntime(const char (*Obj)[N]) {
208+
const auto *Str = reinterpret_cast<const char *const>(Obj);
209+
return PrintValueRuntime(&Str);
210+
}
211+
212+
// std::vector<bool>
213+
inline std::string PrintValueRuntime(const std::vector<bool> *Val) {
214+
// Try our best to fix std::vector<bool> without too much of templated code.
215+
std::vector<__repl_runtime_detail::__StdVectorBool> ValFixed(Val->begin(),
216+
Val->end());
217+
return PrintValueRuntime<decltype(ValFixed)>(&ValFixed);
218+
}
219+
220+
// tuple
221+
template <typename... Ts>
222+
inline std::string PrintValueRuntime(const std::tuple<Ts...> *Val) {
223+
using T = std::tuple<Ts...>;
224+
return __repl_runtime_detail::TuplePairPrintValue<T>(Val);
225+
}
226+
227+
// pair
228+
template <typename... Ts>
229+
inline std::string PrintValueRuntime(const std::pair<Ts...> *Val) {
230+
using T = std::pair<Ts...>;
231+
return __repl_runtime_detail::TuplePairPrintValue<T>(Val);
232+
}
233+
234+
// unique_ptr
235+
template <class T>
236+
inline std::string PrintValueRuntime(const std::unique_ptr<T> *Val) {
237+
auto Ptr = Val->get();
238+
return "std::unique_ptr -> " + PrintValueRuntime((const void **)&Ptr);
239+
}
240+
241+
// shared_ptr
242+
template <class T>
243+
inline std::string PrintValueRuntime(const std::shared_ptr<T> *Val) {
244+
auto Ptr = Val->get();
245+
return "std::shared_ptr -> " + PrintValueRuntime((const void **)&Ptr);
246+
}
247+
248+
// weak_ptr
249+
template <class T>
250+
inline std::string PrintValueRuntime(const std::weak_ptr<T> *Val) {
251+
auto Ptr = Val->lock().get();
252+
return "std::weak_ptr -> " + PrintValueRuntime((const void **)&Ptr);
253+
}
254+
255+
// string
256+
template <class T>
257+
inline std::string PrintValueRuntime(const std::basic_string<T> *Val) {
258+
const char *Chars = Val->c_str();
259+
return PrintValueRuntime((const char **)&Chars);
260+
}
261+
#endif

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ add_clang_library(clangInterpreter
2020
Interpreter.cpp
2121
InterpreterUtils.cpp
2222
Value.cpp
23+
ValuePrinter.cpp
2324

2425
DEPENDS
2526
intrinsics_gen

clang/lib/Interpreter/DeviceOffload.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@
2020
#include "llvm/MC/TargetRegistry.h"
2121
#include "llvm/Target/TargetMachine.h"
2222

23-
namespace clang {
23+
namespace clang::caas {
2424

2525
IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
2626
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
@@ -173,4 +173,4 @@ llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
173173

174174
IncrementalCUDADeviceParser::~IncrementalCUDADeviceParser() {}
175175

176-
} // namespace clang
176+
} // namespace clang::caas

clang/lib/Interpreter/DeviceOffload.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
#include "llvm/Support/FileSystem.h"
1818
#include "llvm/Support/VirtualFileSystem.h"
1919

20-
namespace clang {
20+
namespace clang::caas {
2121

2222
class IncrementalCUDADeviceParser : public IncrementalParser {
2323
public:
@@ -46,6 +46,6 @@ class IncrementalCUDADeviceParser : public IncrementalParser {
4646
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
4747
};
4848

49-
} // namespace clang
49+
} // namespace clang::caas
5050

5151
#endif // LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H

0 commit comments

Comments
 (0)