Skip to content

Commit a72d7ee

Browse files
authoredSep 23, 2024··
[clang-repl] Simplify the value printing logic to enable out-of-process. (#107737)
This patch improves the design of the IncrementalParser and Interpreter classes. Now the incremental parser is only responsible for building the partial translation unit declaration and the AST, while the Interpreter fills in the lower level llvm::Module and other JIT-related infrastructure. Finally the Interpreter class now orchestrates the AST and the LLVM IR with the IncrementalParser and IncrementalExecutor classes. The design improvement allows us to rework some of the logic that extracts an interpreter value into the clang::Value object. The new implementation simplifies use-cases which are used for out-of-process execution by allowing interpreter to be inherited or customized with an clang::ASTConsumer. This change will enable completing the pretty printing work which is in #84769
1 parent 7a18198 commit a72d7ee

13 files changed

+732
-822
lines changed
 

‎clang/include/clang/Frontend/MultiplexConsumer.h

+2-1
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ class MultiplexConsumer : public SemaConsumer {
5353
public:
5454
// Takes ownership of the pointers in C.
5555
MultiplexConsumer(std::vector<std::unique_ptr<ASTConsumer>> C);
56+
MultiplexConsumer(std::unique_ptr<ASTConsumer> C);
5657
~MultiplexConsumer() override;
5758

5859
// ASTConsumer
@@ -80,7 +81,7 @@ class MultiplexConsumer : public SemaConsumer {
8081
void InitializeSema(Sema &S) override;
8182
void ForgetSema() override;
8283

83-
private:
84+
protected:
8485
std::vector<std::unique_ptr<ASTConsumer>> Consumers; // Owns these.
8586
std::unique_ptr<MultiplexASTMutationListener> MutationListener;
8687
std::unique_ptr<MultiplexASTDeserializationListener> DeserializationListener;

‎clang/include/clang/Interpreter/Interpreter.h

+30-28
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,9 @@
1414
#ifndef LLVM_CLANG_INTERPRETER_INTERPRETER_H
1515
#define LLVM_CLANG_INTERPRETER_INTERPRETER_H
1616

17-
#include "clang/AST/Decl.h"
1817
#include "clang/AST/GlobalDecl.h"
1918
#include "clang/Interpreter/PartialTranslationUnit.h"
2019
#include "clang/Interpreter/Value.h"
21-
#include "clang/Sema/Ownership.h"
2220

2321
#include "llvm/ADT/DenseMap.h"
2422
#include "llvm/ExecutionEngine/JITSymbol.h"
@@ -38,6 +36,9 @@ class ThreadSafeContext;
3836
namespace clang {
3937

4038
class CompilerInstance;
39+
class CodeGenerator;
40+
class CXXRecordDecl;
41+
class Decl;
4142
class IncrementalExecutor;
4243
class IncrementalParser;
4344

@@ -77,42 +78,45 @@ class IncrementalCompilerBuilder {
7778
llvm::StringRef CudaSDKPath;
7879
};
7980

80-
/// Generate glue code between the Interpreter's built-in runtime and user code.
81-
class RuntimeInterfaceBuilder {
82-
public:
83-
virtual ~RuntimeInterfaceBuilder() = default;
84-
85-
using TransformExprFunction = ExprResult(RuntimeInterfaceBuilder *Builder,
86-
Expr *, ArrayRef<Expr *>);
87-
virtual TransformExprFunction *getPrintValueTransformer() = 0;
88-
};
81+
class IncrementalAction;
82+
class InProcessPrintingASTConsumer;
8983

9084
/// Provides top-level interfaces for incremental compilation and execution.
9185
class Interpreter {
86+
friend class Value;
87+
friend InProcessPrintingASTConsumer;
88+
9289
std::unique_ptr<llvm::orc::ThreadSafeContext> TSCtx;
90+
/// Long-lived, incremental parsing action.
91+
std::unique_ptr<IncrementalAction> Act;
9392
std::unique_ptr<IncrementalParser> IncrParser;
9493
std::unique_ptr<IncrementalExecutor> IncrExecutor;
95-
std::unique_ptr<RuntimeInterfaceBuilder> RuntimeIB;
9694

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

98+
/// List containing information about each incrementally parsed piece of code.
99+
std::list<PartialTranslationUnit> PTUs;
100+
100101
unsigned InitPTUSize = 0;
101102

102103
// This member holds the last result of the value printing. It's a class
103104
// member because we might want to access it after more inputs. If no value
104105
// printing happens, it's in an invalid state.
105106
Value LastValue;
106107

107-
// Add a call to an Expr to report its result. We query the function from
108-
// RuntimeInterfaceBuilder once and store it as a function pointer to avoid
109-
// frequent virtual function calls.
110-
RuntimeInterfaceBuilder::TransformExprFunction *AddPrintValueCall = nullptr;
108+
/// When CodeGen is created the first llvm::Module gets cached in many places
109+
/// and we must keep it alive.
110+
std::unique_ptr<llvm::Module> CachedInCodeGenModule;
111+
112+
/// Compiler instance performing the incremental compilation.
113+
std::unique_ptr<CompilerInstance> CI;
111114

112115
protected:
113116
// Derived classes can use an extended interface of the Interpreter.
114-
Interpreter(std::unique_ptr<CompilerInstance> CI, llvm::Error &Err,
115-
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr);
117+
Interpreter(std::unique_ptr<CompilerInstance> Instance, llvm::Error &Err,
118+
std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder = nullptr,
119+
std::unique_ptr<clang::ASTConsumer> Consumer = nullptr);
116120

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

125-
// Lazily construct the RuntimeInterfaceBuilder. The provided instance will be
126-
// used for the entire lifetime of the interpreter. The default implementation
127-
// targets the in-process __clang_Interpreter runtime. Override this to use a
128-
// custom runtime.
129-
virtual std::unique_ptr<RuntimeInterfaceBuilder> FindRuntimeInterface();
130-
131129
public:
132130
virtual ~Interpreter();
133-
134131
static llvm::Expected<std::unique_ptr<Interpreter>>
135132
create(std::unique_ptr<CompilerInstance> CI);
136133
static llvm::Expected<std::unique_ptr<Interpreter>>
@@ -145,7 +142,6 @@ class Interpreter {
145142
llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Code);
146143
llvm::Error Execute(PartialTranslationUnit &T);
147144
llvm::Error ParseAndExecute(llvm::StringRef Code, Value *V = nullptr);
148-
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
149145

150146
/// Undo N previous incremental inputs.
151147
llvm::Error Undo(unsigned N = 1);
@@ -167,8 +163,6 @@ class Interpreter {
167163
llvm::Expected<llvm::orc::ExecutorAddr>
168164
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;
169165

170-
enum InterfaceKind { NoAlloc, WithAlloc, CopyArray, NewTag };
171-
172166
const llvm::SmallVectorImpl<Expr *> &getValuePrintingInfo() const {
173167
return ValuePrintingInfo;
174168
}
@@ -178,7 +172,15 @@ class Interpreter {
178172
private:
179173
size_t getEffectivePTUSize() const;
180174
void markUserCodeStart();
175+
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
176+
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
177+
178+
CodeGenerator *getCodeGen() const;
179+
std::unique_ptr<llvm::Module> GenModule();
180+
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU);
181181

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

184186
llvm::SmallVector<Expr *, 4> ValuePrintingInfo;

‎clang/lib/Frontend/MultiplexConsumer.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -298,6 +298,13 @@ MultiplexConsumer::MultiplexConsumer(
298298
}
299299
}
300300

301+
MultiplexConsumer::MultiplexConsumer(std::unique_ptr<ASTConsumer> C)
302+
: MultiplexConsumer([](std::unique_ptr<ASTConsumer> Consumer) {
303+
std::vector<std::unique_ptr<ASTConsumer>> Consumers;
304+
Consumers.push_back(std::move(Consumer));
305+
return Consumers;
306+
}(std::move(C))) {}
307+
301308
MultiplexConsumer::~MultiplexConsumer() {}
302309

303310
void MultiplexConsumer::Initialize(ASTContext &Context) {

‎clang/lib/Interpreter/CMakeLists.txt

+1
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ add_clang_library(clangInterpreter
2222
IncrementalExecutor.cpp
2323
IncrementalParser.cpp
2424
Interpreter.cpp
25+
InterpreterValuePrinter.cpp
2526
InterpreterUtils.cpp
2627
Value.cpp
2728
${WASM_SRC}

‎clang/lib/Interpreter/DeviceOffload.cpp

+12-9
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "clang/Basic/TargetOptions.h"
1616
#include "clang/CodeGen/ModuleBuilder.h"
1717
#include "clang/Frontend/CompilerInstance.h"
18+
#include "clang/Interpreter/PartialTranslationUnit.h"
1819

1920
#include "llvm/IR/LegacyPassManager.h"
2021
#include "llvm/IR/Module.h"
@@ -24,15 +25,17 @@
2425
namespace clang {
2526

2627
IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
27-
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
28-
IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
28+
std::unique_ptr<CompilerInstance> DeviceInstance,
29+
CompilerInstance &HostInstance,
2930
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
30-
llvm::Error &Err)
31-
: IncrementalParser(Interp, std::move(Instance), LLVMCtx, Err),
32-
HostParser(HostParser), VFS(FS) {
31+
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs)
32+
: IncrementalParser(*DeviceInstance, Err), PTUs(PTUs), VFS(FS),
33+
CodeGenOpts(HostInstance.getCodeGenOpts()),
34+
TargetOpts(HostInstance.getTargetOpts()) {
3335
if (Err)
3436
return;
35-
StringRef Arch = CI->getTargetOpts().CPU;
37+
DeviceCI = std::move(DeviceInstance);
38+
StringRef Arch = TargetOpts.CPU;
3639
if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
3740
Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
3841
"Invalid CUDA architecture",
@@ -41,7 +44,7 @@ IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
4144
}
4245
}
4346

44-
llvm::Expected<PartialTranslationUnit &>
47+
llvm::Expected<TranslationUnitDecl *>
4548
IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
4649
auto PTU = IncrementalParser::Parse(Input);
4750
if (!PTU)
@@ -62,7 +65,7 @@ IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
6265
llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
6366
"", false));
6467

65-
HostParser.getCI()->getCodeGenOpts().CudaGpuBinaryFileName = FatbinFileName;
68+
CodeGenOpts.CudaGpuBinaryFileName = FatbinFileName;
6669

6770
FatbinContent.clear();
6871

@@ -80,7 +83,7 @@ llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
8083
std::error_code());
8184
llvm::TargetOptions TO = llvm::TargetOptions();
8285
llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
83-
PTU.TheModule->getTargetTriple(), getCI()->getTargetOpts().CPU, "", TO,
86+
PTU.TheModule->getTargetTriple(), TargetOpts.CPU, "", TO,
8487
llvm::Reloc::Model::PIC_);
8588
PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
8689

‎clang/lib/Interpreter/DeviceOffload.h

+14-7
Original file line numberDiff line numberDiff line change
@@ -18,19 +18,24 @@
1818
#include "llvm/Support/VirtualFileSystem.h"
1919

2020
namespace clang {
21+
struct PartialTranslationUnit;
22+
class CompilerInstance;
23+
class CodeGenOptions;
24+
class TargetOptions;
2125

2226
class IncrementalCUDADeviceParser : public IncrementalParser {
27+
const std::list<PartialTranslationUnit> &PTUs;
28+
2329
public:
2430
IncrementalCUDADeviceParser(
25-
Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
26-
IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
31+
std::unique_ptr<CompilerInstance> DeviceInstance,
32+
CompilerInstance &HostInstance,
2733
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
28-
llvm::Error &Err);
34+
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs);
2935

30-
llvm::Expected<PartialTranslationUnit &>
31-
Parse(llvm::StringRef Input) override;
36+
llvm::Expected<TranslationUnitDecl *> Parse(llvm::StringRef Input) override;
3237

33-
// Generate PTX for the last PTU
38+
// Generate PTX for the last PTU.
3439
llvm::Expected<llvm::StringRef> GeneratePTX();
3540

3641
// Generate fatbinary contents in memory
@@ -39,11 +44,13 @@ class IncrementalCUDADeviceParser : public IncrementalParser {
3944
~IncrementalCUDADeviceParser();
4045

4146
protected:
42-
IncrementalParser &HostParser;
47+
std::unique_ptr<CompilerInstance> DeviceCI;
4348
int SMVersion;
4449
llvm::SmallString<1024> PTXCode;
4550
llvm::SmallVector<char, 1024> FatbinContent;
4651
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
52+
CodeGenOptions &CodeGenOpts; // Intentionally a reference.
53+
const TargetOptions &TargetOpts;
4754
};
4855

4956
} // namespace clang

‎clang/lib/Interpreter/IncrementalExecutor.cpp

+1-1
Original file line numberDiff line numberDiff line change
@@ -118,4 +118,4 @@ IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
118118
return SymOrErr->getAddress();
119119
}
120120

121-
} // end namespace clang
121+
} // namespace clang

0 commit comments

Comments
 (0)
Please sign in to comment.