Skip to content

[clang-repl] Delegate CodeGen related operations for PTU to IncrementalParser #137458

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
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
14 changes: 3 additions & 11 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ class ThreadSafeContext;
namespace clang {

class CompilerInstance;
class CodeGenerator;
class CXXRecordDecl;
class Decl;
class IncrementalExecutor;
Expand Down Expand Up @@ -109,13 +108,12 @@ 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;

/// An optional compiler instance for CUDA offloading
std::unique_ptr<CompilerInstance> DeviceCI;

protected:
// Derived classes can use an extended interface of the Interpreter.
Interpreter(std::unique_ptr<CompilerInstance> Instance, llvm::Error &Err,
Expand Down Expand Up @@ -179,12 +177,6 @@ class Interpreter {
llvm::Expected<Expr *> ExtractValueFromExpr(Expr *E);
llvm::Expected<llvm::orc::ExecutorAddr> CompileDtorCall(CXXRecordDecl *CXXRD);

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

// A cache for the compiled destructors used to for de-allocation of managed
// clang::Values.
llvm::DenseMap<CXXRecordDecl *, llvm::orc::ExecutorAddr> Dtors;
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
11 changes: 5 additions & 6 deletions clang/lib/Interpreter/DeviceOffload.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,13 +25,13 @@
namespace clang {

IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
std::unique_ptr<CompilerInstance> DeviceInstance,
CompilerInstance &HostInstance,
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()) {
TargetOpts(DeviceInstance.getTargetOpts()) {
if (Err)
return;
StringRef Arch = TargetOpts.CPU;
Expand All @@ -41,7 +41,6 @@ IncrementalCUDADeviceParser::IncrementalCUDADeviceParser(
llvm::inconvertibleErrorCode()));
return;
}
DeviceCI = std::move(DeviceInstance);
}

llvm::Expected<llvm::StringRef> IncrementalCUDADeviceParser::GeneratePTX() {
Expand Down
9 changes: 4 additions & 5 deletions clang/lib/Interpreter/DeviceOffload.h
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ struct PartialTranslationUnit;
class CompilerInstance;
class CodeGenOptions;
class TargetOptions;
class IncrementalAction;

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

public:
IncrementalCUDADeviceParser(
std::unique_ptr<CompilerInstance> DeviceInstance,
CompilerInstance &HostInstance,
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 All @@ -42,7 +42,6 @@ class IncrementalCUDADeviceParser : public IncrementalParser {
~IncrementalCUDADeviceParser();

protected:
std::unique_ptr<CompilerInstance> DeviceCI;
int SMVersion;
llvm::SmallString<1024> PTXCode;
llvm::SmallVector<char, 1024> FatbinContent;
Expand Down
152 changes: 152 additions & 0 deletions clang/lib/Interpreter/IncrementalAction.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,152 @@
//===--- 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.ExtractValueFromExpr(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
Loading