brintos

brintos / llvm-project-archived public Read only

0
0
Text · 5.5 KiB · 3d489fc Raw
154 lines · cpp
1//===--- IncrementalAction.h - Incremental Frontend Action -*- C++ -*-===//2//3// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.4// See https://llvm.org/LICENSE.txt for license information.5// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception6//7//===----------------------------------------------------------------------===//8 9#include "IncrementalAction.h"10 11#include "clang/AST/ASTConsumer.h"12#include "clang/CodeGen/CodeGenAction.h"13#include "clang/CodeGen/ModuleBuilder.h"14#include "clang/Frontend/CompilerInstance.h"15#include "clang/Frontend/FrontendOptions.h"16#include "clang/FrontendTool/Utils.h"17#include "clang/Interpreter/Interpreter.h"18#include "clang/Lex/PreprocessorOptions.h"19#include "clang/Sema/Sema.h"20#include "llvm/IR/Module.h"21#include "llvm/Support/Error.h"22#include "llvm/Support/ErrorHandling.h"23 24namespace clang {25IncrementalAction::IncrementalAction(CompilerInstance &Instance,26                                     llvm::LLVMContext &LLVMCtx,27                                     llvm::Error &Err, Interpreter &I,28                                     std::unique_ptr<ASTConsumer> Consumer)29    : WrapperFrontendAction([&]() {30        llvm::ErrorAsOutParameter EAO(&Err);31        std::unique_ptr<FrontendAction> Act;32        switch (Instance.getFrontendOpts().ProgramAction) {33        default:34          Err = llvm::createStringError(35              std::errc::state_not_recoverable,36              "Driver initialization failed. "37              "Incremental mode for action %d is not supported",38              Instance.getFrontendOpts().ProgramAction);39          return Act;40        case frontend::ASTDump:41        case frontend::ASTPrint:42        case frontend::ParseSyntaxOnly:43          Act = CreateFrontendAction(Instance);44          break;45        case frontend::PluginAction:46        case frontend::EmitAssembly:47        case frontend::EmitBC:48        case frontend::EmitObj:49        case frontend::PrintPreprocessedInput:50        case frontend::EmitLLVMOnly:51          Act.reset(new EmitLLVMOnlyAction(&LLVMCtx));52          break;53        }54        return Act;55      }()),56      Interp(I), CI(Instance), Consumer(std::move(Consumer)) {}57 58std::unique_ptr<ASTConsumer>59IncrementalAction::CreateASTConsumer(CompilerInstance & /*CI*/,60                                     StringRef InFile) {61  std::unique_ptr<ASTConsumer> C =62      WrapperFrontendAction::CreateASTConsumer(this->CI, InFile);63 64  if (Consumer) {65    std::vector<std::unique_ptr<ASTConsumer>> Cs;66    Cs.push_back(std::move(Consumer));67    Cs.push_back(std::move(C));68    return std::make_unique<MultiplexConsumer>(std::move(Cs));69  }70 71  return std::make_unique<InProcessPrintingASTConsumer>(std::move(C), Interp);72}73 74void IncrementalAction::ExecuteAction() {75  WrapperFrontendAction::ExecuteAction();76  getCompilerInstance().getSema().CurContext = nullptr;77}78 79void IncrementalAction::EndSourceFile() {80  if (IsTerminating && getWrapped())81    WrapperFrontendAction::EndSourceFile();82}83 84void IncrementalAction::FinalizeAction() {85  assert(!IsTerminating && "Already finalized!");86  IsTerminating = true;87  EndSourceFile();88}89 90void IncrementalAction::CacheCodeGenModule() {91  CachedInCodeGenModule = GenModule();92}93 94llvm::Module *IncrementalAction::getCachedCodeGenModule() const {95  return CachedInCodeGenModule.get();96}97 98std::unique_ptr<llvm::Module> IncrementalAction::GenModule() {99  static unsigned ID = 0;100  if (CodeGenerator *CG = getCodeGen()) {101    // Clang's CodeGen is designed to work with a single llvm::Module. In many102    // cases for convenience various CodeGen parts have a reference to the103    // llvm::Module (TheModule or Module) which does not change when a new104    // module is pushed. However, the execution engine wants to take ownership105    // of the module which does not map well to CodeGen's design. To work this106    // around we created an empty module to make CodeGen happy. We should make107    // sure it always stays empty.108    assert(((!CachedInCodeGenModule ||109             !CI.getPreprocessorOpts().Includes.empty() ||110             !CI.getPreprocessorOpts().ImplicitPCHInclude.empty()) ||111            (CachedInCodeGenModule->empty() &&112             CachedInCodeGenModule->global_empty() &&113             CachedInCodeGenModule->alias_empty() &&114             CachedInCodeGenModule->ifunc_empty())) &&115           "CodeGen wrote to a readonly module");116    std::unique_ptr<llvm::Module> M(CG->ReleaseModule());117    CG->StartModule("incr_module_" + std::to_string(ID++), M->getContext());118    return M;119  }120  return nullptr;121}122 123CodeGenerator *IncrementalAction::getCodeGen() const {124  FrontendAction *WrappedAct = getWrapped();125  if (!WrappedAct || !WrappedAct->hasIRSupport())126    return nullptr;127  return static_cast<CodeGenAction *>(WrappedAct)->getCodeGenerator();128}129 130InProcessPrintingASTConsumer::InProcessPrintingASTConsumer(131    std::unique_ptr<ASTConsumer> C, Interpreter &I)132    : MultiplexConsumer(std::move(C)), Interp(I) {}133 134bool InProcessPrintingASTConsumer::HandleTopLevelDecl(DeclGroupRef DGR) {135  if (DGR.isNull())136    return true;137 138  for (Decl *D : DGR)139    if (auto *TLSD = llvm::dyn_cast<TopLevelStmtDecl>(D))140      if (TLSD && TLSD->isSemiMissing()) {141        auto ExprOrErr = Interp.convertExprToValue(cast<Expr>(TLSD->getStmt()));142        if (llvm::Error E = ExprOrErr.takeError()) {143          llvm::logAllUnhandledErrors(std::move(E), llvm::errs(),144                                      "Value printing failed: ");145          return false; // abort parsing146        }147        TLSD->setStmt(*ExprOrErr);148      }149 150  return MultiplexConsumer::HandleTopLevelDecl(DGR);151}152 153} // namespace clang154