clang  15.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  return std::move(Clang);
120 }
121 
122 } // anonymous namespace
123 
125 IncrementalCompilerBuilder::create(std::vector<const char *> &ClangArgv) {
126 
127  // If we don't know ClangArgv0 or the address of main() at this point, try
128  // to guess it anyway (it's possible on some platforms).
129  std::string MainExecutableName =
130  llvm::sys::fs::getMainExecutable(nullptr, nullptr);
131 
132  ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
133 
134  // Prepending -c to force the driver to do something if no action was
135  // specified. By prepending we allow users to override the default
136  // action and use other actions in incremental mode.
137  // FIXME: Print proper driver diagnostics if the driver flags are wrong.
138  ClangArgv.insert(ClangArgv.begin() + 1, "-c");
139 
140  if (!llvm::is_contained(ClangArgv, " -x")) {
141  // We do C++ by default; append right after argv[0] if no "-x" given
142  ClangArgv.push_back("-x");
143  ClangArgv.push_back("c++");
144  }
145 
146  // Put a dummy C++ file on to ensure there's at least one compile job for the
147  // driver to construct.
148  ClangArgv.push_back("<<< inputs >>>");
149 
150  // Buffer diagnostics from argument parsing so that we can output them using a
151  // well formed diagnostic object.
154  CreateAndPopulateDiagOpts(ClangArgv);
155  TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
156  DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
157 
158  driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0],
159  llvm::sys::getProcessTriple(), Diags);
160  Driver.setCheckInputsExist(false); // the input comes from mem buffers
161  llvm::ArrayRef<const char *> RF = llvm::makeArrayRef(ClangArgv);
162  std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
163 
164  if (Compilation->getArgs().hasArg(driver::options::OPT_v))
165  Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
166 
167  auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
168  if (auto Err = ErrOrCC1Args.takeError())
169  return std::move(Err);
170 
171  return CreateCI(**ErrOrCC1Args);
172 }
173 
174 Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
175  llvm::Error &Err) {
176  llvm::ErrorAsOutParameter EAO(&Err);
177  auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
178  TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
179  IncrParser = std::make_unique<IncrementalParser>(std::move(CI),
180  *TSCtx->getContext(), Err);
181 }
182 
184 
186 Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
187  llvm::Error Err = llvm::Error::success();
188  auto Interp =
189  std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
190  if (Err)
191  return std::move(Err);
192  return std::move(Interp);
193 }
194 
196  return IncrParser->getCI();
197 }
198 
199 const llvm::orc::LLJIT *Interpreter::getExecutionEngine() const {
200  if (IncrExecutor)
201  return IncrExecutor->getExecutionEngine();
202  return nullptr;
203 }
204 
206 Interpreter::Parse(llvm::StringRef Code) {
207  return IncrParser->Parse(Code);
208 }
209 
211  assert(T.TheModule);
212  if (!IncrExecutor) {
213  const llvm::Triple &Triple =
215  llvm::Error Err = llvm::Error::success();
216  IncrExecutor = std::make_unique<IncrementalExecutor>(*TSCtx, Err, Triple);
217 
218  if (Err)
219  return Err;
220  }
221  // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
222  if (auto Err = IncrExecutor->addModule(std::move(T.TheModule)))
223  return Err;
224 
225  if (auto Err = IncrExecutor->runCtors())
226  return Err;
227 
228  return llvm::Error::success();
229 }
230 
233  if (!IncrExecutor)
234  return llvm::make_error<llvm::StringError>("Operation failed. "
235  "No execution engine",
236  std::error_code());
237  llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
238  return getSymbolAddress(MangledName);
239 }
240 
242 Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
243  if (!IncrExecutor)
244  return llvm::make_error<llvm::StringError>("Operation failed. "
245  "No execution engine",
246  std::error_code());
247 
248  return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
249 }
250 
252 Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) 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(Name, IncrementalExecutor::LinkerName);
259 }
clang::Interpreter::Parse
llvm::Expected< PartialTranslationUnit & > Parse(llvm::StringRef Code)
Definition: Interpreter.cpp:206
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:252
clang::driver::JobList::begin
iterator begin()
Definition: Job.h:291
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
ModuleBuilder.h
Interpreter.h
llvm::Expected
Definition: LLVM.h:41
clang::IncrementalExecutor::IRName
@ IRName
Definition: IncrementalExecutor.h:38
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:195
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
Tool.h
clang::driver::JobList
JobList - A sequence of jobs to perform.
Definition: Job.h:267
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:680
clang::CompilerInstance::getASTContext
ASTContext & getASTContext() const
Definition: CompilerInstance.h:462
clang::Interpreter::getSymbolAddress
llvm::Expected< llvm::JITTargetAddress > getSymbolAddress(GlobalDecl GD) const
Definition: Interpreter.cpp:232
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:125
Cmd
CompileCommand Cmd
Definition: InterpolatingCompilationDatabase.cpp:130
clang::TargetInfo::getTriple
const llvm::Triple & getTriple() const
Returns the target triple of the primary target.
Definition: TargetInfo.h:1160
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:38
llvm::ArrayRef< const char * >
IncrementalParser.h
IncrementalExecutor.h
clang::driver::JobList::size
size_type size() const
Definition: Job.h:290
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:199
clang::ASTContext::getTargetInfo
const TargetInfo & getTargetInfo() const
Definition: ASTContext.h:768
clang::TextDiagnosticBuffer
Definition: TextDiagnosticBuffer.h:25
clang::Interpreter::Execute
llvm::Error Execute(PartialTranslationUnit &T)
Definition: Interpreter.cpp:210
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:71
clang::Interpreter::~Interpreter
~Interpreter()
Definition: Interpreter.cpp:183
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:2333
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:2938
PreprocessorOptions.h
clang::Interpreter::create
static llvm::Expected< std::unique_ptr< Interpreter > > create(std::unique_ptr< CompilerInstance > CI)
Definition: Interpreter.cpp:186
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:4527
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:366
clang::driver::Driver::BuildCompilation
Compilation * BuildCompilation(ArrayRef< const char * > Args)
BuildCompilation - Construct a compilation object for a command line argument vector.
Definition: Driver.cpp:1113