Skip to content

[clang-repl] Implement value printing of custom types #84769

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Draft
wants to merge 3 commits into
base: main
Choose a base branch
from
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions clang/include/clang/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -1099,6 +1099,8 @@ class ASTContext : public RefCountedBase<ASTContext> {
bool isInSameModule(const Module *M1, const Module *M2);

TranslationUnitDecl *getTranslationUnitDecl() const {
assert(TUDecl->getMostRecentDecl() == TUDecl &&
"The active TU is not current one!");
return TUDecl->getMostRecentDecl();
}
void addTranslationUnitDecl() {
Expand Down
3 changes: 2 additions & 1 deletion clang/include/clang/Frontend/MultiplexConsumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@ class MultiplexConsumer : public SemaConsumer {
public:
// Takes ownership of the pointers in C.
MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C);
MultiplexConsumer(std::unique_ptr<ASTConsumer> C);
~MultiplexConsumer() override;

// ASTConsumer
Expand Down Expand Up @@ -80,7 +81,7 @@ class MultiplexConsumer : public SemaConsumer {
void InitializeSema(Sema &S) override;
void ForgetSema() override;

private:
protected:
std::vector<std::unique_ptr<ASTConsumer>> Consumers; // Owns these.
std::unique_ptr<MultiplexASTMutationListener> MutationListener;
std::unique_ptr<MultiplexASTDeserializationListener> DeserializationListener;
Expand Down
85 changes: 50 additions & 35 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,11 +14,9 @@
#ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H
#define LLVM_CLANG_INTERPRETER_INTERPRETER_H

#include "clang/AST/Decl.h"
#include "clang/AST/GlobalDecl.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Interpreter/Value.h"
#include "clang/Sema/Ownership.h"

#include "llvm/ADT/DenseMap.h"
#include "llvm/ExecutionEngine/JITSymbol.h"
Expand All @@ -38,8 +36,12 @@ class ThreadSafeContext;
namespace clang {

class CompilerInstance;
class CodeGenerator;
class CXXRecordDecl;
class Decl;
class IncrementalExecutor;
class IncrementalParser;
class LookupResult;

/// Create a pre-configured \c CompilerInstance for incremental processing.
class IncrementalCompilerBuilder {
Expand Down Expand Up @@ -77,42 +79,56 @@ class IncrementalCompilerBuilder {
llvm::StringRef CudaSDKPath;
};

/// Generate glue code between the Interpreter's built-in runtime and user code.
class RuntimeInterfaceBuilder {
public:
virtual ~RuntimeInterfaceBuilder() = default;

using TransformExprFunction = ExprResult(RuntimeInterfaceBuilder *Builder,
Expr *, ArrayRef<Expr *>);
virtual TransformExprFunction *getPrintValueTransformer() = 0;
};
class IncrementalAction;
class InProcessPrintingASTConsumer;

/// Provides top-level interfaces for incremental compilation and execution.
class Interpreter {
friend class Value;
friend InProcessPrintingASTConsumer;

std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx;
/// Long-lived, incremental parsing action.
std::unique_ptr<IncrementalAction> Act;
std::unique_ptr<IncrementalParser> IncrParser;
std::unique_ptr<IncrementalExecutor> IncrExecutor;
std::unique_ptr<RuntimeInterfaceBuilder> RuntimeIB;

// An optional parser for CUDA offloading
std::unique_ptr<IncrementalParser> DeviceParser;

std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;

/// List containing every information about every incrementally parsed piece
/// of code.
std::list<PartialTranslationUnit> PTUs;

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;

// Add a call to an Expr to report its result. We query the function from
// RuntimeInterfaceBuilder once and store it as a function pointer to avoid
// frequent virtual function calls.
RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr;
// The cached declaration of std::string used as a return type for the built
// trampoline. This is done in C++ to simplify the memory management for
// user-defined printing functions.
Decl *StdString = nullptr;

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

std::array<Expr *, 4> ValuePrintingInfo = {0};

/// When CodeGen is created the first llvm::Module gets cached in many places
/// and we must keep it alive.
std::unique_ptr<llvm::Module> CachedInCodeGenModule;

protected:
// Derived classes can use an extended interface of the Interpreter.
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err,
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr,
std::unique_ptr<clang::ASTConsumer> Consumer = nullptr);

// Create the internal IncrementalExecutor, or re-create it after calling
// ResetExecutor().
Expand All @@ -122,15 +138,8 @@ class Interpreter {
// JIT engine. In particular, it doesn't run cleanup or destructors.
void ResetExecutor();

// Lazily construct the RuntimeInterfaceBuilder. The provided instance will be
// used for the entire lifetime of the interpreter. The default implementation
// targets the in-process __clang_Interpreter runtime. Override this to use a
// custom runtime.
virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface();

public:
virtual ~Interpreter();

static llvm::Expected<std::unique_ptr<Interpreter>>
create(std::unique_ptr<CompilerInstance> CI);
static llvm::Expected<std::unique_ptr<Interpreter>>
Expand All @@ -145,7 +154,6 @@ class Interpreter {
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
llvm::Error Execute(PartialTranslationUnit &T);
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);

/// Undo N previous incremental inputs.
llvm::Error Undo(unsigned N = 1);
Expand All @@ -167,23 +175,30 @@ class Interpreter {
llvm::Expected<llvm::orc::ExecutorAddr>
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;

enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };

const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
return ValuePrintingInfo;
}

Expr *SynthesizeExpr(Expr *E);
std::unique_ptr<llvm::Module> GenModule();

private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();

llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
/// @}
/// @name Value and pretty printing support
/// @{

llvm::SmallVector<Expr *, 4> ValuePrintingInfo;
std::string ValueDataToString(const Value &V);
std::string ValueTypeToString(const Value &V) const;
std::string CallUserSpecifiedPrinter(LookupResult &R, const Value &V);

std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder;
llvm::Expected<Expr *> convertExprToValue(Expr *E);

// When we deallocate clang::Value we need to run the destructor of the type.
// This function forces emission of the needed dtor.
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);

/// @}
/// @name Code generation
/// @{
CodeGenerator *getCodeGen() const;
};
} // namespace clang

Expand Down
13 changes: 7 additions & 6 deletions clang/include/clang/Interpreter/Value.h
Original file line number Diff line number Diff line change
Expand Up @@ -49,9 +49,10 @@ class raw_ostream;
namespace clang {

class ASTContext;
class Interpreter;
class QualType;

class Interpreter;

#if defined(_WIN32)
// REPL_EXTERNAL_VISIBILITY are symbols that we need to be able to locate
// at runtime. On Windows, this requires them to be exported from any of the
Expand Down Expand Up @@ -118,9 +119,9 @@ class REPL_EXTERNAL_VISIBILITY Value {
~Value();

void printType(llvm::raw_ostream &Out) const;
void printData(llvm::raw_ostream &Out) const;
void print(llvm::raw_ostream &Out) const;
void dump() const;
void printData(llvm::raw_ostream &Out);
void print(llvm::raw_ostream &Out);
void dump();
void clear();

ASTContext &getASTContext();
Expand All @@ -138,6 +139,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
void setOpaqueType(void *Ty) { OpaqueType = Ty; }

void *getPtr() const;
void **getPtrAddress() const;
void setPtr(void *Ptr) { Data.m_Ptr = Ptr; }

#define X(type, name) \
Expand Down Expand Up @@ -176,7 +178,7 @@ class REPL_EXTERNAL_VISIBILITY Value {
template <typename T> struct convertFwd {
static T cast(const Value &V) {
if (V.isPointerOrObjectType())
return (T)(uintptr_t)V.as<void *>();
return *(T*)(uintptr_t)V.as<void *>();
if (!V.isValid() || V.isVoid()) {
return T();
}
Expand Down Expand Up @@ -204,6 +206,5 @@ template <> inline void *Value::as() const {
return Data.m_Ptr;
return (void *)as<uintptr_t>();
}

} // namespace clang
#endif
7 changes: 7 additions & 0 deletions clang/lib/Frontend/MultiplexConsumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,6 +298,13 @@ MultiplexConsumer::MultiplexConsumer(
}
}

MultiplexConsumer::MultiplexConsumer(std::unique_ptr<ASTConsumer> C)
: MultiplexConsumer([](std::unique_ptr<ASTConsumer> Consumer) {
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
Consumers.push_back(std::move(Consumer));
return Consumers;
}(std::move(C))) {}

MultiplexConsumer::~MultiplexConsumer() {}

void MultiplexConsumer::Initialize(ASTContext &Context) {
Expand Down
1 change: 1 addition & 0 deletions clang/lib/Headers/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ set(core_files
tgmath.h
unwind.h
varargs.h
__clang_interpreter_runtime_printvalue.h
)

set(arm_common_files
Expand Down
Loading
Loading