CGDeclCXX.cpp revision 202379
1//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===//
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// This contains code dealing with code generation of C++ declarations
11//
12//===----------------------------------------------------------------------===//
13
14#include "CodeGenFunction.h"
15using namespace clang;
16using namespace CodeGen;
17
18static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
19                         llvm::Constant *DeclPtr) {
20  assert(D.hasGlobalStorage() && "VarDecl must have global storage!");
21  assert(!D.getType()->isReferenceType() &&
22         "Should not call EmitDeclInit on a reference!");
23
24  CodeGenModule &CGM = CGF.CGM;
25  ASTContext &Context = CGF.getContext();
26
27  const Expr *Init = D.getInit();
28  QualType T = D.getType();
29  bool isVolatile = Context.getCanonicalType(T).isVolatileQualified();
30
31  if (!CGF.hasAggregateLLVMType(T)) {
32    llvm::Value *V = CGF.EmitScalarExpr(Init);
33    CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T);
34  } else if (T->isAnyComplexType()) {
35    CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
36  } else {
37    CGF.EmitAggExpr(Init, DeclPtr, isVolatile);
38
39    // Avoid generating destructor(s) for initialized objects.
40    if (!isa<CXXConstructExpr>(Init))
41      return;
42
43    const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
44    if (Array)
45      T = Context.getBaseElementType(Array);
46
47    const RecordType *RT = T->getAs<RecordType>();
48    if (!RT)
49      return;
50
51    CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
52    if (RD->hasTrivialDestructor())
53      return;
54
55    CXXDestructorDecl *Dtor = RD->getDestructor(Context);
56
57    llvm::Constant *DtorFn;
58    if (Array) {
59      DtorFn =
60        CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor,
61                                                             Array,
62                                                             DeclPtr);
63      const llvm::Type *Int8PtrTy =
64        llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
65      DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
66     } else
67      DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
68
69    CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
70  }
71}
72
73void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
74                                               llvm::Constant *DeclPtr) {
75
76  const Expr *Init = D.getInit();
77  QualType T = D.getType();
78
79  if (!T->isReferenceType()) {
80    EmitDeclInit(*this, D, DeclPtr);
81    return;
82  }
83
84  ErrorUnsupported(Init, "global variable that binds to a reference");
85}
86
87void
88CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
89                                               llvm::Constant *DeclPtr) {
90  const llvm::Type *Int8PtrTy =
91    llvm::Type::getInt8Ty(VMContext)->getPointerTo();
92
93  std::vector<const llvm::Type *> Params;
94  Params.push_back(Int8PtrTy);
95
96  // Get the destructor function type
97  const llvm::Type *DtorFnTy =
98    llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
99  DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
100
101  Params.clear();
102  Params.push_back(DtorFnTy);
103  Params.push_back(Int8PtrTy);
104  Params.push_back(Int8PtrTy);
105
106  // Get the __cxa_atexit function type
107  // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
108  const llvm::FunctionType *AtExitFnTy =
109    llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
110
111  llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
112                                                       "__cxa_atexit");
113
114  llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
115                                                     "__dso_handle");
116  llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
117                           llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
118                           llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
119  Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
120}
121
122void
123CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
124  const llvm::FunctionType *FTy
125    = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
126                              false);
127
128  // Create a variable initialization function.
129  llvm::Function *Fn =
130    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
131                           "__cxx_global_var_init", &TheModule);
132
133  CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
134
135  CXXGlobalInits.push_back(Fn);
136}
137
138void
139CodeGenModule::EmitCXXGlobalInitFunc() {
140  if (CXXGlobalInits.empty())
141    return;
142
143  const llvm::FunctionType *FTy
144    = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
145                              false);
146
147  // Create our global initialization function.
148  // FIXME: Should this be tweakable by targets?
149  llvm::Function *Fn =
150    llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
151                           "__cxx_global_initialization", &TheModule);
152
153  CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
154                                                   &CXXGlobalInits[0],
155                                                   CXXGlobalInits.size());
156  AddGlobalCtor(Fn);
157}
158
159void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
160                                                       const VarDecl *D) {
161  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
162                SourceLocation());
163
164  llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
165  EmitCXXGlobalVarDeclInit(*D, DeclPtr);
166
167  FinishFunction();
168}
169
170void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
171                                                llvm::Constant **Decls,
172                                                unsigned NumDecls) {
173  StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
174                SourceLocation());
175
176  for (unsigned i = 0; i != NumDecls; ++i)
177    Builder.CreateCall(Decls[i]);
178
179  FinishFunction();
180}
181
182void
183CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D,
184                                               llvm::GlobalVariable *GV) {
185  // FIXME: This should use __cxa_guard_{acquire,release}?
186
187  assert(!getContext().getLangOptions().ThreadsafeStatics &&
188         "thread safe statics are currently not supported!");
189
190  llvm::SmallString<256> GuardVName;
191  CGM.getMangleContext().mangleGuardVariable(&D, GuardVName);
192
193  // Create the guard variable.
194  llvm::GlobalValue *GuardV =
195    new llvm::GlobalVariable(CGM.getModule(), llvm::Type::getInt64Ty(VMContext),
196                             false, GV->getLinkage(),
197                llvm::Constant::getNullValue(llvm::Type::getInt64Ty(VMContext)),
198                             GuardVName.str());
199
200  // Load the first byte of the guard variable.
201  const llvm::Type *PtrTy
202    = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0);
203  llvm::Value *V = Builder.CreateLoad(Builder.CreateBitCast(GuardV, PtrTy),
204                                      "tmp");
205
206  // Compare it against 0.
207  llvm::Value *nullValue
208    = llvm::Constant::getNullValue(llvm::Type::getInt8Ty(VMContext));
209  llvm::Value *ICmp = Builder.CreateICmpEQ(V, nullValue , "tobool");
210
211  llvm::BasicBlock *InitBlock = createBasicBlock("init");
212  llvm::BasicBlock *EndBlock = createBasicBlock("init.end");
213
214  // If the guard variable is 0, jump to the initializer code.
215  Builder.CreateCondBr(ICmp, InitBlock, EndBlock);
216
217  EmitBlock(InitBlock);
218
219  if (D.getType()->isReferenceType()) {
220    QualType T = D.getType();
221    // We don't want to pass true for IsInitializer here, because a static
222    // reference to a temporary does not extend its lifetime.
223    RValue RV = EmitReferenceBindingToExpr(D.getInit(), T,
224                                           /*IsInitializer=*/false);
225    EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T);
226
227  } else
228    EmitDeclInit(*this, D, GV);
229
230  Builder.CreateStore(llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext),
231                                             1),
232                      Builder.CreateBitCast(GuardV, PtrTy));
233
234  EmitBlock(EndBlock);
235}
236