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