Clang Project

clang_source_code/unittests/CodeGen/CodeGenExternalTest.cpp
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
28using namespace llvm;
29using namespace clang;
30
31namespace {
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
39static const bool DebugThisTest = false;
40
41// forward declarations
42struct MyASTConsumer;
43static void test_codegen_fns(MyASTConsumer *my);
44static 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
52struct MyASTConsumer : public ASTConsumer {
53  std::unique_ptr<CodeGeneratorBuilder;
54  std::vector<Decl*> toplevel_decls;
55
56  MyASTConsumer(std::unique_ptr<CodeGeneratorBuilder_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
83void MyASTConsumer::Initialize(ASTContext &Context) {
84  Builder->Initialize(Context);
85}
86
87bool 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
96void MyASTConsumer::HandleInlineFunctionDefinition(FunctionDecl *D) {
97  Builder->HandleInlineFunctionDefinition(D);
98}
99
100void MyASTConsumer::HandleInterestingDecl(DeclGroupRef D) {
101  Builder->HandleInterestingDecl(D);
102}
103
104void MyASTConsumer::HandleTranslationUnit(ASTContext &Context) {
105  test_codegen_fns(this);
106  // HandleTranslationUnit can close the module
107  Builder->HandleTranslationUnit(Context);
108}
109
110void MyASTConsumer::HandleTagDeclDefinition(TagDecl *D) {
111  Builder->HandleTagDeclDefinition(D);
112}
113
114void MyASTConsumer::HandleTagDeclRequiredDefinition(const TagDecl *D) {
115  Builder->HandleTagDeclRequiredDefinition(D);
116}
117
118void MyASTConsumer::HandleCXXImplicitFunctionInstantiation(FunctionDecl *D) {
119  Builder->HandleCXXImplicitFunctionInstantiation(D);
120}
121
122void MyASTConsumer::HandleTopLevelDeclInObjCContainer(DeclGroupRef D) {
123  Builder->HandleTopLevelDeclInObjCContainer(D);
124}
125
126void MyASTConsumer::HandleImplicitImportDecl(ImportDecl *D) {
127  Builder->HandleImplicitImportDecl(D);
128}
129
130void MyASTConsumer::CompleteTentativeDefinition(VarDecl *D) {
131  Builder->CompleteTentativeDefinition(D);
132}
133
134void MyASTConsumer::AssignInheritanceModel(CXXRecordDecl *RD) {
135  Builder->AssignInheritanceModel(RD);
136}
137
138void MyASTConsumer::HandleCXXStaticMemberVarInstantiation(VarDecl *VD) {
139   Builder->HandleCXXStaticMemberVarInstantiation(VD);
140}
141
142void MyASTConsumer::HandleVTable(CXXRecordDecl *RD) {
143   Builder->HandleVTable(RD);
144 }
145
146ASTMutationListener *MyASTConsumer::GetASTMutationListener() {
147  return Builder->GetASTMutationListener();
148}
149
150ASTDeserializationListener *MyASTConsumer::GetASTDeserializationListener() {
151  return Builder->GetASTDeserializationListener();
152}
153
154void MyASTConsumer::PrintStats() {
155  Builder->PrintStats();
156}
157
158bool MyASTConsumer::shouldSkipFunctionBody(Decl *D) {
159  return Builder->shouldSkipFunctionBody(D);
160}
161
162const 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
167static 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(CGMqType);
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(CGMrdxField);
221        unsigned y = CodeGen::getLLVMFieldNumber(CGMrdyField);
222        unsigned z = CodeGen::getLLVMFieldNumber(CGMrdzField);
223
224        ASSERT_NE(xy);
225        ASSERT_NE(yz);
226
227        llvm::TypexTy = structTy->getTypeAtIndex(x);
228        llvm::TypeyTy = structTy->getTypeAtIndex(y);
229        llvm::TypezTy = 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
259TEST(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_Prefixnullptr);
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()falsefalse);
297
298    ASSERT_TRUE(test_codegen_fns_ran);
299}
300
301// end anonymous namespace
302