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