8000 [clang-repl] Delegate CodeGen related operations for PTU to IncrementalParser by anutosh491 · Pull Request #137458 · llvm/llvm-project · GitHub
[go: up one dir, main page]

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 1 commit
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
Prev Previous commit
move codegen related operations to incrementalaction clas
  • Loading branch information
anutosh491 committed May 5, 2025
commit 44cd370729b80c7aef7601b492ecd3d24610dec9
3 changes: 3 additions & 0 deletions clang/include/clang/Interpreter/Interpreter.h
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,9 @@ class Interpreter {
/// 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
9 changes: 4 additions & 5 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, IncrementalAction *DeviceAct,
CompilerInstance &DeviceInstance, CompilerInstance &HostInstance,
IncrementalAction *DeviceAct,
llvm::IntrusiveRefCntPtr<llvm::vfs::InMemoryFileSystem> FS,
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs)
: IncrementalParser(*DeviceInstance, DeviceAct, Err, PTUs), VFS(FS),
: 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
5 changes: 2 additions & 3 deletions clang/lib/Interpreter/DeviceOffload.h
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ class IncrementalCUDADeviceParser : public IncrementalParser {

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

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
44 changes: 43 additions & 1 deletion clang/lib/Interpreter/IncrementalAction.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,11 +10,14 @@

#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"

Expand Down Expand Up @@ -50,7 +53,7 @@ IncrementalAction::IncrementalAction(CompilerInstance &CI,
}
return Act;
}()),
Interp(I), Consumer(std::move(Consumer)) {}
Interp(I), CI(CI), Consumer(std::move(Consumer)) {}

