xref: /llvm-project/clang/unittests/CodeGen/CodeGenExternalTest.cpp (revision f3d9b488bd1edff0e36e8ca840307df79e3af3f8)
1 //===- unittests/CodeGen/CodeGenExternalTest.cpp - test external CodeGen -===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 
10 #include "clang/AST/ASTConsumer.h"
11 #include "clang/AST/ASTContext.h"
12 #include "clang/AST/GlobalDecl.h"
13 #include "clang/AST/RecursiveASTVisitor.h"
14 #include "clang/Basic/TargetInfo.h"
15 #include "clang/CodeGen/CodeGenABITypes.h"
16 #include "clang/CodeGen/ModuleBuilder.h"
17 #include "clang/Frontend/CompilerInstance.h"
18 #include "clang/Lex/Preprocessor.h"
19 #include "clang/Parse/ParseAST.h"
20 #include "clang/Sema/Sema.h"
21 #include "llvm/ADT/Triple.h"
22 #include "llvm/IR/Instructions.h"
23 #include "llvm/IR/LLVMContext.h"
24 #include "llvm/Support/Debug.h"
25 #include "llvm/Support/Host.h"
26 #include "llvm/Support/MemoryBuffer.h"
27 #include "gtest/gtest.h"
28 
29 using namespace llvm;
30 using namespace clang;
31 
32 namespace {
33 
34 // Mocks up a language using Clang code generation as a library and
35 // tests some basic functionality there.
36 //   - CodeGen->GetAddrOfGlobal
37 //   - CodeGen::convertTypeForMemory
38 //   - CodeGen::getLLVMFieldNumber
39 
40 static const bool DebugThisTest = false;
41 
42 // forward declarations
43 struct MyASTConsumer;
44 static void test_codegen_fns(MyASTConsumer *my);
45 static bool test_codegen_fns_ran;
46 
47 // This forwards the calls to the Clang CodeGenerator
48 // so that we can test CodeGen functions while it is open.
49 // It accumulates toplevel decls in HandleTopLevelDecl and
50 // calls test_codegen_fns() in HandleTranslationUnit
51 // before forwarding that function to the CodeGenerator.
52 
53 struct MyASTConsumer : public ASTConsumer {
54   std::unique_ptr<CodeGenerator> Builder;
55   std::vector<Decl*> toplevel_decls;
56 
57   MyASTConsumer(std::unique_ptr<CodeGenerator> Builder_in)
58     : ASTConsumer(), Builder(std::move(Builder_in))
59   {
60   }
61 
62   ~MyASTConsumer() { }
63 
64   void Initialize(ASTContext &Context) override;
65   void HandleCXXStaticMemberVarInstantiation(VarDecl *VD) override;
66   bool HandleTopLevelDecl(DeclGroupRef D) override;
67   void HandleInlineFunctionDefinition(FunctionDecl *D) override;
68   void HandleInterestingDecl(DeclGroupRef D) override;
69   void HandleTranslationUnit(ASTContext &Ctx) override;
70   void HandleTagDeclDefinition(TagDecl *D) override;
71   void HandleTagDeclRequiredDefinition(const TagDecl *D) override;
72   void HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) override;
73   void HandleTopLevelDeclInObjCContainer(DeclGroupRef D) override;
74   void HandleImplicitImportDecl(ImportDecl *D) override;
75   void CompleteTentativeDefinition(VarDecl *D) override;
76   void AssignInheritanceModel(CXXRecordDecl *RD) override;
77   void HandleVTable(CXXRecordDecl *RD) override;
78   ASTMutationListener *GetASTMutationListener() override;
79   ASTDeserializationListener *GetASTDeserializationListener() override;
80   void PrintStats() override;
81   bool shouldSkipFunctionBody(Decl *D) override;
82 };
83 
84 void MyASTConsumer::Initialize(ASTContext &Context) {
85   Builder->Initialize(Context);
86 }
87 
88 bool MyASTConsumer::HandleTopLevelDecl(DeclGroupRef DG) {
89 
90   for (DeclGroupRef::iterator I = DG.begin(), E = DG.end(); I != E; ++I) {
91     toplevel_decls.push_back(*I);
92   }
93 
94   return Builder->HandleTopLevelDecl(DG);
95 }
96 
97 void MyASTConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
98   Builder->HandleInlineFunctionDefinition(D);
99 }
100 
101 void MyASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
102   Builder->HandleInterestingDecl(D);
103 }
104 
105 void MyASTConsumer::HandleTranslationUnit(ASTContext &Context) {
106   test_codegen_fns(this);
107   // HandleTranslationUnit can close the module
108   Builder->HandleTranslationUnit(Context);
109 }
110 
111 void MyASTConsumer::HandleTagDeclDefinition(TagDecl *D) {
112   Builder->HandleTagDeclDefinition(D);
113 }
114 
115 void MyASTConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
116   Builder->HandleTagDeclRequiredDefinition(D);
117 }
118 
119 void MyASTConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
120   Builder->HandleCXXImplicitFunctionInstantiation(D);
121 }
122 
123 void MyASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
124   Builder->HandleTopLevelDeclInObjCContainer(D);
125 }
126 
127 void MyASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
128   Builder->HandleImplicitImportDecl(D);
129 }
130 
131 void MyASTConsumer::CompleteTentativeDefinition(VarDecl *D) {
132   Builder->CompleteTentativeDefinition(D);
133 }
134 
135 void MyASTConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
136   Builder->AssignInheritanceModel(RD);
137 }
138 
139 void MyASTConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
140    Builder->HandleCXXStaticMemberVarInstantiation(VD);
141 }
142 
143 void MyASTConsumer::HandleVTable(CXXRecordDecl *RD) {
144    Builder->HandleVTable(RD);
145  }
146 
147 ASTMutationListener *MyASTConsumer::GetASTMutationListener() {
148   return Builder->GetASTMutationListener();
149 }
150 
151 ASTDeserializationListener *MyASTConsumer::GetASTDeserializationListener() {
152   return Builder->GetASTDeserializationListener();
153 }
154 
155 void MyASTConsumer::PrintStats() {
156   Builder->PrintStats();
157 }
158 
159 bool MyASTConsumer::shouldSkipFunctionBody(Decl *D) {
160   return Builder->shouldSkipFunctionBody(D);
161 }
162 
163 const char TestProgram[] =
164     "struct mytest_struct { char x; short y; char p; long z; };\n"
165     "int mytest_fn(int x) { return x; }\n";
166 
167 // This function has the real test code here
168 static void test_codegen_fns(MyASTConsumer *my) {
169 
170   bool mytest_fn_ok = false;
171   bool mytest_struct_ok = false;
172 
173   CodeGen::CodeGenModule &CGM = my->Builder->CGM();
174 
175   for (auto decl : my->toplevel_decls ) {
176     if (FunctionDecl *fd = dyn_cast<FunctionDecl>(decl)) {
177       if (fd->getName() == "mytest_fn") {
178         Constant *c = my->Builder->GetAddrOfGlobal(GlobalDecl(fd), false);
179         // Verify that we got a function.
180         ASSERT_TRUE(c != NULL);
181         if (DebugThisTest) {
182           c->print(dbgs(), true);
183           dbgs() << "\n";
184         }
185         mytest_fn_ok = true;
186       }
187     } else if(clang::RecordDecl *rd = dyn_cast<RecordDecl>(decl)) {
188       if (rd->getName() == "mytest_struct") {
189         RecordDecl *def = rd->getDefinition();
190         ASSERT_TRUE(def != NULL);
191         const clang::Type *clangTy = rd->getCanonicalDecl()->getTypeForDecl();
192         ASSERT_TRUE(clangTy != NULL);
193         QualType qType = clangTy->getCanonicalTypeInternal();
194 
195         // Check convertTypeForMemory
196         llvm::Type *llvmTy = CodeGen::convertTypeForMemory(CGM, qType);
197         ASSERT_TRUE(llvmTy != NULL);
198         if (DebugThisTest) {
199           llvmTy->print(dbgs(), true);
200           dbgs() << "\n";
201         }
202 
203         llvm::CompositeType* structTy = dyn_cast<CompositeType>(llvmTy);
204         ASSERT_TRUE(structTy != NULL);
205 
206         // Check getLLVMFieldNumber
207         FieldDecl *xField = NULL;
208         FieldDecl *yField = NULL;
209         FieldDecl *zField = NULL;
210 
211         for (auto field : rd->fields()) {
212           if (field->getName() == "x") xField = field;
213           if (field->getName() == "y") yField = field;
214           if (field->getName() == "z") zField = field;
215         }
216 
217         ASSERT_TRUE(xField != NULL);
218         ASSERT_TRUE(yField != NULL);
219         ASSERT_TRUE(zField != NULL);
220 
221         unsigned x = CodeGen::getLLVMFieldNumber(CGM, rd, xField);
222         unsigned y = CodeGen::getLLVMFieldNumber(CGM, rd, yField);
223         unsigned z = CodeGen::getLLVMFieldNumber(CGM, rd, zField);
224 
225         ASSERT_NE(x, y);
226         ASSERT_NE(y, z);
227 
228         llvm::Type* xTy = structTy->getTypeAtIndex(x);
229         llvm::Type* yTy = structTy->getTypeAtIndex(y);
230         llvm::Type* zTy = structTy->getTypeAtIndex(z);
231 
232         ASSERT_TRUE(xTy != NULL);
233         ASSERT_TRUE(yTy != NULL);
234         ASSERT_TRUE(zTy != NULL);
235 
236         if (DebugThisTest) {
237           xTy->print(dbgs(), true);
238           dbgs() << "\n";
239           yTy->print(dbgs(), true);
240           dbgs() << "\n";
241           zTy->print(dbgs(), true);
242           dbgs() << "\n";
243         }
244 
245         ASSERT_GE(xTy->getPrimitiveSizeInBits(), 1u);
246         ASSERT_GE(yTy->getPrimitiveSizeInBits(), 16u); // short is at least 16b
247         ASSERT_GE(zTy->getPrimitiveSizeInBits(), 32u); // long is at least 32b
248 
249         mytest_struct_ok = true;
250       }
251     }
252   }
253 
254   ASSERT_TRUE(mytest_fn_ok);
255   ASSERT_TRUE(mytest_struct_ok);
256 
257   test_codegen_fns_ran = true;
258 }
259 
260 TEST(CodeGenExternalTest, CodeGenExternalTest) {
261     LLVMContext Context;
262     CompilerInstance compiler;
263 
264     compiler.createDiagnostics();
265     compiler.getLangOpts().CPlusPlus = 1;
266     compiler.getLangOpts().CPlusPlus11 = 1;
267 
268     compiler.getTargetOpts().Triple = llvm::Triple::normalize(
269         llvm::sys::getProcessTriple());
270     compiler.setTarget(clang::TargetInfo::CreateTargetInfo(
271       compiler.getDiagnostics(),
272       std::make_shared<clang::TargetOptions>(
273         compiler.getTargetOpts())));
274 
275     compiler.createFileManager();
276     compiler.createSourceManager(compiler.getFileManager());
277     compiler.createPreprocessor(clang::TU_Prefix);
278 
279     compiler.createASTContext();
280 
281 
282     compiler.setASTConsumer(std::unique_ptr<ASTConsumer>(
283           new MyASTConsumer(std::unique_ptr<CodeGenerator>(
284              CreateLLVMCodeGen(compiler.getDiagnostics(),
285                                "MemoryTypesTest",
286                                compiler.getHeaderSearchOpts(),
287                                compiler.getPreprocessorOpts(),
288                                compiler.getCodeGenOpts(),
289                                Context)))));
290 
291     compiler.createSema(clang::TU_Prefix, nullptr);
292 
293     clang::SourceManager &sm = compiler.getSourceManager();
294     sm.setMainFileID(sm.createFileID(
295         llvm::MemoryBuffer::getMemBuffer(TestProgram), clang::SrcMgr::C_User));
296 
297     clang::ParseAST(compiler.getSema(), false, false);
298 
299     ASSERT_TRUE(test_codegen_fns_ran);
300 }
301 
302 } // end anonymous namespace
303