CGDeclCXX.cpp revision 202379
1184610Salfred//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===//
2184610Salfred//
3184610Salfred//                     The LLVM Compiler Infrastructure
4184610Salfred//
5184610Salfred// This file is distributed under the University of Illinois Open Source
6184610Salfred// License. See LICENSE.TXT for details.
7184610Salfred//
8184610Salfred//===----------------------------------------------------------------------===//
9184610Salfred//
10184610Salfred// This contains code dealing with code generation of C++ declarations
11184610Salfred//
12184610Salfred//===----------------------------------------------------------------------===//
13184610Salfred
14184610Salfred#include "CodeGenFunction.h"
15184610Salfredusing namespace clang;
16184610Salfredusing namespace CodeGen;
17184610Salfred
18184610Salfredstatic void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
19184610Salfred                         llvm::Constant *DeclPtr) {
20184610Salfred  assert(D.hasGlobalStorage() && "VarDecl must have global storage!");
21184610Salfred  assert(!D.getType()->isReferenceType() &&
22184610Salfred         "Should not call EmitDeclInit on a reference!");
23184610Salfred
24184610Salfred  CodeGenModule &CGM = CGF.CGM;
25184610Salfred  ASTContext &Context = CGF.getContext();
26184610Salfred
27184610Salfred  const Expr *Init = D.getInit();
28184610Salfred  QualType T = D.getType();
29184610Salfred  bool isVolatile = Context.getCanonicalType(T).isVolatileQualified();
30184610Salfred
31184610Salfred  if (!CGF.hasAggregateLLVMType(T)) {
32184610Salfred    llvm::Value *V = CGF.EmitScalarExpr(Init);
33184610Salfred    CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T);
34184610Salfred  } else if (T->isAnyComplexType()) {
35190754Sthompsa    CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
36184610Salfred  } else {
37184610Salfred    CGF.EmitAggExpr(Init, DeclPtr, isVolatile);
38194677Sthompsa
39194677Sthompsa    // Avoid generating destructor(s) for initialized objects.
40194677Sthompsa    if (!isa<CXXConstructExpr>(Init))
41194677Sthompsa      return;
42194677Sthompsa
43194677Sthompsa    const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
44194677Sthompsa    if (Array)
45194677Sthompsa      T = Context.getBaseElementType(Array);
46194677Sthompsa
47194677Sthompsa    const RecordType *RT = T->getAs<RecordType>();
48194677Sthompsa    if (!RT)
49194677Sthompsa      return;
50194677Sthompsa
51194677Sthompsa    CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
52194677Sthompsa    if (RD->hasTrivialDestructor())
53194677Sthompsa      return;
54194677Sthompsa
55194677Sthompsa    CXXDestructorDecl *Dtor = RD->getDestructor(Context);
56194677Sthompsa
57194677Sthompsa    llvm::Constant *DtorFn;
58188942Sthompsa    if (Array) {
59194677Sthompsa      DtorFn =
60184610Salfred        CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor,
61184610Salfred                                                             Array,
62184610Salfred                                                             DeclPtr);
63188942Sthompsa      const llvm::Type *Int8PtrTy =
64188942Sthompsa        llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
65188942Sthompsa      DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
66188942Sthompsa     } else
67188942Sthompsa      DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
68188942Sthompsa
69188942Sthompsa    CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
70188942Sthompsa  }
71184610Salfred}
72188942Sthompsa
73188942Sthompsavoid CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
74188942Sthompsa                                               llvm::Constant *DeclPtr) {
75198151Sthompsa
76184610Salfred  const Expr *Init = D.getInit();
77190181Sthompsa  QualType T = D.getType();
78190181Sthompsa
79190181Sthompsa  if (!T->isReferenceType()) {
80184610Salfred    EmitDeclInit(*this, D, DeclPtr);
81194677Sthompsa    return;
82184610Salfred  }
83184610Salfred
84192502Sthompsa  ErrorUnsupported(Init, "global variable that binds to a reference");
85192502Sthompsa}
86184610Salfred
87199675Sthompsavoid
88199675SthompsaCodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
89199675Sthompsa                                               llvm::Constant *DeclPtr) {
90184610Salfred  const llvm::Type *Int8PtrTy =
91184610Salfred    llvm::Type::getInt8Ty(VMContext)->getPointerTo();
92184610Salfred
93184610Salfred  std::vector<const llvm::Type *> Params;
94184610Salfred  Params.push_back(Int8PtrTy);
95184610Salfred
96184610Salfred  // Get the destructor function type
97184610Salfred  const llvm::Type *DtorFnTy =
98184610Salfred    llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
99184610Salfred  DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
100184610Salfred
101184610Salfred  Params.clear();
102184610Salfred  Params.push_back(DtorFnTy);
103184610Salfred  Params.push_back(Int8PtrTy);
104184610Salfred  Params.push_back(Int8PtrTy);
105184610Salfred
106184610Salfred  // Get the __cxa_atexit function type
107184610Salfred  // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
108184610Salfred  const llvm::FunctionType *AtExitFnTy =
109184610Salfred    llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
110184610Salfred
111184610Salfred  llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
112184610Salfred                                                       "__cxa_atexit");
113192984Sthompsa
114192984Sthompsa  llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
115192984Sthompsa                                                     "__dso_handle");
116192984Sthompsa  llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
117192984Sthompsa                           llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
118184610Salfred                           llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
119192984Sthompsa  Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
120193045Sthompsa}
121184610Salfred
122192984Sthompsavoid
123190735SthompsaCodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
124184610Salfred  const llvm::FunctionType *FTy
125184610Salfred    = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
126192984Sthompsa                              false);
127184610Salfred
128184610Salfred  // Create a variable initialization function.
129184610Salfred  llvm::Function *Fn =
130184610Salfred    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
131184610Salfred                           "__cxx_global_var_init", &TheModule);
132184610Salfred
133184610Salfred  CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
134184610Salfred
135190183Sthompsa  CXXGlobalInits.push_back(Fn);
136184610Salfred}
137184610Salfred
138184610Salfredvoid
139184610SalfredCodeGenModule::EmitCXXGlobalInitFunc() {
140184610Salfred  if (CXXGlobalInits.empty())
141194228Sthompsa    return;
142184610Salfred
143184610Salfred  const llvm::FunctionType *FTy
144184610Salfred    = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
145184610Salfred                              false);
146193045Sthompsa
147184610Salfred  // Create our global initialization function.
148184610Salfred  // FIXME: Should this be tweakable by targets?
149184610Salfred  llvm::Function *Fn =
150184610Salfred    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
151184610Salfred                           "__cxx_global_initialization", &TheModule);
152184610Salfred
153184610Salfred  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
154184610Salfred                                                   &CXXGlobalInits[0],
155184610Salfred                                                   CXXGlobalInits.size());
156184610Salfred  AddGlobalCtor(Fn);
157184610Salfred}
158184610Salfred
159184610Salfredvoid CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
160184610Salfred                                                       const VarDecl *D) {
161184610Salfred  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
162184610Salfred                SourceLocation());
163184610Salfred
164184610Salfred  llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
165184610Salfred  EmitCXXGlobalVarDeclInit(*D, DeclPtr);
166184610Salfred
167184610Salfred  FinishFunction();
168184610Salfred}
169193045Sthompsa
170184610Salfredvoid CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
171184610Salfred                                                llvm::Constant **Decls,
172192984Sthompsa                                                unsigned NumDecls) {
173184610Salfred  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
174184610Salfred                SourceLocation());
175184610Salfred
176184610Salfred  for (unsigned i = 0; i != NumDecls; ++i)
177184610Salfred    Builder.CreateCall(Decls[i]);
178184610Salfred
179184610Salfred  FinishFunction();
180184610Salfred}
181198501Sthompsa
182198501Sthompsavoid
183198501SthompsaCodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
184198501Sthompsa                                               llvm::GlobalVariable *GV) {
185198501Sthompsa  // FIXME: This should use __cxa_guard_{acquire,release}?
186198501Sthompsa
187198501Sthompsa  assert(!getContext().getLangOptions().ThreadsafeStatics &&
188198501Sthompsa         "thread safe statics are currently not supported!");
189198501Sthompsa
190198501Sthompsa  llvm::SmallString<256> GuardVName;
191198501Sthompsa  CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
192198501Sthompsa
193198501Sthompsa  // Create the guard variable.
194198501Sthompsa  llvm::GlobalValue *GuardV =
195198501Sthompsa    new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
196198501Sthompsa                             false, GV->getLinkage(),
197198501Sthompsa                llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
198198501Sthompsa                             GuardVName.str());
199198501Sthompsa
200198501Sthompsa  // Load the first byte of the guard variable.
201198501Sthompsa  const llvm::Type *PtrTy
202198501Sthompsa    = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
203198501Sthompsa  llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
204198501Sthompsa                                      "tmp");
205184610Salfred
206184610Salfred  // Compare it against 0.
207184610Salfred  llvm::Value *nullValue
208184610Salfred    = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
209184610Salfred  llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
210184610Salfred
211184610Salfred  llvm::BasicBlock *InitBlock = createBasicBlock("init");
212194228Sthompsa  llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
213188409Sthompsa
214184610Salfred  // If the guard variable is 0, jump to the initializer code.
215184610Salfred  Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
216184610Salfred
217184610Salfred  EmitBlock(InitBlock);
218184610Salfred
219184610Salfred  if (D.getType()->isReferenceType()) {
220184610Salfred    QualType T = D.getType();
221184610Salfred    // We don't want to pass true for IsInitializer here, because a static
222184610Salfred    // reference to a temporary does not extend its lifetime.
223184610Salfred    RValue RV = EmitReferenceBindingToExpr(D.getInit(), T,
224184610Salfred                                           /*IsInitializer=*/false);
225184610Salfred    EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
226184610Salfred
227184610Salfred  } else
228184610Salfred    EmitDeclInit(*this, D, GV);
229184610Salfred
230184610Salfred  Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
231194677Sthompsa                                             1),
232184610Salfred                      Builder.CreateBitCast(GuardV, PtrTy));
233184610Salfred
234184610Salfred  EmitBlock(EndBlock);
235184610Salfred}
236184610Salfred