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