std::unique_ptr<ASTConsumer>
IncrementalAction::CreateASTConsumer(CompilerInstance &CI, StringRef InFile) {
Expand Down Expand Up @@ -83,6 +86,45 @@ void IncrementalAction::FinalizeAction() {
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) {}
Expand Down
22 changes: 22 additions & 0 deletions clang/lib/Interpreter/IncrementalAction.h
6D40
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,14 @@
#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.
///
Expand All @@ -29,8 +34,13 @@ 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,
Expand All @@ -52,6 +62,18 @@ class IncrementalAction : public WrapperFrontendAction {
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 {
Expand Down
44 changes: 4 additions & 40 deletions clang/lib/Interpreter/IncrementalParser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,12 +14,8 @@
#include "IncrementalAction.h"

#include "clang/AST/DeclContextInternals.h"
#include "clang/CodeGen/CodeGenAction.h"
#include "clang/CodeGen/ModuleBuilder.h"
#include "clang/Frontend/CompilerInstance.h"
#include "clang/Frontend/FrontendAction.h"
#include "clang/Interpreter/PartialTranslationUnit.h"
#include "clang/Lex/PreprocessorOptions.h"
#include "clang/Parse/Parser.h"
#include "clang/Sema/Sema.h"
#include "llvm/IR/Module.h"
Expand All @@ -37,10 +33,10 @@ namespace clang {
IncrementalParser::IncrementalParser(CompilerInstance &Instance,
IncrementalAction *Act, llvm::Error &Err,
std::list<PartialTranslationUnit> &PTUs)
: S(Instance.getSema()), CI(Instance), Act(Act), PTUs(PTUs) {
: S(Instance.getSema()), Act(Act), PTUs(PTUs) {
llvm::ErrorAsOutParameter EAO(&Err);
Consumer = &S.getASTConsumer();
P = std::make_unique<Parser>(S.getPreprocessor(), S, /*SkipBodies=*/false);
P.reset(new Parser(S.getPreprocessor(), S, /*SkipBodies=*/false));
P->Initialize();
}

Expand Down Expand Up @@ -202,9 +198,9 @@ IncrementalParser::RegisterPTU(TranslationUnitDecl *TU,
LastPTU.TUPart = TU;

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

assert((!getCodeGen() || M) && "Must have a llvm::Module at this point");
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
Expand All @@ -215,36 +211,4 @@ IncrementalParser::RegisterPTU(TranslationUnitDecl *TU,
LLVM_DEBUG(llvm::dbgs() << "]\n");
return LastPTU;
}

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 ||
!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 *IncrementalParser::getCodeGen() const {
FrontendAction *WrappedAct = Act->getWrapped();
if (!WrappedAct->hasIRSupport())
return nullptr;
return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();
}

} // end namespace clang
14 changes: 0 additions & 14 deletions clang/lib/Interpreter/IncrementalParser.h
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ class Module;

namespace clang {
class ASTConsumer;
class CodeGenerator;
class CompilerInstance;
class Parser;
class Sema;
Expand All @@ -50,9 +49,6 @@ class IncrementalParser {
/// Counts the number of direct user input lines that have been parsed.
unsigned InputCount = 0;

/// The CompilerInstance used during parsing.
CompilerInstance &CI;

/// The FrontendAction used during incremental parsing.
IncrementalAction *Act = nullptr;

Expand All @@ -63,23 +59,13 @@ class IncrementalParser {
llvm::Error &Err, std::list<PartialTranslationUnit> &PTUs);
virtual ~IncrementalParser();

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

/// Parses incremental input by creating an in-memory file.
///\returns a \c PartialTranslationUnit which holds information about the
/// \c TranslationUnitDecl.
virtual llvm::Expected<TranslationUnitDecl *> Parse(llvm::StringRef Input);

void CleanUpPTU(TranslationUnitDecl *MostRecentTU);

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

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

/// Register a PTU produced by Parse.
PartialTranslationUnit &RegisterPTU(TranslationUnitDecl *TU,
std::unique_ptr<llvm::Module> M = {});
Expand Down
22 changes: 14 additions & 8 deletions clang/lib/Interpreter/Interpreter.cpp
10670
Original file line number Diff line number Diff line change
Expand Up @@ -270,15 +270,15 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
if (ErrOut)
return;

if (IncrParser->getCodeGen()) {
IncrParser->CachedInCodeGenModule = IncrParser->GenModule();
if (Act->getCodeGen()) {
Act->CacheCodeGenModule();
// The initial PTU is filled by `-include` or by CUDA includes
// automatically.
if (!CI->getPreprocessorOpts().Includes.empty()) {
// We can't really directly pass the CachedInCodeGenModule to the Jit
// because it will steal it, causing dangling references as explained in
// Interpreter::Execute
auto M = llvm::CloneModule(*IncrParser->CachedInCodeGenModule);
auto M = llvm::CloneModule(*Act->getCachedCodeGenModule());
ASTContext &C = CI->getASTContext();
IncrParser->RegisterPTU(C.getTranslationUnitDecl(), std::move(M));
}
Expand All @@ -289,7 +289,7 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
}

// Not all frontends support code-generation, e.g. ast-dump actions don't
if (IncrParser->getCodeGen()) {
if (Act->getCodeGen()) {
// 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 : PTUs)
Expand All @@ -303,6 +303,10 @@ Interpreter::Interpreter(std::unique_ptr<CompilerInstance> Instance,
Interpreter::~Interpreter() {
IncrParser.reset();
Act->FinalizeAction();
if (DeviceParser)
DeviceParser.reset();
if (DeviceAct)
DeviceAct->FinalizeAction();
if (IncrExecutor) {
if (llvm::Error Err = IncrExecutor->cleanUp())
llvm::report_fatal_error(
Expand Down Expand Up @@ -388,9 +392,11 @@ Interpreter::createWithCUDA(std::unique_ptr<CompilerInstance> CI,

DCI->ExecuteAction(*Interp->DeviceAct);

Interp->DeviceCI = std::move(DCI);

auto DeviceParser = std::make_unique<IncrementalCUDADeviceParser>(
std::move(DCI), *Interp->getCompilerInstance(), Interp->DeviceAct.get(),
IMVFS, Err, Interp->PTUs);
*Interp->DeviceCI, *Interp->getCompilerInstance(),
Interp->DeviceAct.get(), IMVFS, Err, Interp->PTUs);

if (Err)
return std::move(Err);
Expand Down Expand Up @@ -479,7 +485,7 @@ llvm::Error Interpreter::CreateExecutor() {
return llvm::make_error<llvm::StringError>("Operation failed. "
"Execution engine exists",
std::error_code());
if (!IncrParser->getCodeGen())
if (!Act->getCodeGen())
return llvm::make_error<llvm::StringError>("Operation failed. "
"No code generator available",
std::error_code());
Expand Down Expand Up @@ -559,7 +565,7 @@ Interpreter::getSymbolAddress(GlobalDecl GD) const {
return llvm::make_error<llvm::StringError>("Operation failed. "
"No execution engine",
std::error_code());
llvm::StringRef MangledName = IncrParser->getCodeGen()->GetMangledName(GD);
llvm::StringRef MangledName = Act->getCodeGen()->GetMangledName(GD);
return getSymbolAddress(MangledName);
}

Expand Down
4 changes: 2 additions & 2 deletions clang/lib/Interpreter/InterpreterValuePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@
//
//===----------------------------------------------------------------------===//

#include "IncrementalParser.h"
#include "IncrementalAction.h"
#include "InterpreterUtils.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/PrettyPrinter.h"
Expand Down Expand Up @@ -45,7 +45,7 @@ Interpreter::CompileDtorCall(CXXRecordDecl *CXXRD) {
getCompilerInstance()->getSema().LookupDestructor(CXXRD);

llvm::StringRef Name =
IncrParser->getCodeGen()->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
Act->getCodeGen()->GetMangledName(GlobalDecl(DtorRD, Dtor_Base));
auto AddrOrErr = getSymbolAddress(Name);
if (!AddrOrErr)
return AddrOrErr.takeError();
Expand Down
0