clang  16.0.0git
Interpreter.cpp
Go to the documentation of this file.
1 //===------ Interpreter.cpp - Incremental Compilation and Execution -------===//
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 // This file implements the component which performs incremental code
10 // compilation and execution.
11 //
12 //===----------------------------------------------------------------------===//
13 
15 
16 #include "IncrementalExecutor.h"
17 #include "IncrementalParser.h"
18 
19 #include "clang/AST/ASTContext.h"
20 #include "clang/Basic/TargetInfo.h"
24 #include "clang/Driver/Driver.h"
25 #include "clang/Driver/Job.h"
26 #include "clang/Driver/Options.h"
27 #include "clang/Driver/Tool.h"
31 
32 #include "llvm/IR/Module.h"
33 #include "llvm/Support/Errc.h"
34 #include "llvm/Support/Host.h"
35 
36 using namespace clang;
37 
38 // FIXME: Figure out how to unify with namespace init_convenience from
39 // tools/clang-import-test/clang-import-test.cpp
40 namespace {
41 /// Retrieves the clang CC1 specific flags out of the compilation's jobs.
42 /// \returns NULL on error.
44 GetCC1Arguments(DiagnosticsEngine *Diagnostics,
45  driver::Compilation *Compilation) {
46  // We expect to get back exactly one Command job, if we didn't something
47  // failed. Extract that job from the Compilation.
48  const driver::JobList &Jobs = Compilation->getJobs();
49  if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))
50  return llvm::createStringError(llvm::errc::not_supported,
51  "Driver initialization failed. "
52  "Unable to create a driver job");
53 
54  // The one job we find should be to invoke clang again.
55  const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));
56  if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
57  return llvm::createStringError(llvm::errc::not_supported,
58  "Driver initialization failed");
59 
60  return &Cmd->getArguments();
61 }
62 
64 CreateCI(const llvm::opt::ArgStringList &Argv) {
65  std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
67 
68  // Register the support for object-file-wrapped Clang modules.
69  // FIXME: Clang should register these container operations automatically.
70  auto PCHOps = Clang->getPCHContainerOperations();
71  PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
72  PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
73 
74  // Buffer diagnostics from argument parsing so that we can output them using
75  // a well formed diagnostic object.
77  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
78  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
80  Clang->getInvocation(), llvm::makeArrayRef(Argv.begin(), Argv.size()),
81  Diags);
82 
83  // Infer the builtin include path if unspecified.
84  if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
85  Clang->getHeaderSearchOpts().ResourceDir.empty())
86  Clang->getHeaderSearchOpts().ResourceDir =
87  CompilerInvocation::GetResourcesPath(Argv[0], nullptr);
88 
89  // Create the actual diagnostics engine.
90  Clang->createDiagnostics();
91  if (!Clang->hasDiagnostics())
92  return llvm::createStringError(llvm::errc::not_supported,
93  "Initialization failed. "
94  "Unable to create diagnostics engine");
95 
96  DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
97  if (!Success)
98  return llvm::createStringError(llvm::errc::not_supported,
99  "Initialization failed. "
100  "Unable to flush diagnostics");
101 
102  // FIXME: Merge with CompilerInstance::ExecuteAction.
103  llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
104  Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
105 
106  Clang->setTarget(TargetInfo::CreateTargetInfo(
107  Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
108  if (!Clang->hasTarget())
109  return llvm::createStringError(llvm::errc::not_supported,
110  "Initialization failed. "
111  "Target is missing");
112 
113  Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts());
114 
115  // Don't clear the AST before backend codegen since we do codegen multiple
116  // times, reusing the same AST.
117  Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
118 
119  Clang->getFrontendOpts().DisableFree = false;
120  Clang->getCodeGenOpts().DisableFree = false;
121 
122  return std::move(Clang);
123 }
124 
125 } // anonymous namespace
126 
128 IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
129 
130  // If we don't know ClangArgv0 or the address of main() at this point, try
131  // to guess it anyway (it's possible on some platforms).
132  std::string MainExecutableName =
133  llvm::sys::fs::getMainExecutable(nullptr, nullptr);
134 
135  ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
136 
137  // Prepending -c to force the driver to do something if no action was
138  // specified. By prepending we allow users to override the default
139  // action and use other actions in incremental mode.
140  // FIXME: Print proper driver diagnostics if the driver flags are wrong.
141  ClangArgv.insert(ClangArgv.begin() + 1, "-c");
142 
143  if (!llvm::is_contained(ClangArgv, " -x")) {
144  // We do C++ by default; append right after argv[0] if no "-x" given
145  ClangArgv.push_back("-x");
146  ClangArgv.push_back("c++");
147  }
148 
149  // Put a dummy C++ file on to ensure there's at least one compile job for the
150  // driver to construct.
151  ClangArgv.push_back("<<< inputs >>>");
152 
153  // Buffer diagnostics from argument parsing so that we can output them using a
154  // well formed diagnostic object.
157  CreateAndPopulateDiagOpts(ClangArgv);
158  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
159  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
160 
161  driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
162  llvm::sys::getProcessTriple(), Diags);
163  Driver.setCheckInputsExist(false); // the input comes from mem buffers
164  llvm::ArrayRef<const char *> RF = llvm::makeArrayRef(ClangArgv);
165  std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
166 
167  if (Compilation->getArgs().hasArg(driver::options::OPT_v))
168  Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
169 
170  auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
171  if (auto Err = ErrOrCC1Args.takeError())
172  return std::move(Err);
173 
174  return CreateCI(**ErrOrCC1Args);
175 }
176 
177 Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
178  llvm::Error &Err) {
179  llvm::ErrorAsOutParameter EAO(&Err);
180  auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
181  TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
182  IncrParser = std::make_unique<IncrementalParser>(std::move(CI),
183  *TSCtx->getContext(), Err);
184 }
185 
187  if (IncrExecutor) {
188  if (llvm::Error Err = IncrExecutor->cleanUp())
189  llvm::report_fatal_error(
190  llvm::Twine("Failed to clean up IncrementalExecutor: ") +
191  toString(std::move(Err)));
192  }
193 }
194 
196 Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
197  llvm::Error Err = llvm::Error::success();
198  auto Interp =
199  std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
200  if (Err)
201  return std::move(Err);
202  return std::move(Interp);
203 }
204 
206  return IncrParser->getCI();
207 }
208 
209 const llvm::orc::LLJIT *Interpreter::getExecutionEngine() const {
210  if (IncrExecutor)
211  return IncrExecutor->getExecutionEngine();
212  return nullptr;
213 }
214 
216 Interpreter::Parse(llvm::StringRef Code) {
217  return IncrParser->Parse(Code);
218 }
219 
221  assert(T.TheModule);
222  if (!IncrExecutor) {
223  const clang::TargetInfo &TI =
225  llvm::Error Err = llvm::Error::success();
226  IncrExecutor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, TI);
227 
228  if (Err)
229  return Err;
230  }
231  // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
232  if (auto Err = IncrExecutor->addModule(T))
233  return Err;
234 
235  if (auto Err = IncrExecutor->runCtors())
236  return Err;
237 
238  return llvm::Error::success();
239 }
240 
243  if (!IncrExecutor)
244  return llvm::make_error<llvm::StringError>("Operation failed. "
245  "No execution engine",
246  std::error_code());
247  llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
248  return getSymbolAddress(MangledName);
249 }
250 
252 Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
253  if (!IncrExecutor)
254  return llvm::make_error<llvm::StringError>("Operation failed. "
255  "No execution engine",
256  std::error_code());
257 
258  return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
259 }
260 
262 Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
263  if (!IncrExecutor)
264  return llvm::make_error<llvm::StringError>("Operation failed. "
265  "No execution engine",
266  std::error_code());
267 
268  return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
269 }
270 
271 llvm::Error Interpreter::Undo(unsigned N) {
272 
273  std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
274  if (N > PTUs.size())
275  return llvm::make_error<llvm::StringError>("Operation failed. "
276  "Too many undos",
277  std::error_code());
278  for (unsigned I = 0; I < N; I++) {
279  if (IncrExecutor) {
280  if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
281  return Err;
282  }
283 
284  IncrParser->CleanUpPTU(PTUs.back());
285  PTUs.pop_back();
286  }
287  return llvm::Error::success();
288 }
clang::Interpreter::Parse
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
Definition: Interpreter.cpp:216
Driver.h
string
string(SUBSTRING ${CMAKE_CURRENT_BINARY_DIR} 0 ${PATH_LIB_START} PATH_HEAD) string(SUBSTRING $
Definition: CMakeLists.txt:22
TargetInfo.h
clang::Interpreter::getSymbolAddressFromLinkerName
llvm::Expected< llvm::JITTargetAddress > getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const
Definition: Interpreter.cpp:262
clang::driver::JobList::begin
iterator begin()
Definition: Job.h:297
clang::driver::Compilation::getJobs
JobList & getJobs()
Definition: Compilation.h:214
clang::DiagnosticsEngine
Concrete class used by the front-end to report problems and issues.
Definition: Diagnostic.h:192
Job.h
clang::TargetInfo
Exposes information about the current target.
Definition: TargetInfo.h:205
ModuleBuilder.h
Interpreter.h
llvm::Expected
Definition: LLVM.h:41
clang::IncrementalExecutor::IRName
@ IRName
Definition: IncrementalExecutor.h:44
clang::format::ParseError::Success
@ Success
clang::PartialTranslationUnit::TheModule
std::unique_ptr< llvm::Module > TheModule
The llvm IR produced for the input.
Definition: PartialTranslationUnit.h:33
clang::Interpreter::getCompilerInstance
const CompilerInstance * getCompilerInstance() const
Definition: Interpreter.cpp:205
clang::GlobalDecl
GlobalDecl - represents a global declaration.
Definition: GlobalDecl.h:56
clang::Interpreter
Provides top-level interfaces for incremental compilation and execution.
Definition: Interpreter.h:48
Options.h
clang::threadSafety::sx::toString
std::string toString(const til::SExpr *E)
Definition: ThreadSafetyCommon.h:91
Tool.h
clang::driver::JobList
JobList - A sequence of jobs to perform.
Definition: Job.h:273
ASTContext.h
TextDiagnosticBuffer.h
clang::TargetInfo::CreateTargetInfo
static TargetInfo * CreateTargetInfo(DiagnosticsEngine &Diags, const std::shared_ptr< TargetOptions > &Opts)
Construct a target for the given options.
Definition: Targets.cpp:698
clang::CompilerInstance::getASTContext
ASTContext & getASTContext() const
Definition: CompilerInstance.h:462
clang::Interpreter::getSymbolAddress
llvm::Expected< llvm::JITTargetAddress > getSymbolAddress(GlobalDecl GD) const
Definition: Interpreter.cpp:242
clang::CompilerInstance
CompilerInstance - Helper class for managing a single instance of the Clang compiler.
Definition: CompilerInstance.h:72
clang::IncrementalCompilerBuilder::create
static llvm::Expected< std::unique_ptr< CompilerInstance > > create(std::vector< const char * > &ClangArgv)
Definition: Interpreter.cpp:128
Cmd
CompileCommand Cmd
Definition: InterpolatingCompilationDatabase.cpp:129
clang::Interpreter::Undo
llvm::Error Undo(unsigned N=1)
Undo N previous incremental inputs.
Definition: Interpreter.cpp:271
clang::driver::Command
Command - An executable path/name and argument vector to execute.
Definition: Job.h:106
Compilation.h
clang::IncrementalExecutor::LinkerName
@ LinkerName
Definition: IncrementalExecutor.h:44
llvm::ArrayRef< const char * >
IncrementalParser.h
IncrementalExecutor.h
clang::driver::JobList::size
size_type size() const
Definition: Job.h:296
clang::DiagnosticIDs
Used for handling and querying diagnostic IDs.
Definition: DiagnosticIDs.h:166
clang::driver::Compilation
Compilation - A set of tasks to perform for a single driver invocation.
Definition: Compilation.h:45
clang::Interpreter::getExecutionEngine
const llvm::orc::LLJIT * getExecutionEngine() const
Definition: Interpreter.cpp:209
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:773
clang::TextDiagnosticBuffer
Definition: TextDiagnosticBuffer.h:25
clang::Interpreter::Execute
llvm::Error Execute(PartialTranslationUnit &T)
Definition: Interpreter.cpp:220
clang
Definition: CalledOnceCheck.h:17
clang::driver::Driver
Driver - Encapsulate logic for constructing compilation processes from a set of gcc-driver-like comma...
Definition: Driver.h:75
clang::Interpreter::~Interpreter
~Interpreter()
Definition: Interpreter.cpp:186
clang::PartialTranslationUnit
The class keeps track of various objects created as part of processing incremental inputs.
Definition: PartialTranslationUnit.h:29
clang::TextDiagnosticBuffer::FlushDiagnostics
void FlushDiagnostics(DiagnosticsEngine &Diags) const
FlushDiagnostics - Flush the buffered diagnostics to an given diagnostic engine.
Definition: TextDiagnosticBuffer.cpp:53
clang::CreateAndPopulateDiagOpts
std::unique_ptr< DiagnosticOptions > CreateAndPopulateDiagOpts(ArrayRef< const char * > Argv)
Definition: CompilerInvocation.cpp:2345
CompilerInstance.h
clang::CompilerInvocation::GetResourcesPath
static std::string GetResourcesPath(const char *Argv0, void *MainAddr)
Get the directory where the compiler headers reside, relative to the compiler binary (found by the pa...
Definition: CompilerInvocation.cpp:2949
PreprocessorOptions.h
clang::Interpreter::create
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI)
Definition: Interpreter.cpp:196
clang::CompilerInvocation::CreateFromArgs
static bool CreateFromArgs(CompilerInvocation &Res, ArrayRef< const char * > CommandLineArgs, DiagnosticsEngine &Diags, const char *Argv0=nullptr)
Create a compiler invocation from a list of input options.
Definition: CompilerInvocation.cpp:4562
ObjectFilePCHContainerOperations.h
llvm::IntrusiveRefCntPtr
Definition: LLVM.h:47
clang::DiagnosticOptions
Options for controlling the compiler diagnostics engine.
Definition: DiagnosticOptions.h:70
clang::driver::Driver::setCheckInputsExist
void setCheckInputsExist(bool Value)
Definition: Driver.h:373
clang::driver::Driver::BuildCompilation
Compilation * BuildCompilation(ArrayRef< const char * > Args)
BuildCompilation - Construct a compilation object for a command line argument vector.
Definition: Driver.cpp:1146