Skip to content

Commit bbf41f4

Browse files
committed
Delegate Codegen to IncrementalParser
1 parent d10dab4 commit bbf41f4

10 files changed

+294
-207
lines changed

clang/include/clang/Interpreter/Interpreter.h

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

3838
class CompilerInstance;
39-
class CodeGenerator;
4039
class CXXRecordDecl;
4140
class Decl;
4241
class IncrementalExecutor;
@@ -109,10 +108,6 @@ class Interpreter {
109108
// printing happens, it's in an invalid state.
110109
Value LastValue;
111110

112-
/// When CodeGen is created the first llvm::Module gets cached in many places
113-
/// and we must keep it alive.
114-
std::unique_ptr<llvm::Module> CachedInCodeGenModule;
115-
116111
/// Compiler instance performing the incremental compilation.
117112
std::unique_ptr<CompilerInstance> CI;
118113

@@ -179,12 +174,6 @@ class Interpreter {
179174
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
180175
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);
181176

182-
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
183-
std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
184-
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
185-
std::unique_ptr<llvm::Module> M = {},
186-
IncrementalAction *Action = nullptr);
187-
188177
// A cache for the compiled destructors used to for de-allocation of managed
189178
// clang::Values.
190179
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;

clang/lib/Interpreter/CMakeLists.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ endif()
2222
add_clang_library(clangInterpreter
2323
DeviceOffload.cpp
2424
CodeCompletion.cpp
25+
IncrementalAction.cpp
2526
IncrementalExecutor.cpp
2627
IncrementalParser.cpp
2728
Interpreter.cpp

clang/lib/Interpreter/DeviceOffload.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -26,10 +26,10 @@ namespace clang {
2626

2727
IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
2828
std::unique_ptr<CompilerInstance> DeviceInstance,
29-
CompilerInstance &HostInstance,
29+
CompilerInstance &HostInstance, IncrementalAction *DeviceAct,
3030
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
31-
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs)
32-
: IncrementalParser(*DeviceInstance, Err), PTUs(PTUs), VFS(FS),
31+
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
32+
: IncrementalParser(*DeviceInstance, DeviceAct, Err, PTUs), VFS(FS),
3333
CodeGenOpts(HostInstance.getCodeGenOpts()),
3434
TargetOpts(DeviceInstance->getTargetOpts()) {
3535
if (Err)

clang/lib/Interpreter/DeviceOffload.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -22,16 +22,16 @@ struct PartialTranslationUnit;
2222
class CompilerInstance;
2323
class CodeGenOptions;
2424
class TargetOptions;
25+
class IncrementalAction;
2526

2627
class IncrementalCUDADeviceParser : public IncrementalParser {
27-
const std::list<PartialTranslationUnit> &PTUs;
2828

2929
public:
3030
IncrementalCUDADeviceParser(
3131
std::unique_ptr<CompilerInstance> DeviceInstance,
32-
CompilerInstance &HostInstance,
32+
CompilerInstance &HostInstance, IncrementalAction *DeviceAct,
3333
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
34-
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs);
34+
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs);
3535

3636
// Generate PTX for the last PTU.
3737
llvm::Expected<llvm::StringRef> GeneratePTX();
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
//===--- IncrementalAction.h - Incremental Frontend Action -*- 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+
#include "IncrementalAction.h"
10+
11+
#include "clang/AST/ASTConsumer.h"
12+
#include "clang/CodeGen/CodeGenAction.h"
13+
#include "clang/Frontend/CompilerInstance.h"
14+
#include "clang/Frontend/FrontendOptions.h"
15+
#include "clang/FrontendTool/Utils.h"
16+
#include "clang/Interpreter/Interpreter.h"
17+
#include "clang/Sema/Sema.h"
18+
#include "llvm/Support/Error.h"
19+
#include "llvm/Support/ErrorHandling.h"
20+
21+
namespace clang {
22+
IncrementalAction::IncrementalAction(CompilerInstance &CI,
23+
llvm::LLVMContext &LLVMCtx,
24+
llvm::Error &Err, Interpreter &I,
25+
std::unique_ptr<ASTConsumer> Consumer)
26+
: WrapperFrontendAction([&]() {
27+
llvm::ErrorAsOutParameter EAO(&Err);
28+
std::unique_ptr<FrontendAction> Act;
29+
switch (CI.getFrontendOpts().ProgramAction) {
30+
default:
31+
Err = llvm::createStringError(
32+
std::errc::state_not_recoverable,
33+
"Driver initialization failed. "
34+
"Incremental mode for action %d is not supported",
35+
CI.getFrontendOpts().ProgramAction);
36+
return Act;
37+
case frontend::ASTDump:
38+
case frontend::ASTPrint:
39+
case frontend::ParseSyntaxOnly:
40+
Act = CreateFrontendAction(CI);
41+
break;
42+
case frontend::PluginAction:
43+
case frontend::EmitAssembly:
44+
case frontend::EmitBC:
45+
case frontend::EmitObj:
46+
case frontend::PrintPreprocessedInput:
47+
case frontend::EmitLLVMOnly:
48+
Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
49+
break;
50+
}
51+
return Act;
52+
}()),
53+
Interp(I), Consumer(std::move(Consumer)) {}
54+
55+
std::unique_ptr<ASTConsumer>
56+
IncrementalAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
57+
std::unique_ptr<ASTConsumer> C =
58+
WrapperFrontendAction::CreateASTConsumer(CI, InFile);
59+
60+
if (Consumer) {
61+
std::vector<std::unique_ptr<ASTConsumer>> Cs;
62+
Cs.push_back(std::move(Consumer));
63+
Cs.push_back(std::move(C));
64+
return std::make_unique<MultiplexConsumer>(std::move(Cs));
65+
}
66+
67+
return std::make_unique<InProcessPrintingASTConsumer>(std::move(C), Interp);
68+
}
69+
70+
void IncrementalAction::ExecuteAction() {
71+
WrapperFrontendAction::ExecuteAction();
72+
getCompilerInstance().getSema().CurContext = nullptr;
73+
}
74+
75+
void IncrementalAction::EndSourceFile() {
76+
if (IsTerminating && getWrapped())
77+
WrapperFrontendAction::EndSourceFile();
78+
}
79+
80+
void IncrementalAction::FinalizeAction() {
81+
assert(!IsTerminating && "Already finalized!");
82+
IsTerminating = true;
83+
EndSourceFile();
84+
}
85+
86+
InProcessPrintingASTConsumer::InProcessPrintingASTConsumer(
87+
std::unique_ptr<ASTConsumer> C, Interpreter &I)
88+
: MultiplexConsumer(std::move(C)), Interp(I) {}
89+
90+
bool InProcessPrintingASTConsumer::HandleTopLevelDecl(DeclGroupRef DGR) {
91+
if (DGR.isNull())
92+
return true;
93+
94+
for (Decl *D : DGR)
95+
if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
96+
if (TLSD && TLSD->isSemiMissing()) {
97+
auto ExprOrErr =
98+
Interp.ExtractValueFromExpr(cast<Expr>(TLSD->getStmt()));
99+
if (llvm::Error E = ExprOrErr.takeError()) {
100+
llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),
101+
"Value printing failed: ");
102+
return false; // abort parsing
103+
}
104+
TLSD->setStmt(*ExprOrErr);
105+
}
106+
107+
return MultiplexConsumer::HandleTopLevelDecl(DGR);
108+
}
109+
110+
} // namespace clang
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
//===--- IncrementalAction.h - Incremental Frontend Action -*- 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+
#ifndef LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H
10+
#define LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H
11+
12+
#include "clang/Frontend/FrontendActions.h"
13+
#include "clang/Frontend/MultiplexConsumer.h"
14+
15+
namespace clang {
16+
17+
class Interpreter;
18+
19+
/// A custom action enabling the incremental processing functionality.
20+
///
21+
/// The usual \p FrontendAction expects one call to ExecuteAction and once it
22+
/// sees a call to \p EndSourceFile it deletes some of the important objects
23+
/// such as \p Preprocessor and \p Sema assuming no further input will come.
24+
///
25+
/// \p IncrementalAction ensures it keep its underlying action's objects alive
26+
/// as long as the \p IncrementalParser needs them.
27+
///
28+
class IncrementalAction : public WrapperFrontendAction {
29+
private:
30+
bool IsTerminating = false;
31+
Interpreter &Interp;
32+
std::unique_ptr<ASTConsumer> Consumer;
33+
34+
public:
35+
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
36+
llvm::Error &Err, Interpreter &I,
37+
std::unique_ptr<ASTConsumer> Consumer = nullptr);
38+
39+
FrontendAction *getWrapped() const { return WrappedAction.get(); }
40+
41+
TranslationUnitKind getTranslationUnitKind() override {
42+
return TU_Incremental;
43+
}
44+
45+
std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
46+
StringRef InFile) override;
47+
48+
void ExecuteAction() override;
49+
50+
// Do not terminate after processing the input. This allows us to keep various
51+
// clang objects alive and to incrementally grow the current TU.
52+
void EndSourceFile() override;
53+
54+
void FinalizeAction();
55+
};
56+
57+
class InProcessPrintingASTConsumer final : public MultiplexConsumer {
58+
Interpreter &Interp;
59+
60+
public:
61+
InProcessPrintingASTConsumer(std::unique_ptr<ASTConsumer> C, Interpreter &I);
62+
63+
bool HandleTopLevelDecl(DeclGroupRef DGR) override;
64+
};
65+
66+
} // end namespace clang
67+
68+
#endif // LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H

