IncrementalProcessingTest.cpp 5.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173
  1. //=== unittests/CodeGen/IncrementalProcessingTest.cpp - IncrementalCodeGen ===//
  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-exception
  6. //
  7. //===----------------------------------------------------------------------===//
  8. #include "clang/AST/ASTConsumer.h"
  9. #include "clang/AST/ASTContext.h"
  10. #include "clang/AST/RecursiveASTVisitor.h"
  11. #include "clang/Basic/TargetInfo.h"
  12. #include "clang/CodeGen/ModuleBuilder.h"
  13. #include "clang/Frontend/CompilerInstance.h"
  14. #include "clang/Lex/Preprocessor.h"
  15. #include "clang/Parse/Parser.h"
  16. #include "clang/Sema/Sema.h"
  17. #include "llvm/ADT/Triple.h"
  18. #include "llvm/IR/LLVMContext.h"
  19. #include "llvm/IR/Module.h"
  20. #include "llvm/Support/Host.h"
  21. #include "llvm/Support/MemoryBuffer.h"
  22. #include "gtest/gtest.h"
  23. #include <memory>
  24. using namespace llvm;
  25. using namespace clang;
  26. namespace {
  27. // Incremental processing produces several modules, all using the same "main
  28. // file". Make sure CodeGen can cope with that, e.g. for static initializers.
  29. const char TestProgram1[] =
  30. "extern \"C\" int funcForProg1() { return 17; }\n"
  31. "struct EmitCXXGlobalInitFunc1 {\n"
  32. " EmitCXXGlobalInitFunc1() {}\n"
  33. "} test1;";
  34. const char TestProgram2[] =
  35. "extern \"C\" int funcForProg2() { return 42; }\n"
  36. "struct EmitCXXGlobalInitFunc2 {\n"
  37. " EmitCXXGlobalInitFunc2() {}\n"
  38. "} test2;";
  39. /// An incremental version of ParseAST().
  40. static std::unique_ptr<llvm::Module>
  41. IncrementalParseAST(CompilerInstance& CI, Parser& P,
  42. CodeGenerator& CG, const char* code) {
  43. static int counter = 0;
  44. struct IncreaseCounterOnRet {
  45. ~IncreaseCounterOnRet() {
  46. ++counter;
  47. }
  48. } ICOR;
  49. Sema& S = CI.getSema();
  50. clang::SourceManager &SM = S.getSourceManager();
  51. if (!code) {
  52. // Main file
  53. SM.setMainFileID(SM.createFileID(
  54. llvm::MemoryBuffer::getMemBuffer(" "), clang::SrcMgr::C_User));
  55. S.getPreprocessor().EnterMainSourceFile();
  56. P.Initialize();
  57. } else {
  58. FileID FID = SM.createFileID(
  59. llvm::MemoryBuffer::getMemBuffer(code), clang::SrcMgr::C_User);
  60. SourceLocation MainStartLoc = SM.getLocForStartOfFile(SM.getMainFileID());
  61. SourceLocation InclLoc = MainStartLoc.getLocWithOffset(counter);
  62. S.getPreprocessor().EnterSourceFile(FID, 0, InclLoc);
  63. }
  64. ExternalASTSource *External = S.getASTContext().getExternalSource();
  65. if (External)
  66. External->StartTranslationUnit(&CG);
  67. Parser::DeclGroupPtrTy ADecl;
  68. for (bool AtEOF = P.ParseFirstTopLevelDecl(ADecl); !AtEOF;
  69. AtEOF = P.ParseTopLevelDecl(ADecl)) {
  70. // If we got a null return and something *was* parsed, ignore it. This
  71. // is due to a top-level semicolon, an action override, or a parse error
  72. // skipping something.
  73. if (ADecl && !CG.HandleTopLevelDecl(ADecl.get()))
  74. return nullptr;
  75. }
  76. // Process any TopLevelDecls generated by #pragma weak.
  77. for (Decl *D : S.WeakTopLevelDecls())
  78. CG.HandleTopLevelDecl(DeclGroupRef(D));
  79. CG.HandleTranslationUnit(S.getASTContext());
  80. std::unique_ptr<llvm::Module> M(CG.ReleaseModule());
  81. // Switch to next module.
  82. CG.StartModule("incremental-module-" + std::to_string(counter),
  83. M->getContext());
  84. return M;
  85. }
  86. const Function* getGlobalInit(llvm::Module& M) {
  87. for (const auto& Func: M)
  88. if (Func.hasName() && Func.getName().startswith("_GLOBAL__sub_I_"))
  89. return &Func;
  90. return nullptr;
  91. }
  92. TEST(IncrementalProcessing, EmitCXXGlobalInitFunc) {
  93. LLVMContext Context;
  94. CompilerInstance compiler;
  95. compiler.createDiagnostics();
  96. compiler.getLangOpts().CPlusPlus = 1;
  97. compiler.getLangOpts().CPlusPlus11 = 1;
  98. compiler.getTargetOpts().Triple = llvm::Triple::normalize(
  99. llvm::sys::getProcessTriple());
  100. compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
  101. compiler.getDiagnostics(),
  102. std::make_shared<clang::TargetOptions>(
  103. compiler.getTargetOpts())));
  104. compiler.createFileManager();
  105. compiler.createSourceManager(compiler.getFileManager());
  106. compiler.createPreprocessor(clang::TU_Prefix);
  107. compiler.getPreprocessor().enableIncrementalProcessing();
  108. compiler.createASTContext();
  109. CodeGenerator* CG =
  110. CreateLLVMCodeGen(
  111. compiler.getDiagnostics(),
  112. "main-module",
  113. compiler.getHeaderSearchOpts(),
  114. compiler.getPreprocessorOpts(),
  115. compiler.getCodeGenOpts(),
  116. Context);
  117. compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(CG));
  118. compiler.createSema(clang::TU_Prefix, nullptr);
  119. Sema& S = compiler.getSema();
  120. std::unique_ptr<Parser> ParseOP(new Parser(S.getPreprocessor(), S,
  121. /*SkipFunctionBodies*/ false));
  122. Parser &P = *ParseOP.get();
  123. std::array<std::unique_ptr<llvm::Module>, 3> M;
  124. M[0] = IncrementalParseAST(compiler, P, *CG, nullptr);
  125. ASSERT_TRUE(M[0]);
  126. M[1] = IncrementalParseAST(compiler, P, *CG, TestProgram1);
  127. ASSERT_TRUE(M[1]);
  128. ASSERT_TRUE(M[1]->getFunction("funcForProg1"));
  129. M[2] = IncrementalParseAST(compiler, P, *CG, TestProgram2);
  130. ASSERT_TRUE(M[2]);
  131. ASSERT_TRUE(M[2]->getFunction("funcForProg2"));
  132. // First code should not end up in second module:
  133. ASSERT_FALSE(M[2]->getFunction("funcForProg1"));
  134. // Make sure global inits exist and are unique:
  135. const Function* GlobalInit1 = getGlobalInit(*M[1]);
  136. ASSERT_TRUE(GlobalInit1);
  137. const Function* GlobalInit2 = getGlobalInit(*M[2]);
  138. ASSERT_TRUE(GlobalInit2);
  139. ASSERT_FALSE(GlobalInit1->getName() == GlobalInit2->getName());
  140. }
  141. } // end anonymous namespace