Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 0 additions & 16 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,6 @@ class ThreadSafeContext;
namespace clang {

class CompilerInstance;
class CodeGenerator;
class CXXRecordDecl;
class Decl;
class IncrementalExecutor;
Expand Down Expand Up @@ -110,10 +109,6 @@ class Interpreter {
// printing happens, it's in an invalid state.
Value LastValue;

/// 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;

/// Compiler instance performing the incremental compilation.
std::unique_ptr<CompilerInstance> CI;

Expand Down Expand Up @@ -175,15 +170,9 @@ class Interpreter {
llvm::Expected<llvm::orc::ExecutorAddr>
getSymbolAddressFromLinkerName(llvm::StringRef LinkerName) const;

std::unique_ptr<llvm::Module> GenModule(IncrementalAction *Action = nullptr);
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
std::unique_ptr<llvm::Module> M = {},
IncrementalAction *Action = nullptr);

private:
size_t getEffectivePTUSize() const;
void markUserCodeStart();
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);

// A cache for the compiled destructors used to for de-allocation of managed
// clang::Values.
Expand All @@ -206,11 +195,6 @@ class Interpreter {
// This function forces emission of the needed dtor.
llvm::Expected<llvm::orc::ExecutorAddr>
CompileDtorCall(CXXRecordDecl *CXXRD) const;

/// @}
/// @name Code generation
/// @{
CodeGenerator *getCodeGen(IncrementalAction *Action = nullptr) const;
};
} // namespace clang

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Interpreter/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ endif()
add_clang_library(clangInterpreter
DeviceOffload.cpp
CodeCompletion.cpp
IncrementalAction.cpp
IncrementalExecutor.cpp
IncrementalParser.cpp
Interpreter.cpp
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Interpreter/DeviceOffload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,10 @@ namespace clang {

IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
IncrementalAction *DeviceAct,
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs)
: IncrementalParser(DeviceInstance, Err), PTUs(PTUs), VFS(FS),
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
: IncrementalParser(DeviceInstance, DeviceAct, Err, PTUs), VFS(FS),
CodeGenOpts(HostInstance.getCodeGenOpts()),
TargetOpts(DeviceInstance.getTargetOpts()) {
if (Err)
Expand Down
5 changes: 3 additions & 2 deletions clang/lib/Interpreter/DeviceOffload.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,15 +22,16 @@ struct PartialTranslationUnit;
class CompilerInstance;
class CodeGenOptions;
class TargetOptions;
class IncrementalAction;

class IncrementalCUDADeviceParser : public IncrementalParser {
const std::list<PartialTranslationUnit> &PTUs;

public:
IncrementalCUDADeviceParser(
CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
IncrementalAction *DeviceAct,
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> VFS,
llvm::Error &Err, const std::list<PartialTranslationUnit> &PTUs);
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs);

// Generate PTX for the last PTU.
llvm::Expected<llvm::StringRef> GeneratePTX();
Expand Down
151 changes: 151 additions & 0 deletions clang/lib/Interpreter/IncrementalAction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,151 @@
//===--- IncrementalAction.h - Incremental Frontend Action -*- 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
//
//===----------------------------------------------------------------------===//

#include "IncrementalAction.h"

#include "clang/AST/ASTConsumer.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendOptions.h"
#include "clang/FrontendTool/Utils.h"
#include "clang/Interpreter/Interpreter.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Sema/Sema.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/Error.h"
#include "llvm/Support/ErrorHandling.h"

namespace clang {
IncrementalAction::IncrementalAction(CompilerInstance &CI,
llvm::LLVMContext &LLVMCtx,
llvm::Error &Err, Interpreter &I,
std::unique_ptr<ASTConsumer> Consumer)
: 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:
case frontend::ASTPrint:
case frontend::ParseSyntaxOnly:
Act = CreateFrontendAction(CI);
break;
case frontend::PluginAction:
case frontend::EmitAssembly:
case frontend::EmitBC:
case frontend::EmitObj:
case frontend::PrintPreprocessedInput:
case frontend::EmitLLVMOnly:
Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));
break;
}
return Act;
}()),
Interp(I), CI(CI), Consumer(std::move(Consumer)) {}

std::unique_ptr<ASTConsumer>
IncrementalAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
std::unique_ptr<ASTConsumer> C =
WrapperFrontendAction::CreateASTConsumer(CI, InFile);

if (Consumer) {
std::vector<std::unique_ptr<ASTConsumer>> Cs;
Cs.push_back(std::move(Consumer));
Cs.push_back(std::move(C));
return std::make_unique<MultiplexConsumer>(std::move(Cs));
}

return std::make_unique<InProcessPrintingASTConsumer>(std::move(C), Interp);
}

void IncrementalAction::ExecuteAction() {
WrapperFrontendAction::ExecuteAction();
getCompilerInstance().getSema().CurContext = nullptr;
}

void IncrementalAction::EndSourceFile() {
if (IsTerminating && getWrapped())
WrapperFrontendAction::EndSourceFile();
}

void IncrementalAction::FinalizeAction() {
assert(!IsTerminating && "Already finalized!");
IsTerminating = true;
EndSourceFile();
}

void IncrementalAction::CacheCodeGenModule() {
CachedInCodeGenModule = GenModule();
}

llvm::Module *IncrementalAction::getCachedCodeGenModule() const {
return CachedInCodeGenModule.get();
}

