Skip to content

Commit 9bf7d04

Browse files
authored
[clang-repl] Lay the basic infrastructure for pretty printing of types (#148701)
The idea is to store a type-value pair in clang::Value which is updated by the interpreter runtime. The class copies builtin types and boxes non-builtin types to provide some lifetime control. The patch enables default printers for C and C++ using a very minimalistic approach. We handle enums, arrays and user types. Once we land this we can focus on enabling user-defined pretty-printers which take control over printing of types The work started as part of https://reviews.llvm.org/D146809, then we created a giant in #84769
1 parent c875bb8 commit 9bf7d04

File tree

13 files changed

+640
-83
lines changed

13 files changed

+640
-83
lines changed

clang/include/clang/AST/ASTContext.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1192,6 +1192,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
11921192
bool isInSameModule(const Module *M1, const Module *M2) const;
11931193

11941194
TranslationUnitDecl *getTranslationUnitDecl() const {
1195+
assert(TUDecl->getMostRecentDecl() == TUDecl &&
1196+
"The active TU is not current one!");
11951197
return TUDecl->getMostRecentDecl();
11961198
}
11971199
void addTranslationUnitDecl() {

clang/include/clang/Interpreter/Interpreter.h

Lines changed: 25 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -175,31 +175,42 @@ class Interpreter {
175175
llvm::Expected<llvm::orc::ExecutorAddr>
176176
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
177177

178-
const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
179-
return ValuePrintingInfo;
180-
}
181-
182-
Expr *SynthesizeExpr(Expr *E);
178+
std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
179+
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
180+
std::unique_ptr<llvm::Module> M = {},
181+
IncrementalAction *Action = nullptr);
183182

184183
private:
185184
size_t getEffectivePTUSize() const;
186185
void markUserCodeStart();
187186
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
188-
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
189-
190-
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
191-
std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
192-
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
193-
std::unique_ptr<llvm::Module> M = {},
194-
IncrementalAction *Action = nullptr);
195187

196188
// A cache for the compiled destructors used to for de-allocation of managed
197189
// clang::Values.
198-
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
190+
mutable llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
199191

200-
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
192+
std::array<Expr *, 4> ValuePrintingInfo = {0};
201193

202194
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;
195+
196+
/// @}
197+
/// @name Value and pretty printing support
198+
/// @{
199+
200+
std::string ValueDataToString(const Value &V) const;
201+
std::string ValueTypeToString(const Value &V) const;
202+
203+
llvm::Expected<Expr *> convertExprToValue(Expr *E);
204+
205+
// When we deallocate clang::Value we need to run the destructor of the type.
206+
// This function forces emission of the needed dtor.
207+
llvm::Expected<llvm::orc::ExecutorAddr>
208+
CompileDtorCall(CXXRecordDecl *CXXRD) const;
209+
210+
/// @}
211+
/// @name Code generation
212+
/// @{
213+
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
203214
};
204215
} // namespace clang
205216

clang/include/clang/Interpreter/Value.h

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@
3535

3636
#include "llvm/Config/llvm-config.h" // for LLVM_BUILD_LLVM_DYLIB, LLVM_BUILD_SHARED_LIBS
3737
#include "llvm/Support/Compiler.h"
38+
#include <cassert>
3839
#include <cstdint>
3940

4041
// NOTE: Since the REPL itself could also include this runtime, extreme caution
@@ -97,6 +98,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
9798
REPL_BUILTIN_TYPES
9899
#undef X
99100
void *m_Ptr;
101+
unsigned char m_RawBits[sizeof(long double) * 8]; // widest type
100102
};
101103

102104
public:
@@ -111,7 +113,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
111113
};
112114

113115
Value() = default;
114-
Value(Interpreter *In, void *Ty);
116+
Value(const Interpreter *In, void *Ty);
115117
Value(const Value &RHS);
116118
Value(Value &&RHS) noexcept;
117119
Value &operator=(const Value &RHS);
@@ -124,9 +126,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
124126
void dump() const;
125127
void clear();
126128

127-
ASTContext &getASTContext();
128129
const ASTContext &getASTContext() const;
129-
Interpreter &getInterpreter();
130130
const Interpreter &getInterpreter() const;
131131
QualType getType() const;
132132

@@ -140,6 +140,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
140140

141141
void *getPtr() const;
142142
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }
143+
void setRawBits(void *Ptr, unsigned NBits = sizeof(Storage));
143144

144145
#define X(type, name) \
145146
void set##name(type Val) { Data.m_##name = Val; } \
@@ -193,7 +194,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
193194
}
194195
};
195196

196-
Interpreter *Interp = nullptr;
197+
const Interpreter *Interp = nullptr;
197198
void *OpaqueType = nullptr;
198199
Storage Data;
199200
Kind ValueKind = K_Unspecified;
@@ -205,6 +206,5 @@ template <> inline void *Value::as() const {
205206
return Data.m_Ptr;
206207
return (void *)as<uintptr_t>();
207208
}
208-
209209
} // namespace clang
210210
#endif

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,7 @@ add_clang_library(clangInterpreter
2929
InterpreterUtils.cpp
3030
RemoteJITUtils.cpp
3131
Value.cpp
32+
InterpreterValuePrinter.cpp
3233
${WASM_SRC}
3334
PARTIAL_SOURCES_INTENDED
3435

clang/lib/Interpreter/Interpreter.cpp

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -264,7 +264,7 @@ class InProcessPrintingASTConsumer final : public MultiplexConsumer {
264264
if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
265265
if (TLSD && TLSD->isSemiMissing()) {
266266
auto ExprOrErr =
267-
Interp.ExtractValueFromExpr(cast<Expr>(TLSD->getStmt()));
267+
Interp.convertExprToValue(cast<Expr>(TLSD->getStmt()));
268268
if (llvm::Error E = ExprOrErr.takeError()) {
269269
llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),
270270
"Value printing failed: ");
@@ -440,11 +440,10 @@ const char *const Runtimes = R"(
440440
#define __CLANG_REPL__ 1
441441
#ifdef __cplusplus
442442
#define EXTERN_C extern "C"
443-
void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
444443
struct __clang_Interpreter_NewTag{} __ci_newtag;
445444
void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
446445
template <class T, class = T (*)() /*disable for arrays*/>
447-
void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
446+
void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {
448447
for (auto Idx = 0; Idx < Size; ++Idx)
449448
new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
450449
}
@@ -454,8 +453,12 @@ const char *const Runtimes = R"(
454453
}
455454
#else
456455
#define EXTERN_C extern
456+
EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);
457+
EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {
458+
memcpy(Placement, Src, Size);
459+
}
457460
#endif // __cplusplus
458-
461+
EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
459462
EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
460463
)";
461464

