819 lines · cpp
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-exception6//7//===----------------------------------------------------------------------===//8//9// This file implements the component which performs incremental code10// compilation and execution.11//12//===----------------------------------------------------------------------===//13 14#include "DeviceOffload.h"15#include "IncrementalAction.h"16#include "IncrementalExecutor.h"17#include "IncrementalParser.h"18#include "InterpreterUtils.h"19#include "llvm/Support/VirtualFileSystem.h"20#ifdef __EMSCRIPTEN__21#include "Wasm.h"22#include <dlfcn.h>23#endif // __EMSCRIPTEN__24 25#include "clang/AST/ASTConsumer.h"26#include "clang/AST/ASTContext.h"27#include "clang/AST/Mangle.h"28#include "clang/AST/TypeVisitor.h"29#include "clang/Basic/DiagnosticSema.h"30#include "clang/Basic/TargetInfo.h"31#include "clang/CodeGen/CodeGenAction.h"32#include "clang/CodeGen/ObjectFilePCHContainerWriter.h"33#include "clang/Driver/Compilation.h"34#include "clang/Driver/Driver.h"35#include "clang/Driver/Job.h"36#include "clang/Driver/Tool.h"37#include "clang/Frontend/CompilerInstance.h"38#include "clang/Frontend/FrontendAction.h"39#include "clang/Frontend/MultiplexConsumer.h"40#include "clang/Frontend/TextDiagnosticBuffer.h"41#include "clang/FrontendTool/Utils.h"42#include "clang/Interpreter/Interpreter.h"43#include "clang/Interpreter/Value.h"44#include "clang/Lex/PreprocessorOptions.h"45#include "clang/Options/OptionUtils.h"46#include "clang/Options/Options.h"47#include "clang/Sema/Lookup.h"48#include "clang/Serialization/ObjectFilePCHContainerReader.h"49#include "llvm/ExecutionEngine/JITSymbol.h"50#include "llvm/ExecutionEngine/Orc/EPCDynamicLibrarySearchGenerator.h"51#include "llvm/ExecutionEngine/Orc/LLJIT.h"52#include "llvm/IR/Module.h"53#include "llvm/Support/Errc.h"54#include "llvm/Support/ErrorHandling.h"55#include "llvm/Support/raw_ostream.h"56#include "llvm/TargetParser/Host.h"57#include "llvm/Transforms/Utils/Cloning.h" // for CloneModule58 59#define DEBUG_TYPE "clang-repl"60 61using namespace clang;62// FIXME: Figure out how to unify with namespace init_convenience from63// tools/clang-import-test/clang-import-test.cpp64namespace {65/// Retrieves the clang CC1 specific flags out of the compilation's jobs.66/// \returns NULL on error.67static llvm::Expected<const llvm::opt::ArgStringList *>68GetCC1Arguments(DiagnosticsEngine *Diagnostics,69 driver::Compilation *Compilation) {70 // We expect to get back exactly one Command job, if we didn't something71 // failed. Extract that job from the Compilation.72 const driver::JobList &Jobs = Compilation->getJobs();73 if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))74 return llvm::createStringError(llvm::errc::not_supported,75 "Driver initialization failed. "76 "Unable to create a driver job");77 78 // The one job we find should be to invoke clang again.79 const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));80 if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")81 return llvm::createStringError(llvm::errc::not_supported,82 "Driver initialization failed");83 84 return &Cmd->getArguments();85}86 87static llvm::Expected<std::unique_ptr<CompilerInstance>>88CreateCI(const llvm::opt::ArgStringList &Argv) {89 std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());90 91 // Register the support for object-file-wrapped Clang modules.92 // FIXME: Clang should register these container operations automatically.93 auto PCHOps = Clang->getPCHContainerOperations();94 PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());95 PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());96 97 // Buffer diagnostics from argument parsing so that we can output them using98 // a well formed diagnostic object.99 DiagnosticOptions DiagOpts;100 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;101 DiagnosticsEngine Diags(DiagnosticIDs::create(), DiagOpts, DiagsBuffer);102 bool Success = CompilerInvocation::CreateFromArgs(103 Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);104 105 // Infer the builtin include path if unspecified.106 if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&107 Clang->getHeaderSearchOpts().ResourceDir.empty())108 Clang->getHeaderSearchOpts().ResourceDir =109 GetResourcesPath(Argv[0], nullptr);110 111 Clang->createVirtualFileSystem();112 113 // Create the actual diagnostics engine.114 Clang->createDiagnostics();115 if (!Clang->hasDiagnostics())116 return llvm::createStringError(llvm::errc::not_supported,117 "Initialization failed. "118 "Unable to create diagnostics engine");119 120 DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());121 if (!Success)122 return llvm::createStringError(llvm::errc::not_supported,123 "Initialization failed. "124 "Unable to flush diagnostics");125 126 // FIXME: Merge with CompilerInstance::ExecuteAction.127 llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();128 Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);129 130 Clang->setTarget(TargetInfo::CreateTargetInfo(131 Clang->getDiagnostics(), Clang->getInvocation().getTargetOpts()));132 if (!Clang->hasTarget())133 return llvm::createStringError(llvm::errc::not_supported,134 "Initialization failed. "135 "Target is missing");136 137 Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts(),138 Clang->getAuxTarget());139 140 // Don't clear the AST before backend codegen since we do codegen multiple141 // times, reusing the same AST.142 Clang->getCodeGenOpts().ClearASTBeforeBackend = false;143 144 Clang->getFrontendOpts().DisableFree = false;145 Clang->getCodeGenOpts().DisableFree = false;146 return std::move(Clang);147}148 149} // anonymous namespace150 151namespace clang {152 153llvm::Expected<std::unique_ptr<CompilerInstance>>154IncrementalCompilerBuilder::create(std::string TT,155 std::vector<const char *> &ClangArgv) {156 157 // If we don't know ClangArgv0 or the address of main() at this point, try158 // to guess it anyway (it's possible on some platforms).159 std::string MainExecutableName =160 llvm::sys::fs::getMainExecutable(nullptr, nullptr);161 162 ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());163 164 // Prepending -c to force the driver to do something if no action was165 // specified. By prepending we allow users to override the default166 // action and use other actions in incremental mode.167 // FIXME: Print proper driver diagnostics if the driver flags are wrong.168 // We do C++ by default; append right after argv[0] if no "-x" given169 ClangArgv.insert(ClangArgv.end(), "-Xclang");170 ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");171 ClangArgv.insert(ClangArgv.end(), "-c");172 173 // Put a dummy C++ file on to ensure there's at least one compile job for the174 // driver to construct.175 ClangArgv.push_back("<<< inputs >>>");176 177 // Buffer diagnostics from argument parsing so that we can output them using a178 // well formed diagnostic object.179 std::unique_ptr<DiagnosticOptions> DiagOpts =180 CreateAndPopulateDiagOpts(ClangArgv);181 TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;182 DiagnosticsEngine Diags(DiagnosticIDs::create(), *DiagOpts, DiagsBuffer);183 184 driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);185 Driver.setCheckInputsExist(false); // the input comes from mem buffers186 llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);187 std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));188 189 if (Compilation->getArgs().hasArg(options::OPT_v))190 Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);191 192 auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());193 if (auto Err = ErrOrCC1Args.takeError())194 return std::move(Err);195 196 return CreateCI(**ErrOrCC1Args);197}198 199llvm::Expected<std::unique_ptr<CompilerInstance>>200IncrementalCompilerBuilder::CreateCpp() {201 std::vector<const char *> Argv;202 Argv.reserve(5 + 1 + UserArgs.size());203 Argv.push_back("-xc++");204#ifdef __EMSCRIPTEN__205 Argv.push_back("-target");206 Argv.push_back("wasm32-unknown-emscripten");207 Argv.push_back("-fvisibility=default");208#endif209 llvm::append_range(Argv, UserArgs);210 211 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();212 return IncrementalCompilerBuilder::create(TT, Argv);213}214 215llvm::Expected<std::unique_ptr<CompilerInstance>>216IncrementalCompilerBuilder::createCuda(bool device) {217 std::vector<const char *> Argv;218 Argv.reserve(5 + 4 + UserArgs.size());219 220 Argv.push_back("-xcuda");221 if (device)222 Argv.push_back("--cuda-device-only");223 else224 Argv.push_back("--cuda-host-only");225 226 std::string SDKPathArg = "--cuda-path=";227 if (!CudaSDKPath.empty()) {228 SDKPathArg += CudaSDKPath;229 Argv.push_back(SDKPathArg.c_str());230 }231 232 std::string ArchArg = "--offload-arch=";233 if (!OffloadArch.empty()) {234 ArchArg += OffloadArch;235 Argv.push_back(ArchArg.c_str());236 }237 238 llvm::append_range(Argv, UserArgs);239 240 std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();241 return IncrementalCompilerBuilder::create(TT, Argv);242}243 244llvm::Expected<std::unique_ptr<CompilerInstance>>245IncrementalCompilerBuilder::CreateCudaDevice() {246 return IncrementalCompilerBuilder::createCuda(true);247}248 249llvm::Expected<std::unique_ptr<CompilerInstance>>250IncrementalCompilerBuilder::CreateCudaHost() {251 return IncrementalCompilerBuilder::createCuda(false);252}253 254Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,255 llvm::Error &ErrOut,256 std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder,257 std::unique_ptr<clang::ASTConsumer> Consumer,258 JITConfig Config)259 : JITBuilder(std::move(JITBuilder)) {260 CI = std::move(Instance);261 llvm::ErrorAsOutParameter EAO(&ErrOut);262 auto LLVMCtx = std::make_unique<llvm::LLVMContext>();263 TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));264 265 Act = TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {266 return std::make_unique<IncrementalAction>(*CI, *Ctx, ErrOut, *this,267 std::move(Consumer));268 });269 270 if (ErrOut)271 return;272 CI->ExecuteAction(*Act);273 274 IncrParser =275 std::make_unique<IncrementalParser>(*CI, Act.get(), ErrOut, PTUs);276 277 if (ErrOut)278 return;279 280 if (Act->getCodeGen()) {281 Act->CacheCodeGenModule();282 // The initial PTU is filled by `-include`/`-include-pch` or by CUDA283 // includes automatically.284 if (!CI->getPreprocessorOpts().Includes.empty() ||285 !CI->getPreprocessorOpts().ImplicitPCHInclude.empty()) {286 // We can't really directly pass the CachedInCodeGenModule to the Jit287 // because it will steal it, causing dangling references as explained in288 // Interpreter::Execute289 auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());290 ASTContext &C = CI->getASTContext();291 IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));292 }293 if (llvm::Error Err = CreateExecutor(Config)) {294 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));295 return;296 }297 }298 299 // Not all frontends support code-generation, e.g. ast-dump actions don't300 if (Act->getCodeGen()) {301 // Process the PTUs that came from initialization. For example -include will302 // give us a header that's processed at initialization of the preprocessor.303 for (PartialTranslationUnit &PTU : PTUs)304 if (llvm::Error Err = Execute(PTU)) {305 ErrOut = joinErrors(std::move(ErrOut), std::move(Err));306 return;307 }308 }309}310 311Interpreter::~Interpreter() {312 IncrParser.reset();313 Act->FinalizeAction();314 if (DeviceParser)315 DeviceParser.reset();316 if (DeviceAct)317 DeviceAct->FinalizeAction();318 if (IncrExecutor) {319 if (llvm::Error Err = IncrExecutor->cleanUp())320 llvm::report_fatal_error(321 llvm::Twine("Failed to clean up IncrementalExecutor: ") +322 toString(std::move(Err)));323 }324}325 326// These better to put in a runtime header but we can't. This is because we327// can't find the precise resource directory in unittests so we have to hard328// code them.329const char *const Runtimes = R"(330 #define __CLANG_REPL__ 1331#ifdef __cplusplus332 #define EXTERN_C extern "C"333 struct __clang_Interpreter_NewTag{} __ci_newtag;334 void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;335 template <class T, class = T (*)() /*disable for arrays*/>336 void __clang_Interpreter_SetValueCopyArr(const T* Src, void* Placement, unsigned long Size) {337 for (auto Idx = 0; Idx < Size; ++Idx)338 new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);339 }340 template <class T, unsigned long N>341 void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {342 __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);343 }344#else345 #define EXTERN_C extern346 EXTERN_C void *memcpy(void *restrict dst, const void *restrict src, __SIZE_TYPE__ n);347 EXTERN_C inline void __clang_Interpreter_SetValueCopyArr(const void* Src, void* Placement, unsigned long Size) {348 memcpy(Placement, Src, Size);349 }350#endif // __cplusplus351 EXTERN_C void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);352 EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);353)";354 355llvm::Expected<std::pair<std::unique_ptr<llvm::orc::LLJITBuilder>, uint32_t>>356Interpreter::outOfProcessJITBuilder(JITConfig Config) {357 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC;358 uint32_t childPid = -1;359 if (!Config.OOPExecutor.empty()) {360 // Launch an out-of-process executor locally in a child process.361 auto ResultOrErr = IncrementalExecutor::launchExecutor(362 Config.OOPExecutor, Config.UseSharedMemory, Config.SlabAllocateSize,363 Config.CustomizeFork);364 if (!ResultOrErr)365 return ResultOrErr.takeError();366 childPid = ResultOrErr->second;367 auto EPCOrErr = std::move(ResultOrErr->first);368 EPC = std::move(EPCOrErr);369 } else if (Config.OOPExecutorConnect != "") {370#if LLVM_ON_UNIX && LLVM_ENABLE_THREADS371 auto EPCOrErr = IncrementalExecutor::connectTCPSocket(372 Config.OOPExecutorConnect, Config.UseSharedMemory,373 Config.SlabAllocateSize);374 if (!EPCOrErr)375 return EPCOrErr.takeError();376 EPC = std::move(*EPCOrErr);377#else378 return llvm::make_error<llvm::StringError>(379 "Out-of-process JIT over TCP is not supported on this platform",380 std::error_code());381#endif382 }383 384 std::unique_ptr<llvm::orc::LLJITBuilder> JB;385 if (EPC) {386 auto JBOrErr = clang::Interpreter::createLLJITBuilder(387 std::move(EPC), Config.OrcRuntimePath);388 if (!JBOrErr)389 return JBOrErr.takeError();390 JB = std::move(*JBOrErr);391 }392 393 return std::make_pair(std::move(JB), childPid);394}395 396llvm::Expected<std::string>397Interpreter::getOrcRuntimePath(const driver::ToolChain &TC) {398 const std::array<const char *, 3> OrcRTLibNames = {399 "liborc_rt.a", "liborc_rt_osx.a", "liborc_rt-x86_64.a"};400 401 auto findInDir = [&](llvm::StringRef Base) -> std::optional<std::string> {402 for (const char *LibName : OrcRTLibNames) {403 llvm::SmallString<256> CandidatePath(Base);404 llvm::sys::path::append(CandidatePath, LibName);405 if (llvm::sys::fs::exists(CandidatePath))406 return std::string(CandidatePath.str());407 }408 return std::nullopt;409 };410 411 std::string SearchedPaths;412 413 if (std::optional<std::string> CompilerRTPath = TC.getCompilerRTPath()) {414 if (auto Found = findInDir(*CompilerRTPath))415 return *Found;416 SearchedPaths += *CompilerRTPath;417 } else {418 return llvm::make_error<llvm::StringError>("CompilerRT path not found",419 std::error_code());420 }421 422 if (std::optional<std::string> ResourceDir = TC.getRuntimePath()) {423 if (auto Found = findInDir(*ResourceDir))424 return *Found;425 if (!SearchedPaths.empty())426 SearchedPaths += "; ";427 SearchedPaths += *ResourceDir;428 } else {429 return llvm::make_error<llvm::StringError>("ResourceDir path not found",430 std::error_code());431 }432 433 return llvm::make_error<llvm::StringError>(434 llvm::Twine("OrcRuntime library not found in: ") + SearchedPaths,435 std::error_code());436}437 438llvm::Expected<std::unique_ptr<Interpreter>>439Interpreter::create(std::unique_ptr<CompilerInstance> CI, JITConfig Config) {440 441 if (Config.IsOutOfProcess) {442 const TargetInfo &TI = CI->getTarget();443 const llvm::Triple &Triple = TI.getTriple();444 445 DiagnosticsEngine &Diags = CI->getDiagnostics();446 std::string BinaryName = llvm::sys::fs::getMainExecutable(nullptr, nullptr);447 driver::Driver Driver(BinaryName, Triple.str(), Diags);448 // Need fake args to get the driver to create a compilation.449 std::vector<const char *> Args = {"clang", "--version"};450 std::unique_ptr<clang::driver::Compilation> C(451 Driver.BuildCompilation(Args));452 if (!C) {453 return llvm::make_error<llvm::StringError>(454 "Failed to create driver compilation for out-of-process JIT",455 std::error_code());456 }457 if (Config.OrcRuntimePath == "") {458 const clang::driver::ToolChain &TC = C->getDefaultToolChain();459 460 auto OrcRuntimePathOrErr = getOrcRuntimePath(TC);461 if (!OrcRuntimePathOrErr) {462 return OrcRuntimePathOrErr.takeError();463 }464 465 Config.OrcRuntimePath = *OrcRuntimePathOrErr;466 }467 }468 469 llvm::Error Err = llvm::Error::success();470 std::unique_ptr<llvm::orc::LLJITBuilder> JB;471 472 auto Interp = std::unique_ptr<Interpreter>(new Interpreter(473 std::move(CI), Err, std::move(JB), /*Consumer=*/nullptr, Config));474 if (auto E = std::move(Err))475 return std::move(E);476 477 // Add runtime code and set a marker to hide it from user code. Undo will not478 // go through that.479 if (auto E = Interp->ParseAndExecute(Runtimes))480 return std::move(E);481 482 Interp->markUserCodeStart();483 484 return std::move(Interp);485}486 487llvm::Expected<std::unique_ptr<Interpreter>>488Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,489 std::unique_ptr<CompilerInstance> DCI) {490 // avoid writing fat binary to disk using an in-memory virtual file system491 llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> IMVFS =492 std::make_unique<llvm::vfs::InMemoryFileSystem>();493 llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =494 std::make_unique<llvm::vfs::OverlayFileSystem>(495 llvm::vfs::getRealFileSystem());496 OverlayVFS->pushOverlay(IMVFS);497 CI->createVirtualFileSystem(OverlayVFS);498 CI->createFileManager();499 500 llvm::Expected<std::unique_ptr<Interpreter>> InterpOrErr =501 Interpreter::create(std::move(CI));502 if (!InterpOrErr)503 return InterpOrErr;504 505 std::unique_ptr<Interpreter> Interp = std::move(*InterpOrErr);506 507 llvm::Error Err = llvm::Error::success();508 509 auto DeviceAct = Interp->TSCtx->withContextDo([&](llvm::LLVMContext *Ctx) {510 return std::make_unique<IncrementalAction>(*DCI, *Ctx, Err, *Interp);511 });512 513 if (Err)514 return std::move(Err);515 516 Interp->DeviceAct = std::move(DeviceAct);517 518 DCI->ExecuteAction(*Interp->DeviceAct);519 520 Interp->DeviceCI = std::move(DCI);521 522 auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(523 *Interp->DeviceCI, *Interp->getCompilerInstance(),524 Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);525 526 if (Err)527 return std::move(Err);528 529 Interp->DeviceParser = std::move(DeviceParser);530 return std::move(Interp);531}532 533CompilerInstance *Interpreter::getCompilerInstance() { return CI.get(); }534const CompilerInstance *Interpreter::getCompilerInstance() const {535 return const_cast<Interpreter *>(this)->getCompilerInstance();536}537 538llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {539 if (!IncrExecutor) {540 if (auto Err = CreateExecutor())541 return std::move(Err);542 }543 544 return IncrExecutor->GetExecutionEngine();545}546 547ASTContext &Interpreter::getASTContext() {548 return getCompilerInstance()->getASTContext();549}550 551const ASTContext &Interpreter::getASTContext() const {552 return getCompilerInstance()->getASTContext();553}554 555void Interpreter::markUserCodeStart() {556 assert(!InitPTUSize && "We only do this once");557 InitPTUSize = PTUs.size();558}559 560size_t Interpreter::getEffectivePTUSize() const {561 assert(PTUs.size() >= InitPTUSize && "empty PTU list?");562 return PTUs.size() - InitPTUSize;563}564 565uint32_t Interpreter::getOutOfProcessExecutorPID() const {566 if (IncrExecutor)567 return IncrExecutor->getOutOfProcessChildPid();568 return -1;569}570 571llvm::Expected<PartialTranslationUnit &>572Interpreter::Parse(llvm::StringRef Code) {573 // If we have a device parser, parse it first. The generated code will be574 // included in the host compilation575 if (DeviceParser) {576 llvm::Expected<TranslationUnitDecl *> DeviceTU = DeviceParser->Parse(Code);577 if (auto E = DeviceTU.takeError())578 return std::move(E);579 580 DeviceParser->RegisterPTU(*DeviceTU);581 582 llvm::Expected<llvm::StringRef> PTX = DeviceParser->GeneratePTX();583 if (!PTX)584 return PTX.takeError();585 586 llvm::Error Err = DeviceParser->GenerateFatbinary();587 if (Err)588 return std::move(Err);589 }590 591 // Tell the interpreter sliently ignore unused expressions since value592 // printing could cause it.593 getCompilerInstance()->getDiagnostics().setSeverity(594 clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());595 596 llvm::Expected<TranslationUnitDecl *> TuOrErr = IncrParser->Parse(Code);597 if (!TuOrErr)598 return TuOrErr.takeError();599 600 PartialTranslationUnit &LastPTU = IncrParser->RegisterPTU(*TuOrErr);601 602 return LastPTU;603}604 605static llvm::Expected<llvm::orc::JITTargetMachineBuilder>606createJITTargetMachineBuilder(const std::string &TT) {607 if (TT == llvm::sys::getProcessTriple())608 // This fails immediately if the target backend is not registered609 return llvm::orc::JITTargetMachineBuilder::detectHost();610 611 // If the target backend is not registered, LLJITBuilder::create() will fail612 return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));613}614 615llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>616Interpreter::createLLJITBuilder(617 std::unique_ptr<llvm::orc::ExecutorProcessControl> EPC,618 llvm::StringRef OrcRuntimePath) {619 const std::string &TT = EPC->getTargetTriple().getTriple();620 auto JTMB = createJITTargetMachineBuilder(TT);621 if (!JTMB)622 return JTMB.takeError();623 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));624 if (!JB)625 return JB.takeError();626 627 (*JB)->setExecutorProcessControl(std::move(EPC));628 (*JB)->setPlatformSetUp(629 llvm::orc::ExecutorNativePlatform(OrcRuntimePath.str()));630 631 return std::move(*JB);632}633 634llvm::Error Interpreter::CreateExecutor(JITConfig Config) {635 if (IncrExecutor)636 return llvm::make_error<llvm::StringError>("Operation failed. "637 "Execution engine exists",638 std::error_code());639 if (!Act->getCodeGen())640 return llvm::make_error<llvm::StringError>("Operation failed. "641 "No code generator available",642 std::error_code());643 644 const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;645 llvm::Triple TargetTriple(TT);646 bool IsWindowsTarget = TargetTriple.isOSWindows();647 648 if (!IsWindowsTarget && Config.IsOutOfProcess) {649 if (!JITBuilder) {650 auto ResOrErr = outOfProcessJITBuilder(Config);651 if (!ResOrErr)652 return ResOrErr.takeError();653 JITBuilder = std::move(ResOrErr->first);654 Config.ExecutorPID = ResOrErr->second;655 }656 if (!JITBuilder)657 return llvm::make_error<llvm::StringError>(658 "Operation failed. No LLJITBuilder for out-of-process JIT",659 std::error_code());660 }661 662 if (!JITBuilder) {663 auto JTMB = createJITTargetMachineBuilder(TT);664 if (!JTMB)665 return JTMB.takeError();666 if (Config.CM)667 JTMB->setCodeModel(Config.CM);668 auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));669 if (!JB)670 return JB.takeError();671 JITBuilder = std::move(*JB);672 }673 674 llvm::Error Err = llvm::Error::success();675 676 // Fix: Declare Executor as the appropriate unique_ptr type677 std::unique_ptr<IncrementalExecutor> Executor;678 679#ifdef __EMSCRIPTEN__680 Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);681#else682 Executor =683 std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Config, Err);684#endif685 if (!Err)686 IncrExecutor = std::move(Executor);687 688 return Err;689}690 691void Interpreter::ResetExecutor() { IncrExecutor.reset(); }692 693llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {694 assert(T.TheModule);695 LLVM_DEBUG(696 llvm::dbgs() << "execute-ptu "697 << (llvm::is_contained(PTUs, T)698 ? std::distance(PTUs.begin(), llvm::find(PTUs, T))699 : -1)700 << ": [TU=" << T.TUPart << ", M=" << T.TheModule.get()701 << " (" << T.TheModule->getName() << ")]\n");702 if (!IncrExecutor) {703 auto Err = CreateExecutor();704 if (Err)705 return Err;706 }707 // FIXME: Add a callback to retain the llvm::Module once the JIT is done.708 if (auto Err = IncrExecutor->addModule(T))709 return Err;710 711 if (auto Err = IncrExecutor->runCtors())712 return Err;713 714 return llvm::Error::success();715}716 717llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {718 719 auto PTU = Parse(Code);720 if (!PTU)721 return PTU.takeError();722 if (PTU->TheModule)723 if (llvm::Error Err = Execute(*PTU))724 return Err;725 726 if (LastValue.isValid()) {727 if (!V) {728 LastValue.dump();729 LastValue.clear();730 } else731 *V = std::move(LastValue);732 }733 return llvm::Error::success();734}735 736llvm::Expected<llvm::orc::ExecutorAddr>737Interpreter::getSymbolAddress(GlobalDecl GD) const {738 if (!IncrExecutor)739 return llvm::make_error<llvm::StringError>("Operation failed. "740 "No execution engine",741 std::error_code());742 llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);743 return getSymbolAddress(MangledName);744}745 746llvm::Expected<llvm::orc::ExecutorAddr>747Interpreter::getSymbolAddress(llvm::StringRef IRName) const {748 if (!IncrExecutor)749 return llvm::make_error<llvm::StringError>("Operation failed. "750 "No execution engine",751 std::error_code());752 753 return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);754}755 756llvm::Expected<llvm::orc::ExecutorAddr>757Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {758 if (!IncrExecutor)759 return llvm::make_error<llvm::StringError>("Operation failed. "760 "No execution engine",761 std::error_code());762 763 return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);764}765 766llvm::Error Interpreter::Undo(unsigned N) {767 768 if (getEffectivePTUSize() == 0) {769 return llvm::make_error<llvm::StringError>("Operation failed. "770 "No input left to undo",771 std::error_code());772 } else if (N > getEffectivePTUSize()) {773 return llvm::make_error<llvm::StringError>(774 llvm::formatv(775 "Operation failed. Wanted to undo {0} inputs, only have {1}.", N,776 getEffectivePTUSize()),777 std::error_code());778 }779 780 for (unsigned I = 0; I < N; I++) {781 if (IncrExecutor) {782 if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))783 return Err;784 }785 786 IncrParser->CleanUpPTU(PTUs.back().TUPart);787 PTUs.pop_back();788 }789 return llvm::Error::success();790}791 792llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {793#ifdef __EMSCRIPTEN__794 void *handle = dlopen(name, RTLD_NOW | RTLD_GLOBAL);795 if (!handle) {796 llvm::errs() << dlerror() << '\n';797 return llvm::make_error<llvm::StringError>("Failed to load dynamic library",798 llvm::inconvertibleErrorCode());799 }800#else801 auto EE = getExecutionEngine();802 if (!EE)803 return EE.takeError();804 805 if (llvm::Expected<806 std::unique_ptr<llvm::orc::EPCDynamicLibrarySearchGenerator>>807 DLSG = llvm::orc::EPCDynamicLibrarySearchGenerator::Load(808 EE->getExecutionSession(), name))809 // FIXME: Eventually we should put each library in its own JITDylib and810 // turn off process symbols by default.811 EE->getProcessSymbolsJITDylib()->addGenerator(std::move(*DLSG));812 else813 return DLSG.takeError();814#endif815 816 return llvm::Error::success();817}818} // end namespace clang819