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 auto* structTy = dyn_cast<llvm::StructType>(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 302