@@ -470,12 +473,12 @@ Interpreter::create(std::unique_ptr<CompilerInstance> CI,
470473

471474
// Add runtime code and set a marker to hide it from user code. Undo will not
472475
// go through that.
473-
auto PTU = Interp->Parse(Runtimes);
474-
if (!PTU)
475-
return PTU.takeError();
476+
Err = Interp->ParseAndExecute(Runtimes);
477+
if (Err)
478+
return std::move(Err);
479+
476480
Interp->markUserCodeStart();
477481

478-
Interp->ValuePrintingInfo.resize(4);
479482
return std::move(Interp);
480483
}
481484

@@ -524,12 +527,11 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
524527
return std::move(Interp);
525528
}
526529

530+
CompilerInstance *Interpreter::getCompilerInstance() { return CI.get(); }
527531
const CompilerInstance *Interpreter::getCompilerInstance() const {
528-
return CI.get();
532+
return const_cast<Interpreter *>(this)->getCompilerInstance();
529533
}
530534

531-
CompilerInstance *Interpreter::getCompilerInstance() { return CI.get(); }
532-
533535
llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
534536
if (!IncrExecutor) {
535537
if (auto Err = CreateExecutor())
@@ -610,7 +612,14 @@ Interpreter::Parse(llvm::StringRef Code) {
610612
if (!TuOrErr)
611613
return TuOrErr.takeError();
612614

613-
return RegisterPTU(*TuOrErr);
615+
PTUs.emplace_back(PartialTranslationUnit());
616+
PartialTranslationUnit &LastPTU = PTUs.back();
617+
LastPTU.TUPart = *TuOrErr;
618+
619+
if (std::unique_ptr<llvm::Module> M = GenModule())
620+
LastPTU.TheModule = std::move(M);
621+
622+
return LastPTU;
614623
}
615624

616625
static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
@@ -808,10 +817,10 @@ Interpreter::GenModule(IncrementalAction *Action) {
808817
// sure it always stays empty.
809818
assert(((!CachedInCodeGenModule ||
810819
!getCompilerInstance()->getPreprocessorOpts().Includes.empty()) ||
811-
(CachedInCodeGenModule->empty() &&
812-
CachedInCodeGenModule->global_empty() &&
813-
CachedInCodeGenModule->alias_empty() &&
814-
CachedInCodeGenModule->ifunc_empty())) &&
820+
((CachedInCodeGenModule->empty() &&
821+
CachedInCodeGenModule->global_empty() &&
822+
CachedInCodeGenModule->alias_empty() &&
823+
CachedInCodeGenModule->ifunc_empty()))) &&
815824
"CodeGen wrote to a readonly module");
816825
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
817826
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
@@ -828,4 +837,4 @@ CodeGenerator *Interpreter::getCodeGen(IncrementalAction *Action) const {
828837
return nullptr;
829838
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
830839
}
831-
} // namespace clang
840+
} // end namespace clang

clang/lib/Interpreter/InterpreterUtils.cpp

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "InterpreterUtils.h"
14+
#include "clang/AST/QualTypeNames.h"
1415

1516
namespace clang {
1617

@@ -81,7 +82,7 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
8182
else {
8283
const DeclContext *PrimaryWithin = nullptr;
8384
if (const auto *TD = dyn_cast<TagDecl>(Within))
84-
PrimaryWithin = llvm::dyn_cast_or_null<DeclContext>(TD->getDefinition());
85+
PrimaryWithin = dyn_cast_if_present<DeclContext>(TD->getDefinition());
8586
else
8687
PrimaryWithin = Within->getPrimaryContext();
8788

@@ -97,15 +98,16 @@ NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
9798
R.resolveKind();
9899

99100
if (R.isSingleResult())
100-
return llvm::dyn_cast<NamedDecl>(R.getFoundDecl());
101+
return dyn_cast<NamedDecl>(R.getFoundDecl());
101102

102103
return nullptr;
103104
}
104105

105106
std::string GetFullTypeName(ASTContext &Ctx, QualType QT) {
107+
QualType FQT = TypeName::getFullyQualifiedType(QT, Ctx);
106108
PrintingPolicy Policy(Ctx.getPrintingPolicy());
107109
Policy.SuppressScope = false;
108110
Policy.AnonymousTagLocations = false;
109-
return QT.getAsString(Policy);
111+
return FQT.getAsString(Policy);
110112
}
111113
} // namespace clang

clang/lib/Interpreter/InterpreterUtils.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name,
4545
const DeclContext *Within = nullptr);
4646

4747
NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
48-
const DeclContext *Within);
48+
const DeclContext *Within = nullptr);
4949

5050
std::string GetFullTypeName(ASTContext &Ctx, QualType QT);
5151
} // namespace clang

0 commit comments

Comments
 (0)