aboutsummaryrefslogtreecommitdiff
path: root/contrib/llvm-project/clang/lib/Interpreter
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/llvm-project/clang/lib/Interpreter')
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/CodeCompletion.cpp387
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.cpp177
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.h51
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.cpp121
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.h71
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.cpp427
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.h96
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp965
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.cpp111
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.h54
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/Value.cpp269
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp149
-rw-r--r--contrib/llvm-project/clang/lib/Interpreter/Wasm.h38
13 files changed, 2916 insertions, 0 deletions
diff --git a/contrib/llvm-project/clang/lib/Interpreter/CodeCompletion.cpp b/contrib/llvm-project/clang/lib/Interpreter/CodeCompletion.cpp
new file mode 100644
index 000000000000..791426807cb9
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/CodeCompletion.cpp
@@ -0,0 +1,387 @@
+//===------ CodeCompletion.cpp - Code Completion for ClangRepl -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the classes which performs code completion at the REPL.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Interpreter/CodeCompletion.h"
+#include "clang/AST/ASTImporter.h"
+#include "clang/AST/DeclLookups.h"
+#include "clang/AST/DeclarationName.h"
+#include "clang/AST/ExternalASTSource.h"
+#include "clang/Basic/IdentifierTable.h"
+#include "clang/Frontend/ASTUnit.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendActions.h"
+#include "clang/Interpreter/Interpreter.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/CodeCompleteConsumer.h"
+#include "clang/Sema/CodeCompleteOptions.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Support/Debug.h"
+#define DEBUG_TYPE "REPLCC"
+
+namespace clang {
+
+const std::string CodeCompletionFileName = "input_line_[Completion]";
+
+clang::CodeCompleteOptions getClangCompleteOpts() {
+ clang::CodeCompleteOptions Opts;
+ Opts.IncludeCodePatterns = true;
+ Opts.IncludeMacros = true;
+ Opts.IncludeGlobals = true;
+ Opts.IncludeBriefComments = true;
+ return Opts;
+}
+
+class ReplCompletionConsumer : public CodeCompleteConsumer {
+public:
+ ReplCompletionConsumer(std::vector<std::string> &Results,
+ ReplCodeCompleter &CC)
+ : CodeCompleteConsumer(getClangCompleteOpts()),
+ CCAllocator(std::make_shared<GlobalCodeCompletionAllocator>()),
+ CCTUInfo(CCAllocator), Results(Results), CC(CC) {}
+
+ // The entry of handling code completion. When the function is called, we
+ // create a `Context`-based handler (see classes defined below) to handle each
+ // completion result.
+ void ProcessCodeCompleteResults(class Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *InResults,
+ unsigned NumResults) final;
+
+ CodeCompletionAllocator &getAllocator() override { return *CCAllocator; }
+
+ CodeCompletionTUInfo &getCodeCompletionTUInfo() override { return CCTUInfo; }
+
+private:
+ std::shared_ptr<GlobalCodeCompletionAllocator> CCAllocator;
+ CodeCompletionTUInfo CCTUInfo;
+ std::vector<std::string> &Results;
+ ReplCodeCompleter &CC;
+};
+
+/// The class CompletionContextHandler contains four interfaces, each of
+/// which handles one type of completion result.
+/// Its derived classes are used to create concrete handlers based on
+/// \c CodeCompletionContext.
+class CompletionContextHandler {
+protected:
+ CodeCompletionContext CCC;
+ std::vector<std::string> &Results;
+
+private:
+ Sema &S;
+
+public:
+ CompletionContextHandler(Sema &S, CodeCompletionContext CCC,
+ std::vector<std::string> &Results)
+ : CCC(CCC), Results(Results), S(S) {}
+
+ virtual ~CompletionContextHandler() = default;
+ /// Converts a Declaration completion result to a completion string, and then
+ /// stores it in Results.
+ virtual void handleDeclaration(const CodeCompletionResult &Result) {
+ auto PreferredType = CCC.getPreferredType();
+ if (PreferredType.isNull()) {
+ Results.push_back(Result.Declaration->getName().str());
+ return;
+ }
+
+ if (auto *VD = dyn_cast<VarDecl>(Result.Declaration)) {
+ auto ArgumentType = VD->getType();
+ if (PreferredType->isReferenceType()) {
+ QualType RT = PreferredType->castAs<ReferenceType>()->getPointeeType();
+ Sema::ReferenceConversions RefConv;
+ Sema::ReferenceCompareResult RefRelationship =
+ S.CompareReferenceRelationship(SourceLocation(), RT, ArgumentType,
+ &RefConv);
+ switch (RefRelationship) {
+ case Sema::Ref_Compatible:
+ case Sema::Ref_Related:
+ Results.push_back(VD->getName().str());
+ break;
+ case Sema::Ref_Incompatible:
+ break;
+ }
+ } else if (S.Context.hasSameType(ArgumentType, PreferredType)) {
+ Results.push_back(VD->getName().str());
+ }
+ }
+ }
+
+ /// Converts a Keyword completion result to a completion string, and then
+ /// stores it in Results.
+ virtual void handleKeyword(const CodeCompletionResult &Result) {
+ auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
+ // Add keyword to the completion results only if we are in a type-aware
+ // situation.
+ if (!CCC.getBaseType().isNull() || !CCC.getPreferredType().isNull())
+ return;
+ if (StringRef(Result.Keyword).starts_with(Prefix))
+ Results.push_back(Result.Keyword);
+ }
+
+ /// Converts a Pattern completion result to a completion string, and then
+ /// stores it in Results.
+ virtual void handlePattern(const CodeCompletionResult &Result) {}
+
+ /// Converts a Macro completion result to a completion string, and then stores
+ /// it in Results.
+ virtual void handleMacro(const CodeCompletionResult &Result) {}
+};
+
+class DotMemberAccessHandler : public CompletionContextHandler {
+public:
+ DotMemberAccessHandler(Sema &S, CodeCompletionContext CCC,
+ std::vector<std::string> &Results)
+ : CompletionContextHandler(S, CCC, Results) {}
+ void handleDeclaration(const CodeCompletionResult &Result) override {
+ auto *ID = Result.Declaration->getIdentifier();
+ if (!ID)
+ return;
+ if (!isa<CXXMethodDecl>(Result.Declaration))
+ return;
+ const auto *Fun = cast<CXXMethodDecl>(Result.Declaration);
+ if (Fun->getParent()->getCanonicalDecl() ==
+ CCC.getBaseType()->getAsCXXRecordDecl()->getCanonicalDecl()) {
+ LLVM_DEBUG(llvm::dbgs() << "[In HandleCodeCompleteDOT] Name : "
+ << ID->getName() << "\n");
+ Results.push_back(ID->getName().str());
+ }
+ }
+
+ void handleKeyword(const CodeCompletionResult &Result) override {}
+};
+
+void ReplCompletionConsumer::ProcessCodeCompleteResults(
+ class Sema &S, CodeCompletionContext Context,
+ CodeCompletionResult *InResults, unsigned NumResults) {
+
+ auto Prefix = S.getPreprocessor().getCodeCompletionFilter();
+ CC.Prefix = Prefix;
+
+ std::unique_ptr<CompletionContextHandler> CCH;
+
+ // initialize fine-grained code completion handler based on the code
+ // completion context.
+ switch (Context.getKind()) {
+ case CodeCompletionContext::CCC_DotMemberAccess:
+ CCH.reset(new DotMemberAccessHandler(S, Context, this->Results));
+ break;
+ default:
+ CCH.reset(new CompletionContextHandler(S, Context, this->Results));
+ };
+
+ for (unsigned I = 0; I < NumResults; I++) {
+ auto &Result = InResults[I];
+ switch (Result.Kind) {
+ case CodeCompletionResult::RK_Declaration:
+ if (Result.Hidden) {
+ break;
+ }
+ if (!Result.Declaration->getDeclName().isIdentifier() ||
+ !Result.Declaration->getName().starts_with(Prefix)) {
+ break;
+ }
+ CCH->handleDeclaration(Result);
+ break;
+ case CodeCompletionResult::RK_Keyword:
+ CCH->handleKeyword(Result);
+ break;
+ case CodeCompletionResult::RK_Macro:
+ CCH->handleMacro(Result);
+ break;
+ case CodeCompletionResult::RK_Pattern:
+ CCH->handlePattern(Result);
+ break;
+ }
+ }
+
+ std::sort(Results.begin(), Results.end());
+}
+
+class IncrementalSyntaxOnlyAction : public SyntaxOnlyAction {
+ const CompilerInstance *ParentCI;
+
+public:
+ IncrementalSyntaxOnlyAction(const CompilerInstance *ParentCI)
+ : ParentCI(ParentCI) {}
+
+protected:
+ void ExecuteAction() override;
+};
+
+class ExternalSource : public clang::ExternalASTSource {
+ TranslationUnitDecl *ChildTUDeclCtxt;
+ ASTContext &ParentASTCtxt;
+ TranslationUnitDecl *ParentTUDeclCtxt;
+
+ std::unique_ptr<ASTImporter> Importer;
+
+public:
+ ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
+ ASTContext &ParentASTCtxt, FileManager &ParentFM);
+ bool FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) override;
+ void
+ completeVisibleDeclsMap(const clang::DeclContext *childDeclContext) override;
+};
+
+// This method is intended to set up `ExternalASTSource` to the running
+// compiler instance before the super `ExecuteAction` triggers parsing
+void IncrementalSyntaxOnlyAction::ExecuteAction() {
+ CompilerInstance &CI = getCompilerInstance();
+ ExternalSource *myExternalSource =
+ new ExternalSource(CI.getASTContext(), CI.getFileManager(),
+ ParentCI->getASTContext(), ParentCI->getFileManager());
+ llvm::IntrusiveRefCntPtr<clang::ExternalASTSource> astContextExternalSource(
+ myExternalSource);
+ CI.getASTContext().setExternalSource(astContextExternalSource);
+ CI.getASTContext().getTranslationUnitDecl()->setHasExternalVisibleStorage(
+ true);
+
+ // Load all external decls into current context. Under the hood, it calls
+ // ExternalSource::completeVisibleDeclsMap, which make all decls on the redecl
+ // chain visible.
+ //
+ // This is crucial to code completion on dot members, since a bound variable
+ // before "." would be otherwise treated out-of-scope.
+ //
+ // clang-repl> Foo f1;
+ // clang-repl> f1.<tab>
+ CI.getASTContext().getTranslationUnitDecl()->lookups();
+ SyntaxOnlyAction::ExecuteAction();
+}
+
+ExternalSource::ExternalSource(ASTContext &ChildASTCtxt, FileManager &ChildFM,
+ ASTContext &ParentASTCtxt, FileManager &ParentFM)
+ : ChildTUDeclCtxt(ChildASTCtxt.getTranslationUnitDecl()),
+ ParentASTCtxt(ParentASTCtxt),
+ ParentTUDeclCtxt(ParentASTCtxt.getTranslationUnitDecl()) {
+ ASTImporter *importer =
+ new ASTImporter(ChildASTCtxt, ChildFM, ParentASTCtxt, ParentFM,
+ /*MinimalImport : ON*/ true);
+ Importer.reset(importer);
+}
+
+bool ExternalSource::FindExternalVisibleDeclsByName(const DeclContext *DC,
+ DeclarationName Name) {
+
+ IdentifierTable &ParentIdTable = ParentASTCtxt.Idents;
+
+ auto ParentDeclName =
+ DeclarationName(&(ParentIdTable.get(Name.getAsString())));
+
+ DeclContext::lookup_result lookup_result =
+ ParentTUDeclCtxt->lookup(ParentDeclName);
+
+ if (!lookup_result.empty()) {
+ return true;
+ }
+ return false;
+}
+
+void ExternalSource::completeVisibleDeclsMap(
+ const DeclContext *ChildDeclContext) {
+ assert(ChildDeclContext && ChildDeclContext == ChildTUDeclCtxt &&
+ "No child decl context!");
+
+ if (!ChildDeclContext->hasExternalVisibleStorage())
+ return;
+
+ for (auto *DeclCtxt = ParentTUDeclCtxt; DeclCtxt != nullptr;
+ DeclCtxt = DeclCtxt->getPreviousDecl()) {
+ for (auto &IDeclContext : DeclCtxt->decls()) {
+ if (!llvm::isa<NamedDecl>(IDeclContext))
+ continue;
+
+ NamedDecl *Decl = llvm::cast<NamedDecl>(IDeclContext);
+
+ auto DeclOrErr = Importer->Import(Decl);
+ if (!DeclOrErr) {
+ // if an error happens, it usually means the decl has already been
+ // imported or the decl is a result of a failed import. But in our
+ // case, every import is fresh each time code completion is
+ // triggered. So Import usually doesn't fail. If it does, it just means
+ // the related decl can't be used in code completion and we can safely
+ // drop it.
+ llvm::consumeError(DeclOrErr.takeError());
+ continue;
+ }
+
+ if (!llvm::isa<NamedDecl>(*DeclOrErr))
+ continue;
+
+ NamedDecl *importedNamedDecl = llvm::cast<NamedDecl>(*DeclOrErr);
+
+ SetExternalVisibleDeclsForName(ChildDeclContext,
+ importedNamedDecl->getDeclName(),
+ importedNamedDecl);
+
+ if (!llvm::isa<CXXRecordDecl>(importedNamedDecl))
+ continue;
+
+ auto *Record = llvm::cast<CXXRecordDecl>(importedNamedDecl);
+
+ if (auto Err = Importer->ImportDefinition(Decl)) {
+ // the same as above
+ consumeError(std::move(Err));
+ continue;
+ }
+
+ Record->setHasLoadedFieldsFromExternalStorage(true);
+ LLVM_DEBUG(llvm::dbgs()
+ << "\nCXXRecrod : " << Record->getName() << " size(methods): "
+ << std::distance(Record->method_begin(), Record->method_end())
+ << " has def?: " << Record->hasDefinition()
+ << " # (methods): "
+ << std::distance(Record->getDefinition()->method_begin(),
+ Record->getDefinition()->method_end())
+ << "\n");
+ for (auto *Meth : Record->methods())
+ SetExternalVisibleDeclsForName(ChildDeclContext, Meth->getDeclName(),
+ Meth);
+ }
+ ChildDeclContext->setHasExternalLexicalStorage(false);
+ }
+}
+
+void ReplCodeCompleter::codeComplete(CompilerInstance *InterpCI,
+ llvm::StringRef Content, unsigned Line,
+ unsigned Col,
+ const CompilerInstance *ParentCI,
+ std::vector<std::string> &CCResults) {
+ auto DiagOpts = DiagnosticOptions();
+ auto consumer = ReplCompletionConsumer(CCResults, *this);
+
+ auto diag = InterpCI->getDiagnosticsPtr();
+ std::unique_ptr<ASTUnit> AU(ASTUnit::LoadFromCompilerInvocationAction(
+ InterpCI->getInvocationPtr(), std::make_shared<PCHContainerOperations>(),
+ diag));
+ llvm::SmallVector<clang::StoredDiagnostic, 8> sd = {};
+ llvm::SmallVector<const llvm::MemoryBuffer *, 1> tb = {};
+ InterpCI->getFrontendOpts().Inputs[0] = FrontendInputFile(
+ CodeCompletionFileName, Language::CXX, InputKind::Source);
+ auto Act = std::make_unique<IncrementalSyntaxOnlyAction>(ParentCI);
+ std::unique_ptr<llvm::MemoryBuffer> MB =
+ llvm::MemoryBuffer::getMemBufferCopy(Content, CodeCompletionFileName);
+ llvm::SmallVector<ASTUnit::RemappedFile, 4> RemappedFiles;
+
+ RemappedFiles.push_back(std::make_pair(CodeCompletionFileName, MB.get()));
+ // we don't want the AU destructor to release the memory buffer that MB
+ // owns twice, because MB handles its resource on its own.
+ AU->setOwnsRemappedFileBuffers(false);
+ AU->CodeComplete(CodeCompletionFileName, 1, Col, RemappedFiles, false, false,
+ false, consumer,
+ std::make_shared<clang::PCHContainerOperations>(), *diag,
+ InterpCI->getLangOpts(), InterpCI->getSourceManager(),
+ InterpCI->getFileManager(), sd, tb, std::move(Act));
+}
+
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.cpp b/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.cpp
new file mode 100644
index 000000000000..07c9e3005e5f
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.cpp
@@ -0,0 +1,177 @@
+//===---------- DeviceOffload.cpp - Device Offloading------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements offloading to CUDA devices.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeviceOffload.h"
+
+#include "clang/Basic/TargetOptions.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+
+#include "llvm/IR/LegacyPassManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Target/TargetMachine.h"
+
+namespace clang {
+
+IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
+ Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
+ IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
+ llvm::Error &Err)
+ : IncrementalParser(Interp, std::move(Instance), LLVMCtx, Err),
+ HostParser(HostParser), VFS(FS) {
+ if (Err)
+ return;
+ StringRef Arch = CI->getTargetOpts().CPU;
+ if (!Arch.starts_with("sm_") || Arch.substr(3).getAsInteger(10, SMVersion)) {
+ Err = llvm::joinErrors(std::move(Err), llvm::make_error<llvm::StringError>(
+ "Invalid CUDA architecture",
+ llvm::inconvertibleErrorCode()));
+ return;
+ }
+}
+
+llvm::Expected<PartialTranslationUnit &>
+IncrementalCUDADeviceParser::Parse(llvm::StringRef Input) {
+ auto PTU = IncrementalParser::Parse(Input);
+ if (!PTU)
+ return PTU.takeError();
+
+ auto PTX = GeneratePTX();
+ if (!PTX)
+ return PTX.takeError();
+
+ auto Err = GenerateFatbinary();
+ if (Err)
+ return std::move(Err);
+
+ std::string FatbinFileName =
+ "/incr_module_" + std::to_string(PTUs.size()) + ".fatbin";
+ VFS->addFile(FatbinFileName, 0,
+ llvm::MemoryBuffer::getMemBuffer(
+ llvm::StringRef(FatbinContent.data(), FatbinContent.size()),
+ "", false));
+
+ HostParser.getCI()->getCodeGenOpts().CudaGpuBinaryFileName = FatbinFileName;
+
+ FatbinContent.clear();
+
+ return PTU;
+}
+
+llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
+ auto &PTU = PTUs.back();
+ std::string Error;
+
+ const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
+ PTU.TheModule->getTargetTriple(), Error);
+ if (!Target)
+ return llvm::make_error<llvm::StringError>(std::move(Error),
+ std::error_code());
+ llvm::TargetOptions TO = llvm::TargetOptions();
+ llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
+ PTU.TheModule->getTargetTriple(), getCI()->getTargetOpts().CPU, "", TO,
+ llvm::Reloc::Model::PIC_);
+ PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
+
+ PTXCode.clear();
+ llvm::raw_svector_ostream dest(PTXCode);
+
+ llvm::legacy::PassManager PM;
+ if (TargetMachine->addPassesToEmitFile(PM, dest, nullptr,
+ llvm::CodeGenFileType::AssemblyFile)) {
+ return llvm::make_error<llvm::StringError>(
+ "NVPTX backend cannot produce PTX code.",
+ llvm::inconvertibleErrorCode());
+ }
+
+ if (!PM.run(*PTU.TheModule))
+ return llvm::make_error<llvm::StringError>("Failed to emit PTX code.",
+ llvm::inconvertibleErrorCode());
+
+ PTXCode += '\0';
+ while (PTXCode.size() % 8)
+ PTXCode += '\0';
+ return PTXCode.str();
+}
+
+llvm::Error IncrementalCUDADeviceParser::GenerateFatbinary() {
+ enum FatBinFlags {
+ AddressSize64 = 0x01,
+ HasDebugInfo = 0x02,
+ ProducerCuda = 0x04,
+ HostLinux = 0x10,
+ HostMac = 0x20,
+ HostWindows = 0x40
+ };
+
+ struct FatBinInnerHeader {
+ uint16_t Kind; // 0x00
+ uint16_t unknown02; // 0x02
+ uint32_t HeaderSize; // 0x04
+ uint32_t DataSize; // 0x08
+ uint32_t unknown0c; // 0x0c
+ uint32_t CompressedSize; // 0x10
+ uint32_t SubHeaderSize; // 0x14
+ uint16_t VersionMinor; // 0x18
+ uint16_t VersionMajor; // 0x1a
+ uint32_t CudaArch; // 0x1c
+ uint32_t unknown20; // 0x20
+ uint32_t unknown24; // 0x24
+ uint32_t Flags; // 0x28
+ uint32_t unknown2c; // 0x2c
+ uint32_t unknown30; // 0x30
+ uint32_t unknown34; // 0x34
+ uint32_t UncompressedSize; // 0x38
+ uint32_t unknown3c; // 0x3c
+ uint32_t unknown40; // 0x40
+ uint32_t unknown44; // 0x44
+ FatBinInnerHeader(uint32_t DataSize, uint32_t CudaArch, uint32_t Flags)
+ : Kind(1 /*PTX*/), unknown02(0x0101), HeaderSize(sizeof(*this)),
+ DataSize(DataSize), unknown0c(0), CompressedSize(0),
+ SubHeaderSize(HeaderSize - 8), VersionMinor(2), VersionMajor(4),
+ CudaArch(CudaArch), unknown20(0), unknown24(0), Flags(Flags),
+ unknown2c(0), unknown30(0), unknown34(0), UncompressedSize(0),
+ unknown3c(0), unknown40(0), unknown44(0) {}
+ };
+
+ struct FatBinHeader {
+ uint32_t Magic; // 0x00
+ uint16_t Version; // 0x04
+ uint16_t HeaderSize; // 0x06
+ uint32_t DataSize; // 0x08
+ uint32_t unknown0c; // 0x0c
+ public:
+ FatBinHeader(uint32_t DataSize)
+ : Magic(0xba55ed50), Version(1), HeaderSize(sizeof(*this)),
+ DataSize(DataSize), unknown0c(0) {}
+ };
+
+ FatBinHeader OuterHeader(sizeof(FatBinInnerHeader) + PTXCode.size());
+ FatbinContent.append((char *)&OuterHeader,
+ ((char *)&OuterHeader) + OuterHeader.HeaderSize);
+
+ FatBinInnerHeader InnerHeader(PTXCode.size(), SMVersion,
+ FatBinFlags::AddressSize64 |
+ FatBinFlags::HostLinux);
+ FatbinContent.append((char *)&InnerHeader,
+ ((char *)&InnerHeader) + InnerHeader.HeaderSize);
+
+ FatbinContent.append(PTXCode.begin(), PTXCode.end());
+
+ return llvm::Error::success();
+}
+
+IncrementalCUDADeviceParser::~IncrementalCUDADeviceParser() {}
+
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.h b/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.h
new file mode 100644
index 000000000000..ce4f218c94c7
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/DeviceOffload.h
@@ -0,0 +1,51 @@
+//===----------- DeviceOffload.h - Device Offloading ------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements classes required for offloading to CUDA devices.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H
+#define LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H
+
+#include "IncrementalParser.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/VirtualFileSystem.h"
+
+namespace clang {
+
+class IncrementalCUDADeviceParser : public IncrementalParser {
+public:
+ IncrementalCUDADeviceParser(
+ Interpreter &Interp, std::unique_ptr<CompilerInstance> Instance,
+ IncrementalParser &HostParser, llvm::LLVMContext &LLVMCtx,
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
+ llvm::Error &Err);
+
+ llvm::Expected<PartialTranslationUnit &>
+ Parse(llvm::StringRef Input) override;
+
+ // Generate PTX for the last PTU
+ llvm::Expected<llvm::StringRef> GeneratePTX();
+
+ // Generate fatbinary contents in memory
+ llvm::Error GenerateFatbinary();
+
+ ~IncrementalCUDADeviceParser();
+
+protected:
+ IncrementalParser &HostParser;
+ int SMVersion;
+ llvm::SmallString<1024> PTXCode;
+ llvm::SmallVector<char, 1024> FatbinContent;
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS;
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_INTERPRETER_DEVICE_OFFLOAD_H
diff --git a/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.cpp b/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.cpp
new file mode 100644
index 000000000000..1824a5b4570a
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.cpp
@@ -0,0 +1,121 @@
+//===--- IncrementalExecutor.cpp - Incremental Execution --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the class which performs incremental code execution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncrementalExecutor.h"
+
+#include "clang/Basic/TargetInfo.h"
+#include "clang/Basic/TargetOptions.h"
+#include "clang/Interpreter/PartialTranslationUnit.h"
+#include "llvm/ExecutionEngine/ExecutionEngine.h"
+#include "llvm/ExecutionEngine/Orc/CompileUtils.h"
+#include "llvm/ExecutionEngine/Orc/Debugging/DebuggerSupport.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/IRCompileLayer.h"
+#include "llvm/ExecutionEngine/Orc/JITTargetMachineBuilder.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/ExecutionEngine/Orc/RTDyldObjectLinkingLayer.h"
+#include "llvm/ExecutionEngine/Orc/TargetProcess/JITLoaderGDB.h"
+#include "llvm/ExecutionEngine/SectionMemoryManager.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/ManagedStatic.h"
+#include "llvm/Support/TargetSelect.h"
+
+// Force linking some of the runtimes that helps attaching to a debugger.
+LLVM_ATTRIBUTE_USED void linkComponents() {
+ llvm::errs() << (void *)&llvm_orc_registerJITLoaderGDBWrapper
+ << (void *)&llvm_orc_registerJITLoaderGDBAllocAction;
+}
+
+namespace clang {
+IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC)
+ : TSCtx(TSC) {}
+
+llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+IncrementalExecutor::createDefaultJITBuilder(
+ llvm::orc::JITTargetMachineBuilder JTMB) {
+ auto JITBuilder = std::make_unique<llvm::orc::LLJITBuilder>();
+ JITBuilder->setJITTargetMachineBuilder(std::move(JTMB));
+ JITBuilder->setPrePlatformSetup([](llvm::orc::LLJIT &J) {
+ // Try to enable debugging of JIT'd code (only works with JITLink for
+ // ELF and MachO).
+ consumeError(llvm::orc::enableDebuggerSupport(J));
+ return llvm::Error::success();
+ });
+ return std::move(JITBuilder);
+}
+
+IncrementalExecutor::IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
+ llvm::orc::LLJITBuilder &JITBuilder,
+ llvm::Error &Err)
+ : TSCtx(TSC) {
+ using namespace llvm::orc;
+ llvm::ErrorAsOutParameter EAO(&Err);
+
+ if (auto JitOrErr = JITBuilder.create())
+ Jit = std::move(*JitOrErr);
+ else {
+ Err = JitOrErr.takeError();
+ return;
+ }
+}
+
+IncrementalExecutor::~IncrementalExecutor() {}
+
+llvm::Error IncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
+ llvm::orc::ResourceTrackerSP RT =
+ Jit->getMainJITDylib().createResourceTracker();
+ ResourceTrackers[&PTU] = RT;
+
+ return Jit->addIRModule(RT, {std::move(PTU.TheModule), TSCtx});
+}
+
+llvm::Error IncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
+
+ llvm::orc::ResourceTrackerSP RT = std::move(ResourceTrackers[&PTU]);
+ if (!RT)
+ return llvm::Error::success();
+
+ ResourceTrackers.erase(&PTU);
+ if (llvm::Error Err = RT->remove())
+ return Err;
+ return llvm::Error::success();
+}
+
+// Clean up the JIT instance.
+llvm::Error IncrementalExecutor::cleanUp() {
+ // This calls the global dtors of registered modules.
+ return Jit->deinitialize(Jit->getMainJITDylib());
+}
+
+llvm::Error IncrementalExecutor::runCtors() const {
+ return Jit->initialize(Jit->getMainJITDylib());
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr>
+IncrementalExecutor::getSymbolAddress(llvm::StringRef Name,
+ SymbolNameKind NameKind) const {
+ using namespace llvm::orc;
+ auto SO = makeJITDylibSearchOrder({&Jit->getMainJITDylib(),
+ Jit->getPlatformJITDylib().get(),
+ Jit->getProcessSymbolsJITDylib().get()});
+
+ ExecutionSession &ES = Jit->getExecutionSession();
+
+ auto SymOrErr =
+ ES.lookup(SO, (NameKind == LinkerName) ? ES.intern(Name)
+ : Jit->mangleAndIntern(Name));
+ if (auto Err = SymOrErr.takeError())
+ return std::move(Err);
+ return SymOrErr->getAddress();
+}
+
+} // end namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.h b/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.h
new file mode 100644
index 000000000000..dbd61f0b8b1e
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/IncrementalExecutor.h
@@ -0,0 +1,71 @@
+//===--- IncrementalExecutor.h - Incremental Execution ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the class which performs incremental code execution.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H
+#define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H
+
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ExecutionEngine/Orc/ExecutionUtils.h"
+#include "llvm/ExecutionEngine/Orc/Shared/ExecutorAddress.h"
+
+#include <memory>
+
+namespace llvm {
+class Error;
+namespace orc {
+class JITTargetMachineBuilder;
+class LLJIT;
+class LLJITBuilder;
+class ThreadSafeContext;
+} // namespace orc
+} // namespace llvm
+
+namespace clang {
+
+struct PartialTranslationUnit;
+class TargetInfo;
+
+class IncrementalExecutor {
+ using CtorDtorIterator = llvm::orc::CtorDtorIterator;
+ std::unique_ptr<llvm::orc::LLJIT> Jit;
+ llvm::orc::ThreadSafeContext &TSCtx;
+
+ llvm::DenseMap<const PartialTranslationUnit *, llvm::orc::ResourceTrackerSP>
+ ResourceTrackers;
+
+protected:
+ IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC);
+
+public:
+ enum SymbolNameKind { IRName, LinkerName };
+
+ IncrementalExecutor(llvm::orc::ThreadSafeContext &TSC,
+ llvm::orc::LLJITBuilder &JITBuilder, llvm::Error &Err);
+ virtual ~IncrementalExecutor();
+
+ virtual llvm::Error addModule(PartialTranslationUnit &PTU);
+ virtual llvm::Error removeModule(PartialTranslationUnit &PTU);
+ virtual llvm::Error runCtors() const;
+ virtual llvm::Error cleanUp();
+ llvm::Expected<llvm::orc::ExecutorAddr>
+ getSymbolAddress(llvm::StringRef Name, SymbolNameKind NameKind) const;
+
+ llvm::orc::LLJIT &GetExecutionEngine() { return *Jit; }
+
+ static llvm::Expected<std::unique_ptr<llvm::orc::LLJITBuilder>>
+ createDefaultJITBuilder(llvm::orc::JITTargetMachineBuilder JTMB);
+};
+
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALEXECUTOR_H
diff --git a/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.cpp b/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.cpp
new file mode 100644
index 000000000000..b7c809c45098
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.cpp
@@ -0,0 +1,427 @@
+//===--------- IncrementalParser.cpp - Incremental Compilation -----------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the class which performs incremental code compilation.
+//
+//===----------------------------------------------------------------------===//
+
+#include "IncrementalParser.h"
+
+#include "clang/AST/DeclContextInternals.h"
+#include "clang/CodeGen/BackendUtil.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/FrontendAction.h"
+#include "clang/FrontendTool/Utils.h"
+#include "clang/Interpreter/Interpreter.h"
+#include "clang/Parse/Parser.h"
+#include "clang/Sema/Sema.h"
+#include "llvm/Option/ArgList.h"
+#include "llvm/Support/CrashRecoveryContext.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Timer.h"
+
+#include <sstream>
+
+namespace clang {
+
+class IncrementalASTConsumer final : public ASTConsumer {
+ Interpreter &Interp;
+ std::unique_ptr<ASTConsumer> Consumer;
+
+public:
+ IncrementalASTConsumer(Interpreter &InterpRef, std::unique_ptr<ASTConsumer> C)
+ : Interp(InterpRef), Consumer(std::move(C)) {}
+
+ bool HandleTopLevelDecl(DeclGroupRef DGR) override final {
+ if (DGR.isNull())
+ return true;
+ if (!Consumer)
+ return true;
+
+ for (Decl *D : DGR)
+ if (auto *TSD = llvm::dyn_cast<TopLevelStmtDecl>(D);
+ TSD && TSD->isSemiMissing())
+ TSD->setStmt(Interp.SynthesizeExpr(cast<Expr>(TSD->getStmt())));
+
+ return Consumer->HandleTopLevelDecl(DGR);
+ }
+ void HandleTranslationUnit(ASTContext &Ctx) override final {
+ Consumer->HandleTranslationUnit(Ctx);
+ }
+ void HandleInlineFunctionDefinition(FunctionDecl *D) override final {
+ Consumer->HandleInlineFunctionDefinition(D);
+ }
+ void HandleInterestingDecl(DeclGroupRef D) override final {
+ Consumer->HandleInterestingDecl(D);
+ }
+ void HandleTagDeclDefinition(TagDecl *D) override final {
+ Consumer->HandleTagDeclDefinition(D);
+ }
+ void HandleTagDeclRequiredDefinition(const TagDecl *D) override final {
+ Consumer->HandleTagDeclRequiredDefinition(D);
+ }
+ void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override final {
+ Consumer->HandleCXXImplicitFunctionInstantiation(D);
+ }
+ void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override final {
+ Consumer->HandleTopLevelDeclInObjCContainer(D);
+ }
+ void HandleImplicitImportDecl(ImportDecl *D) override final {
+ Consumer->HandleImplicitImportDecl(D);
+ }
+ void CompleteTentativeDefinition(VarDecl *D) override final {
+ Consumer->CompleteTentativeDefinition(D);
+ }
+ void CompleteExternalDeclaration(DeclaratorDecl *D) override final {
+ Consumer->CompleteExternalDeclaration(D);
+ }
+ void AssignInheritanceModel(CXXRecordDecl *RD) override final {
+ Consumer->AssignInheritanceModel(RD);
+ }
+ void HandleCXXStaticMemberVarInstantiation(VarDecl *D) override final {
+ Consumer->HandleCXXStaticMemberVarInstantiation(D);
+ }
+ void HandleVTable(CXXRecordDecl *RD) override final {
+ Consumer->HandleVTable(RD);
+ }
+ ASTMutationListener *GetASTMutationListener() override final {
+ return Consumer->GetASTMutationListener();
+ }
+ ASTDeserializationListener *GetASTDeserializationListener() override final {
+ return Consumer->GetASTDeserializationListener();
+ }
+ void PrintStats() override final { Consumer->PrintStats(); }
+ bool shouldSkipFunctionBody(Decl *D) override final {
+ return Consumer->shouldSkipFunctionBody(D);
+ }
+ static bool classof(const clang::ASTConsumer *) { return true; }
+};
+
+/// A custom action enabling the incremental processing functionality.
+///
+/// The usual \p FrontendAction expects one call to ExecuteAction and once it
+/// sees a call to \p EndSourceFile it deletes some of the important objects
+/// such as \p Preprocessor and \p Sema assuming no further input will come.
+///
+/// \p IncrementalAction ensures it keep its underlying action's objects alive
+/// as long as the \p IncrementalParser needs them.
+///
+class IncrementalAction : public WrapperFrontendAction {
+private:
+ bool IsTerminating = false;
+
+public:
+ IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
+ llvm::Error &Err)
+ : WrapperFrontendAction([&]() {
+ llvm::ErrorAsOutParameter EAO(&Err);
+ std::unique_ptr<FrontendAction> Act;
+ switch (CI.getFrontendOpts().ProgramAction) {
+ default:
+ Err = llvm::createStringError(
+ std::errc::state_not_recoverable,
+ "Driver initialization failed. "
+ "Incremental mode for action %d is not supported",
+ CI.getFrontendOpts().ProgramAction);
+ return Act;
+ case frontend::ASTDump:
+ [[fallthrough]];
+ case frontend::ASTPrint:
+ [[fallthrough]];
+ case frontend::ParseSyntaxOnly:
+ Act = CreateFrontendAction(CI);
+ break;
+ case frontend::PluginAction:
+ [[fallthrough]];
+ case frontend::EmitAssembly:
+ [[fallthrough]];
+ case frontend::EmitBC:
+ [[fallthrough]];
+ case frontend::EmitObj:
+ [[fallthrough]];
+ case frontend::PrintPreprocessedInput:
+ [[fallthrough]];
+ case frontend::EmitLLVMOnly:
+ Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
+ break;
+ }
+ return Act;
+ }()) {}
+ FrontendAction *getWrapped() const { return WrappedAction.get(); }
+ TranslationUnitKind getTranslationUnitKind() override {
+ return TU_Incremental;
+ }
+
+ void ExecuteAction() override {
+ CompilerInstance &CI = getCompilerInstance();
+ assert(CI.hasPreprocessor() && "No PP!");
+
+ // Use a code completion consumer?
+ CodeCompleteConsumer *CompletionConsumer = nullptr;
+ if (CI.hasCodeCompletionConsumer())
+ CompletionConsumer = &CI.getCodeCompletionConsumer();
+
+ Preprocessor &PP = CI.getPreprocessor();
+ PP.EnterMainSourceFile();
+
+ if (!CI.hasSema())
+ CI.createSema(getTranslationUnitKind(), CompletionConsumer);
+ }
+
+ // Do not terminate after processing the input. This allows us to keep various
+ // clang objects alive and to incrementally grow the current TU.
+ void EndSourceFile() override {
+ // The WrappedAction can be nullptr if we issued an error in the ctor.
+ if (IsTerminating && getWrapped())
+ WrapperFrontendAction::EndSourceFile();
+ }
+
+ void FinalizeAction() {
+ assert(!IsTerminating && "Already finalized!");
+ IsTerminating = true;
+ EndSourceFile();
+ }
+};
+
+CodeGenerator *IncrementalParser::getCodeGen() const {
+ FrontendAction *WrappedAct = Act->getWrapped();
+ if (!WrappedAct->hasIRSupport())
+ return nullptr;
+ return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
+}
+
+IncrementalParser::IncrementalParser() {}
+
+IncrementalParser::IncrementalParser(Interpreter &Interp,
+ std::unique_ptr<CompilerInstance> Instance,
+ llvm::LLVMContext &LLVMCtx,
+ llvm::Error &Err)
+ : CI(std::move(Instance)) {
+ llvm::ErrorAsOutParameter EAO(&Err);
+ Act = std::make_unique<IncrementalAction>(*CI, LLVMCtx, Err);
+ if (Err)
+ return;
+ CI->ExecuteAction(*Act);
+
+ if (getCodeGen())
+ CachedInCodeGenModule = GenModule();
+
+ std::unique_ptr<ASTConsumer> IncrConsumer =
+ std::make_unique<IncrementalASTConsumer>(Interp, CI->takeASTConsumer());
+ CI->setASTConsumer(std::move(IncrConsumer));
+ Consumer = &CI->getASTConsumer();
+ P.reset(
+ new Parser(CI->getPreprocessor(), CI->getSema(), /*SkipBodies=*/false));
+ P->Initialize();
+
+ // An initial PTU is needed as CUDA includes some headers automatically
+ auto PTU = ParseOrWrapTopLevelDecl();
+ if (auto E = PTU.takeError()) {
+ consumeError(std::move(E)); // FIXME
+ return; // PTU.takeError();
+ }
+
+ if (getCodeGen()) {
+ PTU->TheModule = GenModule();
+ assert(PTU->TheModule && "Failed to create initial PTU");
+ }
+}
+
+IncrementalParser::~IncrementalParser() {
+ P.reset();
+ Act->FinalizeAction();
+}
+
+llvm::Expected<PartialTranslationUnit &>
+IncrementalParser::ParseOrWrapTopLevelDecl() {
+ // Recover resources if we crash before exiting this method.
+ Sema &S = CI->getSema();
+ llvm::CrashRecoveryContextCleanupRegistrar<Sema> CleanupSema(&S);
+ Sema::GlobalEagerInstantiationScope GlobalInstantiations(S, /*Enabled=*/true);
+ Sema::LocalEagerInstantiationScope LocalInstantiations(S);
+
+ PTUs.emplace_back(PartialTranslationUnit());
+ PartialTranslationUnit &LastPTU = PTUs.back();
+ // Add a new PTU.
+ ASTContext &C = S.getASTContext();
+ C.addTranslationUnitDecl();
+ LastPTU.TUPart = C.getTranslationUnitDecl();
+
+ // Skip previous eof due to last incremental input.
+ if (P->getCurToken().is(tok::annot_repl_input_end)) {
+ P->ConsumeAnyToken();
+ // FIXME: Clang does not call ExitScope on finalizing the regular TU, we
+ // might want to do that around HandleEndOfTranslationUnit.
+ P->ExitScope();
+ S.CurContext = nullptr;
+ // Start a new PTU.
+ P->EnterScope(Scope::DeclScope);
+ S.ActOnTranslationUnitScope(P->getCurScope());
+ }
+
+ Parser::DeclGroupPtrTy ADecl;
+ Sema::ModuleImportState ImportState;
+ for (bool AtEOF = P->ParseFirstTopLevelDecl(ADecl, ImportState); !AtEOF;
+ AtEOF = P->ParseTopLevelDecl(ADecl, ImportState)) {
+ if (ADecl && !Consumer->HandleTopLevelDecl(ADecl.get()))
+ return llvm::make_error<llvm::StringError>("Parsing failed. "
+ "The consumer rejected a decl",
+ std::error_code());
+ }
+
+ DiagnosticsEngine &Diags = getCI()->getDiagnostics();
+ if (Diags.hasErrorOccurred()) {
+ PartialTranslationUnit MostRecentPTU = {C.getTranslationUnitDecl(),
+ nullptr};
+ CleanUpPTU(MostRecentPTU);
+
+ Diags.Reset(/*soft=*/true);
+ Diags.getClient()->clear();
+ return llvm::make_error<llvm::StringError>("Parsing failed.",
+ std::error_code());
+ }
+
+ // Process any TopLevelDecls generated by #pragma weak.
+ for (Decl *D : S.WeakTopLevelDecls()) {
+ DeclGroupRef DGR(D);
+ Consumer->HandleTopLevelDecl(DGR);
+ }
+
+ LocalInstantiations.perform();
+ GlobalInstantiations.perform();
+
+ Consumer->HandleTranslationUnit(C);
+
+ return LastPTU;
+}
+
+llvm::Expected<PartialTranslationUnit &>
+IncrementalParser::Parse(llvm::StringRef input) {
+ Preprocessor &PP = CI->getPreprocessor();
+ assert(PP.isIncrementalProcessingEnabled() && "Not in incremental mode!?");
+
+ std::ostringstream SourceName;
+ SourceName << "input_line_" << InputCount++;
+
+ // Create an uninitialized memory buffer, copy code in and append "\n"
+ size_t InputSize = input.size(); // don't include trailing 0
+ // MemBuffer size should *not* include terminating zero
+ std::unique_ptr<llvm::MemoryBuffer> MB(
+ llvm::WritableMemoryBuffer::getNewUninitMemBuffer(InputSize + 1,
+ SourceName.str()));
+ char *MBStart = const_cast<char *>(MB->getBufferStart());
+ memcpy(MBStart, input.data(), InputSize);
+ MBStart[InputSize] = '\n';
+
+ SourceManager &SM = CI->getSourceManager();
+
+ // FIXME: Create SourceLocation, which will allow clang to order the overload
+ // candidates for example
+ SourceLocation NewLoc = SM.getLocForStartOfFile(SM.getMainFileID());
+
+ // Create FileID for the current buffer.
+ FileID FID = SM.createFileID(std::move(MB), SrcMgr::C_User, /*LoadedID=*/0,
+ /*LoadedOffset=*/0, NewLoc);
+
+ // NewLoc only used for diags.
+ if (PP.EnterSourceFile(FID, /*DirLookup=*/nullptr, NewLoc))
+ return llvm::make_error<llvm::StringError>("Parsing failed. "
+ "Cannot enter source file.",
+ std::error_code());
+
+ auto PTU = ParseOrWrapTopLevelDecl();
+ if (!PTU)
+ return PTU.takeError();
+
+ if (PP.getLangOpts().DelayedTemplateParsing) {
+ // Microsoft-specific:
+ // Late parsed templates can leave unswallowed "macro"-like tokens.
+ // They will seriously confuse the Parser when entering the next
+ // source file. So lex until we are EOF.
+ Token Tok;
+ do {
+ PP.Lex(Tok);
+ } while (Tok.isNot(tok::annot_repl_input_end));
+ } else {
+ Token AssertTok;
+ PP.Lex(AssertTok);
+ assert(AssertTok.is(tok::annot_repl_input_end) &&
+ "Lexer must be EOF when starting incremental parse!");
+ }
+
+ if (std::unique_ptr<llvm::Module> M = GenModule())
+ PTU->TheModule = std::move(M);
+
+ return PTU;
+}
+
+std::unique_ptr<llvm::Module> IncrementalParser::GenModule() {
+ static unsigned ID = 0;
+ if (CodeGenerator *CG = getCodeGen()) {
+ // Clang's CodeGen is designed to work with a single llvm::Module. In many
+ // cases for convenience various CodeGen parts have a reference to the
+ // llvm::Module (TheModule or Module) which does not change when a new
+ // module is pushed. However, the execution engine wants to take ownership
+ // of the module which does not map well to CodeGen's design. To work this
+ // around we created an empty module to make CodeGen happy. We should make
+ // sure it always stays empty.
+ assert((!CachedInCodeGenModule ||
+ (CachedInCodeGenModule->empty() &&
+ CachedInCodeGenModule->global_empty() &&
+ CachedInCodeGenModule->alias_empty() &&
+ CachedInCodeGenModule->ifunc_empty())) &&
+ "CodeGen wrote to a readonly module");
+ std::unique_ptr<llvm::Module> M(CG->ReleaseModule());
+ CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());
+ return M;
+ }
+ return nullptr;
+}
+
+void IncrementalParser::CleanUpPTU(PartialTranslationUnit &PTU) {
+ TranslationUnitDecl *MostRecentTU = PTU.TUPart;
+ if (StoredDeclsMap *Map = MostRecentTU->getPrimaryContext()->getLookupPtr()) {
+ for (auto &&[Key, List] : *Map) {
+ DeclContextLookupResult R = List.getLookupResult();
+ std::vector<NamedDecl *> NamedDeclsToRemove;
+ bool RemoveAll = true;
+ for (NamedDecl *D : R) {
+ if (D->getTranslationUnitDecl() == MostRecentTU)
+ NamedDeclsToRemove.push_back(D);
+ else
+ RemoveAll = false;
+ }
+ if (LLVM_LIKELY(RemoveAll)) {
+ Map->erase(Key);
+ } else {
+ for (NamedDecl *D : NamedDeclsToRemove)
+ List.remove(D);
+ }
+ }
+ }
+
+ // FIXME: We should de-allocate MostRecentTU
+ for (Decl *D : MostRecentTU->decls()) {
+ auto *ND = dyn_cast<NamedDecl>(D);
+ if (!ND)
+ continue;
+ // Check if we need to clean up the IdResolver chain.
+ if (ND->getDeclName().getFETokenInfo() && !D->getLangOpts().ObjC &&
+ !D->getLangOpts().CPlusPlus)
+ getCI()->getSema().IdResolver.RemoveDecl(ND);
+ }
+}
+
+llvm::StringRef IncrementalParser::GetMangledName(GlobalDecl GD) const {
+ CodeGenerator *CG = getCodeGen();
+ assert(CG);
+ return CG->GetMangledName(GD);
+}
+} // end namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.h b/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.h
new file mode 100644
index 000000000000..f63bce50acd3
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/IncrementalParser.h
@@ -0,0 +1,96 @@
+//===--- IncrementalParser.h - Incremental Compilation ----------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the class which performs incremental code compilation.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
+#define LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
+
+#include "clang/AST/GlobalDecl.h"
+#include "clang/Interpreter/PartialTranslationUnit.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Error.h"
+
+#include <list>
+#include <memory>
+namespace llvm {
+class LLVMContext;
+class Module;
+} // namespace llvm
+
+namespace clang {
+class ASTConsumer;
+class CodeGenerator;
+class CompilerInstance;
+class IncrementalAction;
+class Interpreter;
+class Parser;
+/// Provides support for incremental compilation. Keeps track of the state
+/// changes between the subsequent incremental input.
+///
+class IncrementalParser {
+protected:
+ /// Long-lived, incremental parsing action.
+ std::unique_ptr<IncrementalAction> Act;
+
+ /// Compiler instance performing the incremental compilation.
+ std::unique_ptr<CompilerInstance> CI;
+
+ /// Parser.
+ std::unique_ptr<Parser> P;
+
+ /// Consumer to process the produced top level decls. Owned by Act.
+ ASTConsumer *Consumer = nullptr;
+
+ /// Counts the number of direct user input lines that have been parsed.
+ unsigned InputCount = 0;
+
+ /// List containing every information about every incrementally parsed piece
+ /// of code.
+ std::list<PartialTranslationUnit> PTUs;
+
+ /// When CodeGen is created the first llvm::Module gets cached in many places
+ /// and we must keep it alive.
+ std::unique_ptr<llvm::Module> CachedInCodeGenModule;
+
+ IncrementalParser();
+
+public:
+ IncrementalParser(Interpreter &Interp,
+ std::unique_ptr<CompilerInstance> Instance,
+ llvm::LLVMContext &LLVMCtx, llvm::Error &Err);
+ virtual ~IncrementalParser();
+
+ CompilerInstance *getCI() { return CI.get(); }
+ CodeGenerator *getCodeGen() const;
+
+ /// Parses incremental input by creating an in-memory file.
+ ///\returns a \c PartialTranslationUnit which holds information about the
+ /// \c TranslationUnitDecl and \c llvm::Module corresponding to the input.
+ virtual llvm::Expected<PartialTranslationUnit &> Parse(llvm::StringRef Input);
+
+ /// Uses the CodeGenModule mangled name cache and avoids recomputing.
+ ///\returns the mangled name of a \c GD.
+ llvm::StringRef GetMangledName(GlobalDecl GD) const;
+
+ void CleanUpPTU(PartialTranslationUnit &PTU);
+
+ std::list<PartialTranslationUnit> &getPTUs() { return PTUs; }
+
+ std::unique_ptr<llvm::Module> GenModule();
+
+private:
+ llvm::Expected<PartialTranslationUnit &> ParseOrWrapTopLevelDecl();
+};
+} // end namespace clang
+
+#endif // LLVM_CLANG_LIB_INTERPRETER_INCREMENTALPARSER_H
diff --git a/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
new file mode 100644
index 000000000000..985d0b7c0ef3
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/Interpreter.cpp
@@ -0,0 +1,965 @@
+//===------ Interpreter.cpp - Incremental Compilation and Execution -------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements the component which performs incremental code
+// compilation and execution.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DeviceOffload.h"
+#include "IncrementalExecutor.h"
+#include "IncrementalParser.h"
+#include "InterpreterUtils.h"
+#ifdef __EMSCRIPTEN__
+#include "Wasm.h"
+#endif // __EMSCRIPTEN__
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Mangle.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/DiagnosticSema.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/CodeGenAction.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Interpreter/Interpreter.h"
+#include "clang/Interpreter/Value.h"
+#include "clang/Lex/PreprocessorOptions.h"
+#include "clang/Sema/Lookup.h"
+#include "llvm/ExecutionEngine/JITSymbol.h"
+#include "llvm/ExecutionEngine/Orc/LLJIT.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_ostream.h"
+#include "llvm/TargetParser/Host.h"
+
+#include <cstdarg>
+
+using namespace clang;
+
+// FIXME: Figure out how to unify with namespace init_convenience from
+// tools/clang-import-test/clang-import-test.cpp
+namespace {
+/// Retrieves the clang CC1 specific flags out of the compilation's jobs.
+/// \returns NULL on error.
+static llvm::Expected<const llvm::opt::ArgStringList *>
+GetCC1Arguments(DiagnosticsEngine *Diagnostics,
+ driver::Compilation *Compilation) {
+ // We expect to get back exactly one Command job, if we didn't something
+ // failed. Extract that job from the Compilation.
+ const driver::JobList &Jobs = Compilation->getJobs();
+ if (!Jobs.size() || !isa<driver::Command>(*Jobs.begin()))
+ return llvm::createStringError(llvm::errc::not_supported,
+ "Driver initialization failed. "
+ "Unable to create a driver job");
+
+ // The one job we find should be to invoke clang again.
+ const driver::Command *Cmd = cast<driver::Command>(&(*Jobs.begin()));
+ if (llvm::StringRef(Cmd->getCreator().getName()) != "clang")
+ return llvm::createStringError(llvm::errc::not_supported,
+ "Driver initialization failed");
+
+ return &Cmd->getArguments();
+}
+
+static llvm::Expected<std::unique_ptr<CompilerInstance>>
+CreateCI(const llvm::opt::ArgStringList &Argv) {
+ std::unique_ptr<CompilerInstance> Clang(new CompilerInstance());
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+
+ // Register the support for object-file-wrapped Clang modules.
+ // FIXME: Clang should register these container operations automatically.
+ auto PCHOps = Clang->getPCHContainerOperations();
+ PCHOps->registerWriter(std::make_unique<ObjectFilePCHContainerWriter>());
+ PCHOps->registerReader(std::make_unique<ObjectFilePCHContainerReader>());
+
+ // Buffer diagnostics from argument parsing so that we can output them using
+ // a well formed diagnostic object.
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts = new DiagnosticOptions();
+ TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+ bool Success = CompilerInvocation::CreateFromArgs(
+ Clang->getInvocation(), llvm::ArrayRef(Argv.begin(), Argv.size()), Diags);
+
+ // Infer the builtin include path if unspecified.
+ if (Clang->getHeaderSearchOpts().UseBuiltinIncludes &&
+ Clang->getHeaderSearchOpts().ResourceDir.empty())
+ Clang->getHeaderSearchOpts().ResourceDir =
+ CompilerInvocation::GetResourcesPath(Argv[0], nullptr);
+
+ // Create the actual diagnostics engine.
+ Clang->createDiagnostics();
+ if (!Clang->hasDiagnostics())
+ return llvm::createStringError(llvm::errc::not_supported,
+ "Initialization failed. "
+ "Unable to create diagnostics engine");
+
+ DiagsBuffer->FlushDiagnostics(Clang->getDiagnostics());
+ if (!Success)
+ return llvm::createStringError(llvm::errc::not_supported,
+ "Initialization failed. "
+ "Unable to flush diagnostics");
+
+ // FIXME: Merge with CompilerInstance::ExecuteAction.
+ llvm::MemoryBuffer *MB = llvm::MemoryBuffer::getMemBuffer("").release();
+ Clang->getPreprocessorOpts().addRemappedFile("<<< inputs >>>", MB);
+
+ Clang->setTarget(TargetInfo::CreateTargetInfo(
+ Clang->getDiagnostics(), Clang->getInvocation().TargetOpts));
+ if (!Clang->hasTarget())
+ return llvm::createStringError(llvm::errc::not_supported,
+ "Initialization failed. "
+ "Target is missing");
+
+ Clang->getTarget().adjust(Clang->getDiagnostics(), Clang->getLangOpts());
+
+ // Don't clear the AST before backend codegen since we do codegen multiple
+ // times, reusing the same AST.
+ Clang->getCodeGenOpts().ClearASTBeforeBackend = false;
+
+ Clang->getFrontendOpts().DisableFree = false;
+ Clang->getCodeGenOpts().DisableFree = false;
+ return std::move(Clang);
+}
+
+} // anonymous namespace
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+IncrementalCompilerBuilder::create(std::string TT,
+ std::vector<const char *> &ClangArgv) {
+
+ // If we don't know ClangArgv0 or the address of main() at this point, try
+ // to guess it anyway (it's possible on some platforms).
+ std::string MainExecutableName =
+ llvm::sys::fs::getMainExecutable(nullptr, nullptr);
+
+ ClangArgv.insert(ClangArgv.begin(), MainExecutableName.c_str());
+
+ // Prepending -c to force the driver to do something if no action was
+ // specified. By prepending we allow users to override the default
+ // action and use other actions in incremental mode.
+ // FIXME: Print proper driver diagnostics if the driver flags are wrong.
+ // We do C++ by default; append right after argv[0] if no "-x" given
+ ClangArgv.insert(ClangArgv.end(), "-Xclang");
+ ClangArgv.insert(ClangArgv.end(), "-fincremental-extensions");
+ ClangArgv.insert(ClangArgv.end(), "-c");
+
+ // Put a dummy C++ file on to ensure there's at least one compile job for the
+ // driver to construct.
+ ClangArgv.push_back("<<< inputs >>>");
+
+ // Buffer diagnostics from argument parsing so that we can output them using a
+ // well formed diagnostic object.
+ IntrusiveRefCntPtr<DiagnosticIDs> DiagID(new DiagnosticIDs());
+ IntrusiveRefCntPtr<DiagnosticOptions> DiagOpts =
+ CreateAndPopulateDiagOpts(ClangArgv);
+ TextDiagnosticBuffer *DiagsBuffer = new TextDiagnosticBuffer;
+ DiagnosticsEngine Diags(DiagID, &*DiagOpts, DiagsBuffer);
+
+ driver::Driver Driver(/*MainBinaryName=*/ClangArgv[0], TT, Diags);
+ Driver.setCheckInputsExist(false); // the input comes from mem buffers
+ llvm::ArrayRef<const char *> RF = llvm::ArrayRef(ClangArgv);
+ std::unique_ptr<driver::Compilation> Compilation(Driver.BuildCompilation(RF));
+
+ if (Compilation->getArgs().hasArg(driver::options::OPT_v))
+ Compilation->getJobs().Print(llvm::errs(), "\n", /*Quote=*/false);
+
+ auto ErrOrCC1Args = GetCC1Arguments(&Diags, Compilation.get());
+ if (auto Err = ErrOrCC1Args.takeError())
+ return std::move(Err);
+
+ return CreateCI(**ErrOrCC1Args);
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+IncrementalCompilerBuilder::CreateCpp() {
+ std::vector<const char *> Argv;
+ Argv.reserve(5 + 1 + UserArgs.size());
+ Argv.push_back("-xc++");
+#ifdef __EMSCRIPTEN__
+ Argv.push_back("-target");
+ Argv.push_back("wasm32-unknown-emscripten");
+ Argv.push_back("-shared");
+ Argv.push_back("-fvisibility=default");
+#endif
+ Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
+
+ std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
+ return IncrementalCompilerBuilder::create(TT, Argv);
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+IncrementalCompilerBuilder::createCuda(bool device) {
+ std::vector<const char *> Argv;
+ Argv.reserve(5 + 4 + UserArgs.size());
+
+ Argv.push_back("-xcuda");
+ if (device)
+ Argv.push_back("--cuda-device-only");
+ else
+ Argv.push_back("--cuda-host-only");
+
+ std::string SDKPathArg = "--cuda-path=";
+ if (!CudaSDKPath.empty()) {
+ SDKPathArg += CudaSDKPath;
+ Argv.push_back(SDKPathArg.c_str());
+ }
+
+ std::string ArchArg = "--offload-arch=";
+ if (!OffloadArch.empty()) {
+ ArchArg += OffloadArch;
+ Argv.push_back(ArchArg.c_str());
+ }
+
+ Argv.insert(Argv.end(), UserArgs.begin(), UserArgs.end());
+
+ std::string TT = TargetTriple ? *TargetTriple : llvm::sys::getProcessTriple();
+ return IncrementalCompilerBuilder::create(TT, Argv);
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+IncrementalCompilerBuilder::CreateCudaDevice() {
+ return IncrementalCompilerBuilder::createCuda(true);
+}
+
+llvm::Expected<std::unique_ptr<CompilerInstance>>
+IncrementalCompilerBuilder::CreateCudaHost() {
+ return IncrementalCompilerBuilder::createCuda(false);
+}
+
+Interpreter::Interpreter(std::unique_ptr<CompilerInstance> CI,
+ llvm::Error &ErrOut,
+ std::unique_ptr<llvm::orc::LLJITBuilder> JITBuilder)
+ : JITBuilder(std::move(JITBuilder)) {
+ llvm::ErrorAsOutParameter EAO(&ErrOut);
+ auto LLVMCtx = std::make_unique<llvm::LLVMContext>();
+ TSCtx = std::make_unique<llvm::orc::ThreadSafeContext>(std::move(LLVMCtx));
+ IncrParser = std::make_unique<IncrementalParser>(
+ *this, std::move(CI), *TSCtx->getContext(), ErrOut);
+ if (ErrOut)
+ return;
+
+ // Not all frontends support code-generation, e.g. ast-dump actions don't
+ if (IncrParser->getCodeGen()) {
+ if (llvm::Error Err = CreateExecutor()) {
+ ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
+ return;
+ }
+
+ // Process the PTUs that came from initialization. For example -include will
+ // give us a header that's processed at initialization of the preprocessor.
+ for (PartialTranslationUnit &PTU : IncrParser->getPTUs())
+ if (llvm::Error Err = Execute(PTU)) {
+ ErrOut = joinErrors(std::move(ErrOut), std::move(Err));
+ return;
+ }
+ }
+}
+
+Interpreter::~Interpreter() {
+ if (IncrExecutor) {
+ if (llvm::Error Err = IncrExecutor->cleanUp())
+ llvm::report_fatal_error(
+ llvm::Twine("Failed to clean up IncrementalExecutor: ") +
+ toString(std::move(Err)));
+ }
+}
+
+// These better to put in a runtime header but we can't. This is because we
+// can't find the precise resource directory in unittests so we have to hard
+// code them.
+const char *const Runtimes = R"(
+ #define __CLANG_REPL__ 1
+#ifdef __cplusplus
+ #define EXTERN_C extern "C"
+ void *__clang_Interpreter_SetValueWithAlloc(void*, void*, void*);
+ struct __clang_Interpreter_NewTag{} __ci_newtag;
+ void* operator new(__SIZE_TYPE__, void* __p, __clang_Interpreter_NewTag) noexcept;
+ template <class T, class = T (*)() /*disable for arrays*/>
+ void __clang_Interpreter_SetValueCopyArr(T* Src, void* Placement, unsigned long Size) {
+ for (auto Idx = 0; Idx < Size; ++Idx)
+ new ((void*)(((T*)Placement) + Idx), __ci_newtag) T(Src[Idx]);
+ }
+ template <class T, unsigned long N>
+ void __clang_Interpreter_SetValueCopyArr(const T (*Src)[N], void* Placement, unsigned long Size) {
+ __clang_Interpreter_SetValueCopyArr(Src[0], Placement, Size);
+ }
+#else
+ #define EXTERN_C extern
+#endif // __cplusplus
+
+ EXTERN_C void __clang_Interpreter_SetValueNoAlloc(void *This, void *OutVal, void *OpaqueType, ...);
+)";
+
+llvm::Expected<std::unique_ptr<Interpreter>>
+Interpreter::create(std::unique_ptr<CompilerInstance> CI) {
+ llvm::Error Err = llvm::Error::success();
+ auto Interp =
+ std::unique_ptr<Interpreter>(new Interpreter(std::move(CI), Err));
+ if (Err)
+ return std::move(Err);
+
+ // Add runtime code and set a marker to hide it from user code. Undo will not
+ // go through that.
+ auto PTU = Interp->Parse(Runtimes);
+ if (!PTU)
+ return PTU.takeError();
+ Interp->markUserCodeStart();
+
+ Interp->ValuePrintingInfo.resize(4);
+ return std::move(Interp);
+}
+
+llvm::Expected<std::unique_ptr<Interpreter>>
+Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,
+ std::unique_ptr<CompilerInstance> DCI) {
+ // avoid writing fat binary to disk using an in-memory virtual file system
+ llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> IMVFS =
+ std::make_unique<llvm::vfs::InMemoryFileSystem>();
+ llvm::IntrusiveRefCntPtr<llvm::vfs::OverlayFileSystem> OverlayVFS =
+ std::make_unique<llvm::vfs::OverlayFileSystem>(
+ llvm::vfs::getRealFileSystem());
+ OverlayVFS->pushOverlay(IMVFS);
+ CI->createFileManager(OverlayVFS);
+
+ auto Interp = Interpreter::create(std::move(CI));
+ if (auto E = Interp.takeError())
+ return std::move(E);
+
+ llvm::Error Err = llvm::Error::success();
+ auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
+ **Interp, std::move(DCI), *(*Interp)->IncrParser.get(),
+ *(*Interp)->TSCtx->getContext(), IMVFS, Err);
+ if (Err)
+ return std::move(Err);
+
+ (*Interp)->DeviceParser = std::move(DeviceParser);
+
+ return Interp;
+}
+
+const CompilerInstance *Interpreter::getCompilerInstance() const {
+ return IncrParser->getCI();
+}
+
+CompilerInstance *Interpreter::getCompilerInstance() {
+ return IncrParser->getCI();
+}
+
+llvm::Expected<llvm::orc::LLJIT &> Interpreter::getExecutionEngine() {
+ if (!IncrExecutor) {
+ if (auto Err = CreateExecutor())
+ return std::move(Err);
+ }
+
+ return IncrExecutor->GetExecutionEngine();
+}
+
+ASTContext &Interpreter::getASTContext() {
+ return getCompilerInstance()->getASTContext();
+}
+
+const ASTContext &Interpreter::getASTContext() const {
+ return getCompilerInstance()->getASTContext();
+}
+
+void Interpreter::markUserCodeStart() {
+ assert(!InitPTUSize && "We only do this once");
+ InitPTUSize = IncrParser->getPTUs().size();
+}
+
+size_t Interpreter::getEffectivePTUSize() const {
+ std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
+ assert(PTUs.size() >= InitPTUSize && "empty PTU list?");
+ return PTUs.size() - InitPTUSize;
+}
+
+llvm::Expected<PartialTranslationUnit &>
+Interpreter::Parse(llvm::StringRef Code) {
+ // If we have a device parser, parse it first.
+ // The generated code will be included in the host compilation
+ if (DeviceParser) {
+ auto DevicePTU = DeviceParser->Parse(Code);
+ if (auto E = DevicePTU.takeError())
+ return std::move(E);
+ }
+
+ // Tell the interpreter sliently ignore unused expressions since value
+ // printing could cause it.
+ getCompilerInstance()->getDiagnostics().setSeverity(
+ clang::diag::warn_unused_expr, diag::Severity::Ignored, SourceLocation());
+ return IncrParser->Parse(Code);
+}
+
+static llvm::Expected<llvm::orc::JITTargetMachineBuilder>
+createJITTargetMachineBuilder(const std::string &TT) {
+ if (TT == llvm::sys::getProcessTriple())
+ // This fails immediately if the target backend is not registered
+ return llvm::orc::JITTargetMachineBuilder::detectHost();
+
+ // If the target backend is not registered, LLJITBuilder::create() will fail
+ return llvm::orc::JITTargetMachineBuilder(llvm::Triple(TT));
+}
+
+llvm::Error Interpreter::CreateExecutor() {
+ if (IncrExecutor)
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "Execution engine exists",
+ std::error_code());
+ if (!IncrParser->getCodeGen())
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "No code generator available",
+ std::error_code());
+ if (!JITBuilder) {
+ const std::string &TT = getCompilerInstance()->getTargetOpts().Triple;
+ auto JTMB = createJITTargetMachineBuilder(TT);
+ if (!JTMB)
+ return JTMB.takeError();
+ auto JB = IncrementalExecutor::createDefaultJITBuilder(std::move(*JTMB));
+ if (!JB)
+ return JB.takeError();
+ JITBuilder = std::move(*JB);
+ }
+
+ llvm::Error Err = llvm::Error::success();
+#ifdef __EMSCRIPTEN__
+ auto Executor = std::make_unique<WasmIncrementalExecutor>(*TSCtx);
+#else
+ auto Executor =
+ std::make_unique<IncrementalExecutor>(*TSCtx, *JITBuilder, Err);
+#endif
+ if (!Err)
+ IncrExecutor = std::move(Executor);
+
+ return Err;
+}
+
+void Interpreter::ResetExecutor() { IncrExecutor.reset(); }
+
+llvm::Error Interpreter::Execute(PartialTranslationUnit &T) {
+ assert(T.TheModule);
+ if (!IncrExecutor) {
+ auto Err = CreateExecutor();
+ if (Err)
+ return Err;
+ }
+ // FIXME: Add a callback to retain the llvm::Module once the JIT is done.
+ if (auto Err = IncrExecutor->addModule(T))
+ return Err;
+
+ if (auto Err = IncrExecutor->runCtors())
+ return Err;
+
+ return llvm::Error::success();
+}
+
+llvm::Error Interpreter::ParseAndExecute(llvm::StringRef Code, Value *V) {
+
+ auto PTU = Parse(Code);
+ if (!PTU)
+ return PTU.takeError();
+ if (PTU->TheModule)
+ if (llvm::Error Err = Execute(*PTU))
+ return Err;
+
+ if (LastValue.isValid()) {
+ if (!V) {
+ LastValue.dump();
+ LastValue.clear();
+ } else
+ *V = std::move(LastValue);
+ }
+ return llvm::Error::success();
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr>
+Interpreter::getSymbolAddress(GlobalDecl GD) const {
+ if (!IncrExecutor)
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "No execution engine",
+ std::error_code());
+ llvm::StringRef MangledName = IncrParser->GetMangledName(GD);
+ return getSymbolAddress(MangledName);
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr>
+Interpreter::getSymbolAddress(llvm::StringRef IRName) const {
+ if (!IncrExecutor)
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "No execution engine",
+ std::error_code());
+
+ return IncrExecutor->getSymbolAddress(IRName, IncrementalExecutor::IRName);
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr>
+Interpreter::getSymbolAddressFromLinkerName(llvm::StringRef Name) const {
+ if (!IncrExecutor)
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "No execution engine",
+ std::error_code());
+
+ return IncrExecutor->getSymbolAddress(Name, IncrementalExecutor::LinkerName);
+}
+
+llvm::Error Interpreter::Undo(unsigned N) {
+
+ std::list<PartialTranslationUnit> &PTUs = IncrParser->getPTUs();
+ if (N > getEffectivePTUSize())
+ return llvm::make_error<llvm::StringError>("Operation failed. "
+ "Too many undos",
+ std::error_code());
+ for (unsigned I = 0; I < N; I++) {
+ if (IncrExecutor) {
+ if (llvm::Error Err = IncrExecutor->removeModule(PTUs.back()))
+ return Err;
+ }
+
+ IncrParser->CleanUpPTU(PTUs.back());
+ PTUs.pop_back();
+ }
+ return llvm::Error::success();
+}
+
+llvm::Error Interpreter::LoadDynamicLibrary(const char *name) {
+ auto EE = getExecutionEngine();
+ if (!EE)
+ return EE.takeError();
+
+ auto &DL = EE->getDataLayout();
+
+ if (auto DLSG = llvm::orc::DynamicLibrarySearchGenerator::Load(
+ name, DL.getGlobalPrefix()))
+ EE->getMainJITDylib().addGenerator(std::move(*DLSG));
+ else
+ return DLSG.takeError();
+
+ return llvm::Error::success();
+}
+
+llvm::Expected<llvm::orc::ExecutorAddr>
+Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
+ assert(CXXRD && "Cannot compile a destructor for a nullptr");
+ if (auto Dtor = Dtors.find(CXXRD); Dtor != Dtors.end())
+ return Dtor->getSecond();
+
+ if (CXXRD->hasIrrelevantDestructor())
+ return llvm::orc::ExecutorAddr{};
+
+ CXXDestructorDecl *DtorRD =
+ getCompilerInstance()->getSema().LookupDestructor(CXXRD);
+
+ llvm::StringRef Name =
+ IncrParser->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
+ auto AddrOrErr = getSymbolAddress(Name);
+ if (!AddrOrErr)
+ return AddrOrErr.takeError();
+
+ Dtors[CXXRD] = *AddrOrErr;
+ return AddrOrErr;
+}
+
+static constexpr llvm::StringRef MagicRuntimeInterface[] = {
+ "__clang_Interpreter_SetValueNoAlloc",
+ "__clang_Interpreter_SetValueWithAlloc",
+ "__clang_Interpreter_SetValueCopyArr", "__ci_newtag"};
+
+static std::unique_ptr<RuntimeInterfaceBuilder>
+createInProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &Ctx,
+ Sema &S);
+
+std::unique_ptr<RuntimeInterfaceBuilder> Interpreter::FindRuntimeInterface() {
+ if (llvm::all_of(ValuePrintingInfo, [](Expr *E) { return E != nullptr; }))
+ return nullptr;
+
+ Sema &S = getCompilerInstance()->getSema();
+ ASTContext &Ctx = S.getASTContext();
+
+ auto LookupInterface = [&](Expr *&Interface, llvm::StringRef Name) {
+ LookupResult R(S, &Ctx.Idents.get(Name), SourceLocation(),
+ Sema::LookupOrdinaryName,
+ RedeclarationKind::ForVisibleRedeclaration);
+ S.LookupQualifiedName(R, Ctx.getTranslationUnitDecl());
+ if (R.empty())
+ return false;
+
+ CXXScopeSpec CSS;
+ Interface = S.BuildDeclarationNameExpr(CSS, R, /*ADL=*/false).get();
+ return true;
+ };
+
+ if (!LookupInterface(ValuePrintingInfo[NoAlloc],
+ MagicRuntimeInterface[NoAlloc]))
+ return nullptr;
+ if (Ctx.getLangOpts().CPlusPlus) {
+ if (!LookupInterface(ValuePrintingInfo[WithAlloc],
+ MagicRuntimeInterface[WithAlloc]))
+ return nullptr;
+ if (!LookupInterface(ValuePrintingInfo[CopyArray],
+ MagicRuntimeInterface[CopyArray]))
+ return nullptr;
+ if (!LookupInterface(ValuePrintingInfo[NewTag],
+ MagicRuntimeInterface[NewTag]))
+ return nullptr;
+ }
+
+ return createInProcessRuntimeInterfaceBuilder(*this, Ctx, S);
+}
+
+namespace {
+
+class InterfaceKindVisitor
+ : public TypeVisitor<InterfaceKindVisitor, Interpreter::InterfaceKind> {
+ friend class InProcessRuntimeInterfaceBuilder;
+
+ ASTContext &Ctx;
+ Sema &S;
+ Expr *E;
+ llvm::SmallVector<Expr *, 3> Args;
+
+public:
+ InterfaceKindVisitor(ASTContext &Ctx, Sema &S, Expr *E)
+ : Ctx(Ctx), S(S), E(E) {}
+
+ Interpreter::InterfaceKind VisitRecordType(const RecordType *Ty) {
+ return Interpreter::InterfaceKind::WithAlloc;
+ }
+
+ Interpreter::InterfaceKind
+ VisitMemberPointerType(const MemberPointerType *Ty) {
+ return Interpreter::InterfaceKind::WithAlloc;
+ }
+
+ Interpreter::InterfaceKind
+ VisitConstantArrayType(const ConstantArrayType *Ty) {
+ return Interpreter::InterfaceKind::CopyArray;
+ }
+
+ Interpreter::InterfaceKind
+ VisitFunctionProtoType(const FunctionProtoType *Ty) {
+ HandlePtrType(Ty);
+ return Interpreter::InterfaceKind::NoAlloc;
+ }
+
+ Interpreter::InterfaceKind VisitPointerType(const PointerType *Ty) {
+ HandlePtrType(Ty);
+ return Interpreter::InterfaceKind::NoAlloc;
+ }
+
+ Interpreter::InterfaceKind VisitReferenceType(const ReferenceType *Ty) {
+ ExprResult AddrOfE = S.CreateBuiltinUnaryOp(SourceLocation(), UO_AddrOf, E);
+ assert(!AddrOfE.isInvalid() && "Can not create unary expression");
+ Args.push_back(AddrOfE.get());
+ return Interpreter::InterfaceKind::NoAlloc;
+ }
+
+ Interpreter::InterfaceKind VisitBuiltinType(const BuiltinType *Ty) {
+ if (Ty->isNullPtrType())
+ Args.push_back(E);
+ else if (Ty->isFloatingType())
+ Args.push_back(E);
+ else if (Ty->isIntegralOrEnumerationType())
+ HandleIntegralOrEnumType(Ty);
+ else if (Ty->isVoidType()) {
+ // Do we need to still run `E`?
+ }
+
+ return Interpreter::InterfaceKind::NoAlloc;
+ }
+
+ Interpreter::InterfaceKind VisitEnumType(const EnumType *Ty) {
+ HandleIntegralOrEnumType(Ty);
+ return Interpreter::InterfaceKind::NoAlloc;
+ }
+
+private:
+ // Force cast these types to the uint that fits the register size. That way we
+ // reduce the number of overloads of `__clang_Interpreter_SetValueNoAlloc`.
+ void HandleIntegralOrEnumType(const Type *Ty) {
+ uint64_t PtrBits = Ctx.getTypeSize(Ctx.VoidPtrTy);
+ QualType UIntTy = Ctx.getBitIntType(/*Unsigned=*/true, PtrBits);
+ TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(UIntTy);
+ ExprResult CastedExpr =
+ S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
+ assert(!CastedExpr.isInvalid() && "Cannot create cstyle cast expr");
+ Args.push_back(CastedExpr.get());
+ }
+
+ void HandlePtrType(const Type *Ty) {
+ TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ctx.VoidPtrTy);
+ ExprResult CastedExpr =
+ S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E);
+ assert(!CastedExpr.isInvalid() && "Can not create cstyle cast expression");
+ Args.push_back(CastedExpr.get());
+ }
+};
+
+class InProcessRuntimeInterfaceBuilder : public RuntimeInterfaceBuilder {
+ Interpreter &Interp;
+ ASTContext &Ctx;
+ Sema &S;
+
+public:
+ InProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &C, Sema &S)
+ : Interp(Interp), Ctx(C), S(S) {}
+
+ TransformExprFunction *getPrintValueTransformer() override {
+ return &transformForValuePrinting;
+ }
+
+private:
+ static ExprResult transformForValuePrinting(RuntimeInterfaceBuilder *Builder,
+ Expr *E,
+ ArrayRef<Expr *> FixedArgs) {
+ auto *B = static_cast<InProcessRuntimeInterfaceBuilder *>(Builder);
+
+ // Get rid of ExprWithCleanups.
+ if (auto *EWC = llvm::dyn_cast_if_present<ExprWithCleanups>(E))
+ E = EWC->getSubExpr();
+
+ InterfaceKindVisitor Visitor(B->Ctx, B->S, E);
+
+ // The Interpreter* parameter and the out parameter `OutVal`.
+ for (Expr *E : FixedArgs)
+ Visitor.Args.push_back(E);
+
+ QualType Ty = E->getType();
+ QualType DesugaredTy = Ty.getDesugaredType(B->Ctx);
+
+ // For lvalue struct, we treat it as a reference.
+ if (DesugaredTy->isRecordType() && E->isLValue()) {
+ DesugaredTy = B->Ctx.getLValueReferenceType(DesugaredTy);
+ Ty = B->Ctx.getLValueReferenceType(Ty);
+ }
+
+ Expr *TypeArg = CStyleCastPtrExpr(B->S, B->Ctx.VoidPtrTy,
+ (uintptr_t)Ty.getAsOpaquePtr());
+ // The QualType parameter `OpaqueType`, represented as `void*`.
+ Visitor.Args.push_back(TypeArg);
+
+ // We push the last parameter based on the type of the Expr. Note we need
+ // special care for rvalue struct.
+ Interpreter::InterfaceKind Kind = Visitor.Visit(&*DesugaredTy);
+ switch (Kind) {
+ case Interpreter::InterfaceKind::WithAlloc:
+ case Interpreter::InterfaceKind::CopyArray: {
+ // __clang_Interpreter_SetValueWithAlloc.
+ ExprResult AllocCall = B->S.ActOnCallExpr(
+ /*Scope=*/nullptr,
+ B->Interp
+ .getValuePrintingInfo()[Interpreter::InterfaceKind::WithAlloc],
+ E->getBeginLoc(), Visitor.Args, E->getEndLoc());
+ assert(!AllocCall.isInvalid() && "Can't create runtime interface call!");
+
+ TypeSourceInfo *TSI =
+ B->Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
+
+ // Force CodeGen to emit destructor.
+ if (auto *RD = Ty->getAsCXXRecordDecl()) {
+ auto *Dtor = B->S.LookupDestructor(RD);
+ Dtor->addAttr(UsedAttr::CreateImplicit(B->Ctx));
+ B->Interp.getCompilerInstance()->getASTConsumer().HandleTopLevelDecl(
+ DeclGroupRef(Dtor));
+ }
+
+ // __clang_Interpreter_SetValueCopyArr.
+ if (Kind == Interpreter::InterfaceKind::CopyArray) {
+ const auto *ConstantArrTy =
+ cast<ConstantArrayType>(DesugaredTy.getTypePtr());
+ size_t ArrSize = B->Ctx.getConstantArrayElementCount(ConstantArrTy);
+ Expr *ArrSizeExpr = IntegerLiteralExpr(B->Ctx, ArrSize);
+ Expr *Args[] = {E, AllocCall.get(), ArrSizeExpr};
+ return B->S.ActOnCallExpr(
+ /*Scope *=*/nullptr,
+ B->Interp
+ .getValuePrintingInfo()[Interpreter::InterfaceKind::CopyArray],
+ SourceLocation(), Args, SourceLocation());
+ }
+ Expr *Args[] = {
+ AllocCall.get(),
+ B->Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NewTag]};
+ ExprResult CXXNewCall = B->S.BuildCXXNew(
+ E->getSourceRange(),
+ /*UseGlobal=*/true, /*PlacementLParen=*/SourceLocation(), Args,
+ /*PlacementRParen=*/SourceLocation(),
+ /*TypeIdParens=*/SourceRange(), TSI->getType(), TSI, std::nullopt,
+ E->getSourceRange(), E);
+
+ assert(!CXXNewCall.isInvalid() &&
+ "Can't create runtime placement new call!");
+
+ return B->S.ActOnFinishFullExpr(CXXNewCall.get(),
+ /*DiscardedValue=*/false);
+ }
+ // __clang_Interpreter_SetValueNoAlloc.
+ case Interpreter::InterfaceKind::NoAlloc: {
+ return B->S.ActOnCallExpr(
+ /*Scope=*/nullptr,
+ B->Interp.getValuePrintingInfo()[Interpreter::InterfaceKind::NoAlloc],
+ E->getBeginLoc(), Visitor.Args, E->getEndLoc());
+ }
+ default:
+ llvm_unreachable("Unhandled Interpreter::InterfaceKind");
+ }
+ }
+};
+} // namespace
+
+static std::unique_ptr<RuntimeInterfaceBuilder>
+createInProcessRuntimeInterfaceBuilder(Interpreter &Interp, ASTContext &Ctx,
+ Sema &S) {
+ return std::make_unique<InProcessRuntimeInterfaceBuilder>(Interp, Ctx, S);
+}
+
+// This synthesizes a call expression to a speciall
+// function that is responsible for generating the Value.
+// In general, we transform:
+// clang-repl> x
+// To:
+// // 1. If x is a built-in type like int, float.
+// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType, x);
+// // 2. If x is a struct, and a lvalue.
+// __clang_Interpreter_SetValueNoAlloc(ThisInterp, OpaqueValue, xQualType,
+// &x);
+// // 3. If x is a struct, but a rvalue.
+// new (__clang_Interpreter_SetValueWithAlloc(ThisInterp, OpaqueValue,
+// xQualType)) (x);
+
+Expr *Interpreter::SynthesizeExpr(Expr *E) {
+ Sema &S = getCompilerInstance()->getSema();
+ ASTContext &Ctx = S.getASTContext();
+
+ if (!RuntimeIB) {
+ RuntimeIB = FindRuntimeInterface();
+ AddPrintValueCall = RuntimeIB->getPrintValueTransformer();
+ }
+
+ assert(AddPrintValueCall &&
+ "We don't have a runtime interface for pretty print!");
+
+ // Create parameter `ThisInterp`.
+ auto *ThisInterp = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)this);
+
+ // Create parameter `OutVal`.
+ auto *OutValue = CStyleCastPtrExpr(S, Ctx.VoidPtrTy, (uintptr_t)&LastValue);
+
+ // Build `__clang_Interpreter_SetValue*` call.
+ ExprResult Result =
+ AddPrintValueCall(RuntimeIB.get(), E, {ThisInterp, OutValue});
+
+ // It could fail, like printing an array type in C. (not supported)
+ if (Result.isInvalid())
+ return E;
+ return Result.get();
+}
+
+// Temporary rvalue struct that need special care.
+REPL_EXTERNAL_VISIBILITY void *
+__clang_Interpreter_SetValueWithAlloc(void *This, void *OutVal,
+ void *OpaqueType) {
+ Value &VRef = *(Value *)OutVal;
+ VRef = Value(static_cast<Interpreter *>(This), OpaqueType);
+ return VRef.getPtr();
+}
+
+extern "C" void REPL_EXTERNAL_VISIBILITY __clang_Interpreter_SetValueNoAlloc(
+ void *This, void *OutVal, void *OpaqueType, ...) {
+ Value &VRef = *(Value *)OutVal;
+ Interpreter *I = static_cast<Interpreter *>(This);
+ VRef = Value(I, OpaqueType);
+ if (VRef.isVoid())
+ return;
+
+ va_list args;
+ va_start(args, /*last named param*/ OpaqueType);
+
+ QualType QT = VRef.getType();
+ if (VRef.getKind() == Value::K_PtrOrObj) {
+ VRef.setPtr(va_arg(args, void *));
+ } else {
+ if (const auto *ET = QT->getAs<EnumType>())
+ QT = ET->getDecl()->getIntegerType();
+ switch (QT->castAs<BuiltinType>()->getKind()) {
+ default:
+ llvm_unreachable("unknown type kind!");
+ break;
+ // Types shorter than int are resolved as int, else va_arg has UB.
+ case BuiltinType::Bool:
+ VRef.setBool(va_arg(args, int));
+ break;
+ case BuiltinType::Char_S:
+ VRef.setChar_S(va_arg(args, int));
+ break;
+ case BuiltinType::SChar:
+ VRef.setSChar(va_arg(args, int));
+ break;
+ case BuiltinType::Char_U:
+ VRef.setChar_U(va_arg(args, unsigned));
+ break;
+ case BuiltinType::UChar:
+ VRef.setUChar(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Short:
+ VRef.setShort(va_arg(args, int));
+ break;
+ case BuiltinType::UShort:
+ VRef.setUShort(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Int:
+ VRef.setInt(va_arg(args, int));
+ break;
+ case BuiltinType::UInt:
+ VRef.setUInt(va_arg(args, unsigned));
+ break;
+ case BuiltinType::Long:
+ VRef.setLong(va_arg(args, long));
+ break;
+ case BuiltinType::ULong:
+ VRef.setULong(va_arg(args, unsigned long));
+ break;
+ case BuiltinType::LongLong:
+ VRef.setLongLong(va_arg(args, long long));
+ break;
+ case BuiltinType::ULongLong:
+ VRef.setULongLong(va_arg(args, unsigned long long));
+ break;
+ // Types shorter than double are resolved as double, else va_arg has UB.
+ case BuiltinType::Float:
+ VRef.setFloat(va_arg(args, double));
+ break;
+ case BuiltinType::Double:
+ VRef.setDouble(va_arg(args, double));
+ break;
+ case BuiltinType::LongDouble:
+ VRef.setLongDouble(va_arg(args, long double));
+ break;
+ // See REPL_BUILTIN_TYPES.
+ }
+ }
+ va_end(args);
+}
+
+// A trampoline to work around the fact that operator placement new cannot
+// really be forward declared due to libc++ and libstdc++ declaration mismatch.
+// FIXME: __clang_Interpreter_NewTag is ODR violation because we get the same
+// definition in the interpreter runtime. We should move it in a runtime header
+// which gets included by the interpreter and here.
+struct __clang_Interpreter_NewTag {};
+REPL_EXTERNAL_VISIBILITY void *
+operator new(size_t __sz, void *__p, __clang_Interpreter_NewTag) noexcept {
+ // Just forward to the standard operator placement new.
+ return operator new(__sz, __p);
+}
diff --git a/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.cpp b/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.cpp
new file mode 100644
index 000000000000..45f6322b8461
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.cpp
@@ -0,0 +1,111 @@
+//===--- InterpreterUtils.cpp - Incremental Utils --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements some common utils used in the incremental library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "InterpreterUtils.h"
+
+namespace clang {
+
+IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val) {
+ return IntegerLiteral::Create(C, llvm::APSInt::getUnsigned(Val),
+ C.UnsignedLongLongTy, SourceLocation());
+}
+
+Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E) {
+ ASTContext &Ctx = S.getASTContext();
+ if (!Ty->isPointerType())
+ Ty = Ctx.getPointerType(Ty);
+
+ TypeSourceInfo *TSI = Ctx.getTrivialTypeSourceInfo(Ty, SourceLocation());
+ Expr *Result =
+ S.BuildCStyleCastExpr(SourceLocation(), TSI, SourceLocation(), E).get();
+ assert(Result && "Cannot create CStyleCastPtrExpr");
+ return Result;
+}
+
+Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, uintptr_t Ptr) {
+ ASTContext &Ctx = S.getASTContext();
+ return CStyleCastPtrExpr(S, Ty, IntegerLiteralExpr(Ctx, (uint64_t)Ptr));
+}
+
+Sema::DeclGroupPtrTy CreateDGPtrFrom(Sema &S, Decl *D) {
+ SmallVector<Decl *, 1> DeclsInGroup;
+ DeclsInGroup.push_back(D);
+ Sema::DeclGroupPtrTy DeclGroupPtr = S.BuildDeclaratorGroup(DeclsInGroup);
+ return DeclGroupPtr;
+}
+
+NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name,
+ const DeclContext *Within) {
+ DeclarationName DName = &S.Context.Idents.get(Name);
+ LookupResult R(S, DName, SourceLocation(),
+ Sema::LookupNestedNameSpecifierName);
+ R.suppressDiagnostics();
+ if (!Within)
+ S.LookupName(R, S.TUScope);
+ else {
+ if (const auto *TD = dyn_cast<clang::TagDecl>(Within);
+ TD && !TD->getDefinition())
+ // No definition, no lookup result.
+ return nullptr;
+
+ S.LookupQualifiedName(R, const_cast<DeclContext *>(Within));
+ }
+
+ if (R.empty())
+ return nullptr;
+
+ R.resolveKind();
+
+ return dyn_cast<NamespaceDecl>(R.getFoundDecl());
+}
+
+NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
+ const DeclContext *Within) {
+ DeclarationName DName = &S.Context.Idents.get(Name);
+ LookupResult R(S, DName, SourceLocation(), Sema::LookupOrdinaryName,
+ RedeclarationKind::ForVisibleRedeclaration);
+
+ R.suppressDiagnostics();
+
+ if (!Within)
+ S.LookupName(R, S.TUScope);
+ else {
+ const DeclContext *PrimaryWithin = nullptr;
+ if (const auto *TD = dyn_cast<TagDecl>(Within))
+ PrimaryWithin = llvm::dyn_cast_or_null<DeclContext>(TD->getDefinition());
+ else
+ PrimaryWithin = Within->getPrimaryContext();
+
+ // No definition, no lookup result.
+ if (!PrimaryWithin)
+ return nullptr;
+
+ S.LookupQualifiedName(R, const_cast<DeclContext *>(PrimaryWithin));
+ }
+
+ if (R.empty())
+ return nullptr;
+ R.resolveKind();
+
+ if (R.isSingleResult())
+ return llvm::dyn_cast<NamedDecl>(R.getFoundDecl());
+
+ return nullptr;
+}
+
+std::string GetFullTypeName(ASTContext &Ctx, QualType QT) {
+ PrintingPolicy Policy(Ctx.getPrintingPolicy());
+ Policy.SuppressScope = false;
+ Policy.AnonymousTagLocations = false;
+ return QT.getAsString(Policy);
+}
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.h b/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.h
new file mode 100644
index 000000000000..8df158c17d49
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/InterpreterUtils.h
@@ -0,0 +1,54 @@
+//===--- InterpreterUtils.h - Incremental Utils --------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements some common utils used in the incremental library.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_INTERPRETER_UTILS_H
+#define LLVM_CLANG_INTERPRETER_UTILS_H
+
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Mangle.h"
+#include "clang/AST/TypeVisitor.h"
+#include "clang/Basic/TargetInfo.h"
+#include "clang/CodeGen/ModuleBuilder.h"
+#include "clang/CodeGen/ObjectFilePCHContainerOperations.h"
+#include "clang/Driver/Compilation.h"
+#include "clang/Driver/Driver.h"
+#include "clang/Driver/Job.h"
+#include "clang/Driver/Options.h"
+#include "clang/Driver/Tool.h"
+#include "clang/Frontend/CompilerInstance.h"
+#include "clang/Frontend/TextDiagnosticBuffer.h"
+#include "clang/Lex/PreprocessorOptions.h"
+
+#include "clang/Sema/Lookup.h"
+#include "llvm/IR/Module.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/TargetParser/Host.h"
+
+namespace clang {
+IntegerLiteral *IntegerLiteralExpr(ASTContext &C, uint64_t Val);
+
+Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, Expr *E);
+
+Expr *CStyleCastPtrExpr(Sema &S, QualType Ty, uintptr_t Ptr);
+
+Sema::DeclGroupPtrTy CreateDGPtrFrom(Sema &S, Decl *D);
+
+NamespaceDecl *LookupNamespace(Sema &S, llvm::StringRef Name,
+ const DeclContext *Within = nullptr);
+
+NamedDecl *LookupNamed(Sema &S, llvm::StringRef Name,
+ const DeclContext *Within);
+
+std::string GetFullTypeName(ASTContext &Ctx, QualType QT);
+} // namespace clang
+
+#endif
diff --git a/contrib/llvm-project/clang/lib/Interpreter/Value.cpp b/contrib/llvm-project/clang/lib/Interpreter/Value.cpp
new file mode 100644
index 000000000000..eb2ce9c9fd33
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/Value.cpp
@@ -0,0 +1,269 @@
+//===------------ Value.cpp - Definition of interpreter value -------------===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the class that used to represent a value in incremental
+// C++.
+//
+//===----------------------------------------------------------------------===//
+
+#include "clang/Interpreter/Value.h"
+#include "clang/AST/ASTContext.h"
+#include "clang/AST/Type.h"
+#include "clang/Interpreter/Interpreter.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/raw_os_ostream.h"
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+namespace {
+
+// This is internal buffer maintained by Value, used to hold temporaries.
+class ValueStorage {
+public:
+ using DtorFunc = void (*)(void *);
+
+ static unsigned char *CreatePayload(void *DtorF, size_t AllocSize,
+ size_t ElementsSize) {
+ if (AllocSize < sizeof(Canary))
+ AllocSize = sizeof(Canary);
+ unsigned char *Buf =
+ new unsigned char[ValueStorage::getPayloadOffset() + AllocSize];
+ ValueStorage *VS = new (Buf) ValueStorage(DtorF, AllocSize, ElementsSize);
+ std::memcpy(VS->getPayload(), Canary, sizeof(Canary));
+ return VS->getPayload();
+ }
+
+ unsigned char *getPayload() { return Storage; }
+ const unsigned char *getPayload() const { return Storage; }
+
+ static unsigned getPayloadOffset() {
+ static ValueStorage Dummy(nullptr, 0, 0);
+ return Dummy.getPayload() - reinterpret_cast<unsigned char *>(&Dummy);
+ }
+
+ static ValueStorage *getFromPayload(void *Payload) {
+ ValueStorage *R = reinterpret_cast<ValueStorage *>(
+ (unsigned char *)Payload - getPayloadOffset());
+ return R;
+ }
+
+ void Retain() { ++RefCnt; }
+
+ void Release() {
+ assert(RefCnt > 0 && "Can't release if reference count is already zero");
+ if (--RefCnt == 0) {
+ // We have a non-trivial dtor.
+ if (Dtor && IsAlive()) {
+ assert(Elements && "We at least should have 1 element in Value");
+ size_t Stride = AllocSize / Elements;
+ for (size_t Idx = 0; Idx < Elements; ++Idx)
+ (*Dtor)(getPayload() + Idx * Stride);
+ }
+ delete[] reinterpret_cast<unsigned char *>(this);
+ }
+ }
+
+ // Check whether the storage is valid by validating the canary bits.
+ // If someone accidentally write some invalid bits in the storage, the canary
+ // will be changed first, and `IsAlive` will return false then.
+ bool IsAlive() const {
+ return std::memcmp(getPayload(), Canary, sizeof(Canary)) != 0;
+ }
+
+private:
+ ValueStorage(void *DtorF, size_t AllocSize, size_t ElementsNum)
+ : RefCnt(1), Dtor(reinterpret_cast<DtorFunc>(DtorF)),
+ AllocSize(AllocSize), Elements(ElementsNum) {}
+
+ mutable unsigned RefCnt;
+ DtorFunc Dtor = nullptr;
+ size_t AllocSize = 0;
+ size_t Elements = 0;
+ unsigned char Storage[1];
+
+ // These are some canary bits that are used for protecting the storage been
+ // damaged.
+ static constexpr unsigned char Canary[8] = {0x4c, 0x37, 0xad, 0x8f,
+ 0x2d, 0x23, 0x95, 0x91};
+};
+} // namespace
+
+namespace clang {
+
+static Value::Kind ConvertQualTypeToKind(const ASTContext &Ctx, QualType QT) {
+ if (Ctx.hasSameType(QT, Ctx.VoidTy))
+ return Value::K_Void;
+
+ if (const auto *ET = QT->getAs<EnumType>())
+ QT = ET->getDecl()->getIntegerType();
+
+ const auto *BT = QT->getAs<BuiltinType>();
+ if (!BT || BT->isNullPtrType())
+ return Value::K_PtrOrObj;
+
+ switch (QT->castAs<BuiltinType>()->getKind()) {
+ default:
+ assert(false && "Type not supported");
+ return Value::K_Unspecified;
+#define X(type, name) \
+ case BuiltinType::name: \
+ return Value::K_##name;
+ REPL_BUILTIN_TYPES
+#undef X
+ }
+}
+
+Value::Value(Interpreter *In, void *Ty) : Interp(In), OpaqueType(Ty) {
+ setKind(ConvertQualTypeToKind(getASTContext(), getType()));
+ if (ValueKind == K_PtrOrObj) {
+ QualType Canon = getType().getCanonicalType();
+ if ((Canon->isPointerType() || Canon->isObjectType() ||
+ Canon->isReferenceType()) &&
+ (Canon->isRecordType() || Canon->isConstantArrayType() ||
+ Canon->isMemberPointerType())) {
+ IsManuallyAlloc = true;
+ // Compile dtor function.
+ Interpreter &Interp = getInterpreter();
+ void *DtorF = nullptr;
+ size_t ElementsSize = 1;
+ QualType DtorTy = getType();
+
+ if (const auto *ArrTy =
+ llvm::dyn_cast<ConstantArrayType>(DtorTy.getTypePtr())) {
+ DtorTy = ArrTy->getElementType();
+ llvm::APInt ArrSize(sizeof(size_t) * 8, 1);
+ do {
+ ArrSize *= ArrTy->getSize();
+ ArrTy = llvm::dyn_cast<ConstantArrayType>(
+ ArrTy->getElementType().getTypePtr());
+ } while (ArrTy);
+ ElementsSize = static_cast<size_t>(ArrSize.getZExtValue());
+ }
+ if (const auto *RT = DtorTy->getAs<RecordType>()) {
+ if (CXXRecordDecl *CXXRD =
+ llvm::dyn_cast<CXXRecordDecl>(RT->getDecl())) {
+ if (llvm::Expected<llvm::orc::ExecutorAddr> Addr =
+ Interp.CompileDtorCall(CXXRD))
+ DtorF = reinterpret_cast<void *>(Addr->getValue());
+ else
+ llvm::logAllUnhandledErrors(Addr.takeError(), llvm::errs());
+ }
+ }
+
+ size_t AllocSize =
+ getASTContext().getTypeSizeInChars(getType()).getQuantity();
+ unsigned char *Payload =
+ ValueStorage::CreatePayload(DtorF, AllocSize, ElementsSize);
+ setPtr((void *)Payload);
+ }
+ }
+}
+
+Value::Value(const Value &RHS)
+ : Interp(RHS.Interp), OpaqueType(RHS.OpaqueType), Data(RHS.Data),
+ ValueKind(RHS.ValueKind), IsManuallyAlloc(RHS.IsManuallyAlloc) {
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Retain();
+}
+
+Value::Value(Value &&RHS) noexcept {
+ Interp = std::exchange(RHS.Interp, nullptr);
+ OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
+ Data = RHS.Data;
+ ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
+ IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
+
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Release();
+}
+
+Value &Value::operator=(const Value &RHS) {
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Release();
+
+ Interp = RHS.Interp;
+ OpaqueType = RHS.OpaqueType;
+ Data = RHS.Data;
+ ValueKind = RHS.ValueKind;
+ IsManuallyAlloc = RHS.IsManuallyAlloc;
+
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Retain();
+
+ return *this;
+}
+
+Value &Value::operator=(Value &&RHS) noexcept {
+ if (this != &RHS) {
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Release();
+
+ Interp = std::exchange(RHS.Interp, nullptr);
+ OpaqueType = std::exchange(RHS.OpaqueType, nullptr);
+ ValueKind = std::exchange(RHS.ValueKind, K_Unspecified);
+ IsManuallyAlloc = std::exchange(RHS.IsManuallyAlloc, false);
+
+ Data = RHS.Data;
+ }
+ return *this;
+}
+
+void Value::clear() {
+ if (IsManuallyAlloc)
+ ValueStorage::getFromPayload(getPtr())->Release();
+ ValueKind = K_Unspecified;
+ OpaqueType = nullptr;
+ Interp = nullptr;
+ IsManuallyAlloc = false;
+}
+
+Value::~Value() { clear(); }
+
+void *Value::getPtr() const {
+ assert(ValueKind == K_PtrOrObj);
+ return Data.m_Ptr;
+}
+
+QualType Value::getType() const {
+ return QualType::getFromOpaquePtr(OpaqueType);
+}
+
+Interpreter &Value::getInterpreter() {
+ assert(Interp != nullptr &&
+ "Can't get interpreter from a default constructed value");
+ return *Interp;
+}
+
+const Interpreter &Value::getInterpreter() const {
+ assert(Interp != nullptr &&
+ "Can't get interpreter from a default constructed value");
+ return *Interp;
+}
+
+ASTContext &Value::getASTContext() { return getInterpreter().getASTContext(); }
+
+const ASTContext &Value::getASTContext() const {
+ return getInterpreter().getASTContext();
+}
+
+void Value::dump() const { print(llvm::outs()); }
+
+void Value::printType(llvm::raw_ostream &Out) const {
+ Out << "Not implement yet.\n";
+}
+void Value::printData(llvm::raw_ostream &Out) const {
+ Out << "Not implement yet.\n";
+}
+void Value::print(llvm::raw_ostream &Out) const {
+ assert(OpaqueType != nullptr && "Can't print default Value");
+ Out << "Not implement yet.\n";
+}
+
+} // namespace clang
diff --git a/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp b/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp
new file mode 100644
index 000000000000..aa10b160ccf8
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/Wasm.cpp
@@ -0,0 +1,149 @@
+//===----------------- Wasm.cpp - Wasm Interpreter --------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements interpreter support for code execution in WebAssembly.
+//
+//===----------------------------------------------------------------------===//
+
+#include "Wasm.h"
+#include "IncrementalExecutor.h"
+
+#include <llvm/IR/LegacyPassManager.h>
+#include <llvm/IR/Module.h>
+#include <llvm/MC/TargetRegistry.h>
+#include <llvm/Target/TargetMachine.h>
+
+#include <clang/Interpreter/Interpreter.h>
+
+#include <string>
+
+namespace lld {
+enum Flavor {
+ Invalid,
+ Gnu, // -flavor gnu
+ MinGW, // -flavor gnu MinGW
+ WinLink, // -flavor link
+ Darwin, // -flavor darwin
+ Wasm, // -flavor wasm
+};
+
+using Driver = bool (*)(llvm::ArrayRef<const char *>, llvm::raw_ostream &,
+ llvm::raw_ostream &, bool, bool);
+
+struct DriverDef {
+ Flavor f;
+ Driver d;
+};
+
+struct Result {
+ int retCode;
+ bool canRunAgain;
+};
+
+Result lldMain(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS, llvm::ArrayRef<DriverDef> drivers);
+
+namespace wasm {
+bool link(llvm::ArrayRef<const char *> args, llvm::raw_ostream &stdoutOS,
+ llvm::raw_ostream &stderrOS, bool exitEarly, bool disableOutput);
+} // namespace wasm
+} // namespace lld
+
+#include <dlfcn.h>
+
+namespace clang {
+
+WasmIncrementalExecutor::WasmIncrementalExecutor(
+ llvm::orc::ThreadSafeContext &TSC)
+ : IncrementalExecutor(TSC) {}
+
+llvm::Error WasmIncrementalExecutor::addModule(PartialTranslationUnit &PTU) {
+ std::string ErrorString;
+
+ const llvm::Target *Target = llvm::TargetRegistry::lookupTarget(
+ PTU.TheModule->getTargetTriple(), ErrorString);
+ if (!Target) {
+ return llvm::make_error<llvm::StringError>("Failed to create Wasm Target: ",
+ llvm::inconvertibleErrorCode());
+ }
+
+ llvm::TargetOptions TO = llvm::TargetOptions();
+ llvm::TargetMachine *TargetMachine = Target->createTargetMachine(
+ PTU.TheModule->getTargetTriple(), "", "", TO, llvm::Reloc::Model::PIC_);
+ PTU.TheModule->setDataLayout(TargetMachine->createDataLayout());
+ std::string ObjectFileName = PTU.TheModule->getName().str() + ".o";
+ std::string BinaryFileName = PTU.TheModule->getName().str() + ".wasm";
+
+ std::error_code Error;
+ llvm::raw_fd_ostream ObjectFileOutput(llvm::StringRef(ObjectFileName), Error);
+
+ llvm::legacy::PassManager PM;
+ if (TargetMachine->addPassesToEmitFile(PM, ObjectFileOutput, nullptr,
+ llvm::CodeGenFileType::ObjectFile)) {
+ return llvm::make_error<llvm::StringError>(
+ "Wasm backend cannot produce object.", llvm::inconvertibleErrorCode());
+ }
+
+ if (!PM.run(*PTU.TheModule)) {
+
+ return llvm::make_error<llvm::StringError>("Failed to emit Wasm object.",
+ llvm::inconvertibleErrorCode());
+ }
+
+ ObjectFileOutput.close();
+
+ std::vector<const char *> LinkerArgs = {"wasm-ld",
+ "-shared",
+ "--import-memory",
+ "--experimental-pic",
+ "--stack-first",
+ "--allow-undefined",
+ ObjectFileName.c_str(),
+ "-o",
+ BinaryFileName.c_str()};
+
+ const lld::DriverDef WasmDriver = {lld::Flavor::Wasm, &lld::wasm::link};
+ std::vector<lld::DriverDef> WasmDriverArgs;
+ WasmDriverArgs.push_back(WasmDriver);
+ lld::Result Result =
+ lld::lldMain(LinkerArgs, llvm::outs(), llvm::errs(), WasmDriverArgs);
+
+ if (Result.retCode)
+ return llvm::make_error<llvm::StringError>(
+ "Failed to link incremental module", llvm::inconvertibleErrorCode());
+
+ void *LoadedLibModule =
+ dlopen(BinaryFileName.c_str(), RTLD_NOW | RTLD_GLOBAL);
+ if (LoadedLibModule == nullptr) {
+ llvm::errs() << dlerror() << '\n';
+ return llvm::make_error<llvm::StringError>(
+ "Failed to load incremental module", llvm::inconvertibleErrorCode());
+ }
+
+ return llvm::Error::success();
+}
+
+llvm::Error WasmIncrementalExecutor::removeModule(PartialTranslationUnit &PTU) {
+ return llvm::make_error<llvm::StringError>("Not implemented yet",
+ llvm::inconvertibleErrorCode());
+}
+
+llvm::Error WasmIncrementalExecutor::runCtors() const {
+ // This seems to be automatically done when using dlopen()
+ return llvm::Error::success();
+}
+
+llvm::Error WasmIncrementalExecutor::cleanUp() {
+ // Can't call cleanUp through IncrementalExecutor as it
+ // tries to deinitialize JIT which hasn't been initialized
+ return llvm::Error::success();
+}
+
+WasmIncrementalExecutor::~WasmIncrementalExecutor() = default;
+
+} // namespace clang \ No newline at end of file
diff --git a/contrib/llvm-project/clang/lib/Interpreter/Wasm.h b/contrib/llvm-project/clang/lib/Interpreter/Wasm.h
new file mode 100644
index 000000000000..4632613326d3
--- /dev/null
+++ b/contrib/llvm-project/clang/lib/Interpreter/Wasm.h
@@ -0,0 +1,38 @@
+//===------------------ Wasm.h - Wasm Interpreter ---------------*- C++ -*-===//
+//
+// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
+// See https://llvm.org/LICENSE.txt for license information.
+// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
+//
+//===----------------------------------------------------------------------===//
+//
+// This file implements interpreter support for code execution in WebAssembly.
+//
+//===----------------------------------------------------------------------===//
+
+#ifndef LLVM_CLANG_LIB_INTERPRETER_WASM_H
+#define LLVM_CLANG_LIB_INTERPRETER_WASM_H
+
+#ifndef __EMSCRIPTEN__
+#error "This requires emscripten."
+#endif // __EMSCRIPTEN__
+
+#include "IncrementalExecutor.h"
+
+namespace clang {
+
+class WasmIncrementalExecutor : public IncrementalExecutor {
+public:
+ WasmIncrementalExecutor(llvm::orc::ThreadSafeContext &TSC);
+
+ llvm::Error addModule(PartialTranslationUnit &PTU) override;
+ llvm::Error removeModule(PartialTranslationUnit &PTU) override;
+ llvm::Error runCtors() const override;
+ llvm::Error cleanUp() override;
+
+ ~WasmIncrementalExecutor() override;
+};
+
+} // namespace clang
+
+#endif // LLVM_CLANG_LIB_INTERPRETER_WASM_H