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