clang/lib/Interpreter/IncrementalParser.cpp

Lines changed: 65 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -11,27 +11,36 @@
1111
//===----------------------------------------------------------------------===//
1212

1313
#include "IncrementalParser.h"
14+
#include "IncrementalAction.h"
1415

1516
#include "clang/AST/DeclContextInternals.h"
17+
#include "clang/CodeGen/CodeGenAction.h"
18+
#include "clang/CodeGen/ModuleBuilder.h"
1619
#include "clang/Frontend/CompilerInstance.h"
20+
#include "clang/Frontend/FrontendAction.h"
1721
#include "clang/Interpreter/PartialTranslationUnit.h"
22+
#include "clang/Lex/PreprocessorOptions.h"
1823
#include "clang/Parse/Parser.h"
1924
#include "clang/Sema/Sema.h"
25+
#include "llvm/IR/Module.h"
2026
#include "llvm/Support/CrashRecoveryContext.h"
2127
#include "llvm/Support/Error.h"
2228

2329
#include <sstream>
2430

31+
#define DEBUG_TYPE "clang-repl"
32+
2533
namespace clang {
2634

2735
// IncrementalParser::IncrementalParser() {}
2836

2937
IncrementalParser::IncrementalParser(CompilerInstance &Instance,
30-
llvm::Error &Err)
31-
: S(Instance.getSema()) {
38+
IncrementalAction *Act, llvm::Error &Err,
39+
std::list<PartialTranslationUnit> &PTUs)
40+
: S(Instance.getSema()), CI(Instance), Act(Act), PTUs(PTUs) {
3241
llvm::ErrorAsOutParameter EAO(&Err);
3342
Consumer = &S.getASTConsumer();
34-
P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
43+
P = std::make_unique<Parser>(S.getPreprocessor(), S, /*SkipBodies=*/false);
3544
P->Initialize();
3645
}
3746

@@ -185,4 +194,57 @@ void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) {
185194
}
186195
}
187196