std::unique_ptr<llvm::Module> IncrementalAction::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 ||
!CI.getPreprocessorOpts().Includes.empty()) ||
(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;
}

CodeGenerator *IncrementalAction::getCodeGen() const {
FrontendAction *WrappedAct = getWrapped();
if (!WrappedAct || !WrappedAct->hasIRSupport())
return nullptr;
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
}

InProcessPrintingASTConsumer::InProcessPrintingASTConsumer(
std::unique_ptr<ASTConsumer> C, Interpreter &I)
: MultiplexConsumer(std::move(C)), Interp(I) {}

bool InProcessPrintingASTConsumer::HandleTopLevelDecl(DeclGroupRef DGR) {
if (DGR.isNull())
return true;

for (Decl *D : DGR)
if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))
if (TLSD && TLSD->isSemiMissing()) {
auto ExprOrErr = Interp.convertExprToValue(cast<Expr>(TLSD->getStmt()));
if (llvm::Error E = ExprOrErr.takeError()) {
llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),
"Value printing failed: ");
return false; // abort parsing
}
TLSD->setStmt(*ExprOrErr);
}

return MultiplexConsumer::HandleTopLevelDecl(DGR);
}

} // namespace clang
90 changes: 90 additions & 0 deletions clang/lib/Interpreter/IncrementalAction.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//===--- IncrementalAction.h - Incremental Frontend Action -*- 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
//
//===----------------------------------------------------------------------===//

#ifndef LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H
#define LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H

#include "clang/Frontend/FrontendActions.h"
#include "clang/Frontend/MultiplexConsumer.h"

namespace llvm {
class Module;
}

namespace clang {

class Interpreter;
class CodeGenerator;

/// 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;
Interpreter &Interp;
CompilerInstance &CI;
std::unique_ptr<ASTConsumer> Consumer;

/// 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;

public:
IncrementalAction(CompilerInstance &CI, llvm::LLVMContext &LLVMCtx,
llvm::Error &Err, Interpreter &I,
std::unique_ptr<ASTConsumer> Consumer = nullptr);

FrontendAction *getWrapped() const { return WrappedAction.get(); }

TranslationUnitKind getTranslationUnitKind() override {
return TU_Incremental;
}

std::unique_ptr<ASTConsumer> CreateASTConsumer(CompilerInstance &CI,
StringRef InFile) override;

void ExecuteAction() override;

// 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;

void FinalizeAction();

/// Cache the current CodeGen module to preserve internal references.
void CacheCodeGenModule();

/// Access the cached CodeGen module.
llvm::Module *getCachedCodeGenModule() const;

/// Access the current code generator.
CodeGenerator *getCodeGen() const;

/// Generate an LLVM module for the most recent parsed input.
std::unique_ptr<llvm::Module> GenModule();
};

class InProcessPrintingASTConsumer final : public MultiplexConsumer {
Interpreter &Interp;

public:
InProcessPrintingASTConsumer(std::unique_ptr<ASTConsumer> C, Interpreter &I);

bool HandleTopLevelDecl(DeclGroupRef DGR) override;
};

} // end namespace clang

#endif // LLVM_CLANG_INTERPRETER_INCREMENTALACTION_H
30 changes: 28 additions & 2 deletions clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -11,24 +11,29 @@
//===----------------------------------------------------------------------===//

#include "IncrementalParser.h"
#include "IncrementalAction.h"

#include "clang/AST/DeclContextInternals.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "llvm/IR/Module.h"
#include "llvm/Support/CrashRecoveryContext.h"
#include "llvm/Support/Error.h"

#include <sstream>

#define DEBUG_TYPE "clang-repl"

namespace clang {

// IncrementalParser::IncrementalParser() {}

IncrementalParser::IncrementalParser(CompilerInstance &Instance,
llvm::Error &Err)
: S(Instance.getSema()) {
IncrementalAction *Act, llvm::Error &Err,
std::list<PartialTranslationUnit> &PTUs)
: S(Instance.getSema()), Act(Act), PTUs(PTUs) {
llvm::ErrorAsOutParameter EAO(&Err);
Consumer = &S.getASTConsumer();
P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
Expand Down Expand Up @@ -185,4 +190,25 @@ void IncrementalParser::CleanUpPTU(TranslationUnitDecl *MostRecentTU) {
}
}

PartialTranslationUnit &
IncrementalParser::RegisterPTU(TranslationUnitDecl *TU,
std::unique_ptr<llvm::Module> M /*={}*/) {
PTUs.emplace_back(PartialTranslationUnit());
PartialTranslationUnit &LastPTU = PTUs.back();
LastPTU.TUPart = TU;

if (!M)
M = Act->GenModule();

assert((!Act->getCodeGen() || M) && "Must have a llvm::Module at this point");

LastPTU.TheModule = std::move(M);
LLVM_DEBUG(llvm::dbgs() << "compile-ptu " << PTUs.size() - 1
<< ": [TU=" << LastPTU.TUPart);
if (LastPTU.TheModule)
LLVM_DEBUG(llvm::dbgs() << ", M=" << LastPTU.TheModule.get() << " ("
<< LastPTU.TheModule->getName() << ")");
LLVM_DEBUG(llvm::dbgs() << "]\n");
return LastPTU;
}
} // end namespace clang
Loading