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/CodeGen/ModuleBuilder.h"
14+ #include " clang/Frontend/CompilerInstance.h"
15+ #include " clang/Frontend/FrontendOptions.h"
16+ #include " clang/FrontendTool/Utils.h"
17+ #include " clang/Interpreter/Interpreter.h"
18+ #include " clang/Lex/PreprocessorOptions.h"
19+ #include " clang/Sema/Sema.h"
20+ #include " llvm/IR/Module.h"
21+ #include " llvm/Support/Error.h"
22+ #include " llvm/Support/ErrorHandling.h"
23+
24+ namespace clang {
25+ IncrementalAction::IncrementalAction (CompilerInstance &CI,
26+ llvm::LLVMContext &LLVMCtx,
27+ llvm::Error &Err, Interpreter &I,
28+ std::unique_ptr<ASTConsumer> Consumer)
29+ : WrapperFrontendAction([&]() {
30+ llvm::ErrorAsOutParameter EAO (&Err);
31+ std::unique_ptr<FrontendAction> Act;
32+ switch (CI.getFrontendOpts ().ProgramAction ) {
33+ default :
34+ Err = llvm::createStringError (
35+ std::errc::state_not_recoverable,
36+ " Driver initialization failed. "
37+ " Incremental mode for action %d is not supported" ,
38+ CI.getFrontendOpts ().ProgramAction );
39+ return Act;
40+ case frontend::ASTDump:
41+ case frontend::ASTPrint:
42+ case frontend::ParseSyntaxOnly:
43+ Act = CreateFrontendAction (CI);
44+ break ;
45+ case frontend::PluginAction:
46+ case frontend::EmitAssembly:
47+ case frontend::EmitBC:
48+ case frontend::EmitObj:
49+ case frontend::PrintPreprocessedInput:
50+ case frontend::EmitLLVMOnly:
51+ Act.reset (new EmitLLVMOnlyAction (&LLVMCtx));
52+ break ;
53+ }
54+ return Act;
55+ }()),
56+ Interp (I), CI(CI), Consumer(std::move(Consumer)) {}
57+
58+ std::unique_ptr<ASTConsumer>
59+ IncrementalAction::CreateASTConsumer (CompilerInstance &CI, StringRef InFile) {
60+ std::unique_ptr<ASTConsumer> C =
61+ WrapperFrontendAction::CreateASTConsumer (CI, InFile);
62+
63+ if (Consumer) {
64+ std::vector<std::unique_ptr<ASTConsumer>> Cs;
65+ Cs.push_back (std::move (Consumer));
66+ Cs.push_back (std::move (C));
67+ return std::make_unique<MultiplexConsumer>(std::move (Cs));
68+ }
69+
70+ return std::make_unique<InProcessPrintingASTConsumer>(std::move (C), Interp);
71+ }
72+
73+ void IncrementalAction::ExecuteAction () {
74+ WrapperFrontendAction::ExecuteAction ();
75+ getCompilerInstance ().getSema ().CurContext = nullptr ;
76+ }
77+
78+ void IncrementalAction::EndSourceFile () {
79+ if (IsTerminating && getWrapped ())
80+ WrapperFrontendAction::EndSourceFile ();
81+ }
82+
83+ void IncrementalAction::FinalizeAction () {
84+ assert (!IsTerminating && " Already finalized!" );
85+ IsTerminating = true ;
86+ EndSourceFile ();
87+ }
88+
89+ void IncrementalAction::CacheCodeGenModule () {
90+ CachedInCodeGenModule = GenModule ();
91+ }
92+
93+ llvm::Module *IncrementalAction::getCachedCodeGenModule () const {
94+ return CachedInCodeGenModule.get ();
95+ }
96+
97+ std::unique_ptr<llvm::Module> IncrementalAction::GenModule () {
98+ static unsigned ID = 0 ;
99+ if (CodeGenerator *CG = getCodeGen ()) {
100+ // Clang's CodeGen is designed to work with a single llvm::Module. In many
101+ // cases for convenience various CodeGen parts have a reference to the
102+ // llvm::Module (TheModule or Module) which does not change when a new
103+ // module is pushed. However, the execution engine wants to take ownership
104+ // of the module which does not map well to CodeGen's design. To work this
105+ // around we created an empty module to make CodeGen happy. We should make
106+ // sure it always stays empty.
107+ assert (((!CachedInCodeGenModule ||
108+ !CI.getPreprocessorOpts ().Includes .empty ()) ||
109+ (CachedInCodeGenModule->empty () &&
110+ CachedInCodeGenModule->global_empty () &&
111+ CachedInCodeGenModule->alias_empty () &&
112+ CachedInCodeGenModule->ifunc_empty ())) &&
113+ " CodeGen wrote to a readonly module" );
114+ std::unique_ptr<llvm::Module> M (CG->ReleaseModule ());
115+ CG->StartModule (" incr_module_" + std::to_string (ID++), M->getContext ());
116+ return M;
117+ }
118+ return nullptr ;
119+ }
120+
121+ CodeGenerator *IncrementalAction::getCodeGen () const {
122+ FrontendAction *WrappedAct = getWrapped ();
123+ if (!WrappedAct || !WrappedAct->hasIRSupport ())
124+ return nullptr ;
125+ return static_cast <CodeGenAction *>(WrappedAct)->getCodeGenerator ();
126+ }
127+
128+ InProcessPrintingASTConsumer::InProcessPrintingASTConsumer (
129+ std::unique_ptr<ASTConsumer> C, Interpreter &I)
130+ : MultiplexConsumer(std::move(C)), Interp(I) {}
131+
132+ bool InProcessPrintingASTConsumer::HandleTopLevelDecl (DeclGroupRef DGR) {
133+ if (DGR.isNull ())
134+ return true ;
135+
136+ for (Decl *D : DGR)
137+ if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
138+ if (TLSD && TLSD->isSemiMissing ()) {
139+ auto ExprOrErr = Interp.convertExprToValue (cast<Expr>(TLSD->getStmt ()));
140+ if (llvm::Error E = ExprOrErr.takeError ()) {
141+ llvm::logAllUnhandledErrors (std::move (E), llvm::errs (),
142+ " Value printing failed: " );
143+ return false ; // abort parsing
144+ }
145+ TLSD->setStmt (*ExprOrErr);
146+ }
147+
148+ return MultiplexConsumer::HandleTopLevelDecl (DGR);
149+ }
150+
151+ } // namespace clang
0 commit comments