197+
PartialTranslationUnit &
198+
IncrementalParser::RegisterPTU(TranslationUnitDecl *TU,
199+
std::unique_ptr<llvm::Module> M /*={}*/) {
200+
PTUs.emplace_back(PartialTranslationUnit());
201+
PartialTranslationUnit &LastPTU = PTUs.back();
202+
LastPTU.TUPart = TU;
203+
204+
if (!M)
205+
M = GenModule();
206+
207+
assert((!getCodeGen() || M) && "Must have a llvm::Module at this point");
208+
209+
LastPTU.TheModule = std::move(M);
210+
LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1
211+
<< ": [TU=" << LastPTU.TUPart);
212+
if (LastPTU.TheModule)
213+
LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("
214+
<< LastPTU.TheModule->getName() << ")");
215+
LLVM_DEBUG(llvm::dbgs() << "]\n");
216+
return LastPTU;
217+
}
218+
219+
std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
220+
static unsigned ID = 0;
221+
if (CodeGenerator *CG = getCodeGen()) {
222+
// Clang's CodeGen is designed to work with a single llvm::Module. In many
223+
// cases for convenience various CodeGen parts have a reference to the
224+
// llvm::Module (TheModule or Module) which does not change when a new
225+
// module is pushed. However, the execution engine wants to take ownership
226+
// of the module which does not map well to CodeGen's design. To work this
227+
// around we created an empty module to make CodeGen happy. We should make
228+
// sure it always stays empty.
229+
assert(((!CachedInCodeGenModule ||
230+
!CI.getPreprocessorOpts().Includes.empty()) ||
231+
(CachedInCodeGenModule->empty() &&
232+
CachedInCodeGenModule->global_empty() &&
233+
CachedInCodeGenModule->alias_empty() &&
234+
CachedInCodeGenModule->ifunc_empty())) &&
235+
"CodeGen wrote to a readonly module");
236+
std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
237+
CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
238+
return M;
239+
}
240+
return nullptr;
241+
}
242+
243+
CodeGenerator *IncrementalParser::getCodeGen() const {
244+
FrontendAction *WrappedAct = Act->getWrapped();
245+
if (!WrappedAct->hasIRSupport())
246+
return nullptr;
247+
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
248+
}
249+
188250
} // end namespace clang

0 commit comments

Comments
 (0)