CGDeclCXX.cpp revision 205408
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" 15#include "clang/CodeGen/CodeGenOptions.h" 16using namespace clang; 17using namespace CodeGen; 18 19static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D, 20 llvm::Constant *DeclPtr) { 21 assert(D.hasGlobalStorage() && "VarDecl must have global storage!"); 22 assert(!D.getType()->isReferenceType() && 23 "Should not call EmitDeclInit on a reference!"); 24 25 CodeGenModule &CGM = CGF.CGM; 26 ASTContext &Context = CGF.getContext(); 27 28 const Expr *Init = D.getInit(); 29 QualType T = D.getType(); 30 bool isVolatile = Context.getCanonicalType(T).isVolatileQualified(); 31 32 if (!CGF.hasAggregateLLVMType(T)) { 33 llvm::Value *V = CGF.EmitScalarExpr(Init); 34 CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, T); 35 } else if (T->isAnyComplexType()) { 36 CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile); 37 } else { 38 CGF.EmitAggExpr(Init, DeclPtr, isVolatile); 39 40 // Avoid generating destructor(s) for initialized objects. 41 if (!isa<CXXConstructExpr>(Init)) 42 return; 43 44 const ConstantArrayType *Array = Context.getAsConstantArrayType(T); 45 if (Array) 46 T = Context.getBaseElementType(Array); 47 48 const RecordType *RT = T->getAs<RecordType>(); 49 if (!RT) 50 return; 51 52 CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl()); 53 if (RD->hasTrivialDestructor()) 54 return; 55 56 CXXDestructorDecl *Dtor = RD->getDestructor(Context); 57 58 llvm::Constant *DtorFn; 59 if (Array) { 60 DtorFn = 61 CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, 62 Array, 63 DeclPtr); 64 const llvm::Type *Int8PtrTy = 65 llvm::Type::getInt8PtrTy(CGM.getLLVMContext()); 66 DeclPtr = llvm::Constant::getNullValue(Int8PtrTy); 67 } else 68 DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete); 69 70 CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr); 71 } 72} 73 74void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D, 75 llvm::Constant *DeclPtr) { 76 77 const Expr *Init = D.getInit(); 78 QualType T = D.getType(); 79 80 if (!T->isReferenceType()) { 81 EmitDeclInit(*this, D, DeclPtr); 82 return; 83 } 84 if (Init->isLvalue(getContext()) == Expr::LV_Valid) { 85 RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); 86 EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); 87 return; 88 } 89 ErrorUnsupported(Init, 90 "global variable that binds reference to a non-lvalue"); 91} 92 93void 94CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, 95 llvm::Constant *DeclPtr) { 96 // Generate a global destructor entry if not using __cxa_atexit. 97 if (!CGM.getCodeGenOpts().CXAAtExit) { 98 CGM.AddCXXDtorEntry(DtorFn, DeclPtr); 99 return; 100 } 101 102 const llvm::Type *Int8PtrTy = 103 llvm::Type::getInt8Ty(VMContext)->getPointerTo(); 104 105 std::vector<const llvm::Type *> Params; 106 Params.push_back(Int8PtrTy); 107 108 // Get the destructor function type 109 const llvm::Type *DtorFnTy = 110 llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); 111 DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); 112 113 Params.clear(); 114 Params.push_back(DtorFnTy); 115 Params.push_back(Int8PtrTy); 116 Params.push_back(Int8PtrTy); 117 118 // Get the __cxa_atexit function type 119 // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); 120 const llvm::FunctionType *AtExitFnTy = 121 llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); 122 123 llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, 124 "__cxa_atexit"); 125 126 llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, 127 "__dso_handle"); 128 llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), 129 llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), 130 llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; 131 Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); 132} 133 134void 135CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) { 136 const llvm::FunctionType *FTy 137 = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 138 false); 139 140 // Create a variable initialization function. 141 llvm::Function *Fn = 142 llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, 143 "__cxx_global_var_init", &TheModule); 144 145 CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D); 146 147 CXXGlobalInits.push_back(Fn); 148} 149 150void 151CodeGenModule::EmitCXXGlobalInitFunc() { 152 if (CXXGlobalInits.empty()) 153 return; 154 155 const llvm::FunctionType *FTy 156 = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 157 false); 158 159 // Create our global initialization function. 160 llvm::Function *Fn = 161 llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, 162 "_GLOBAL__I_a", &TheModule); 163 164 CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, 165 &CXXGlobalInits[0], 166 CXXGlobalInits.size()); 167 AddGlobalCtor(Fn); 168} 169 170void CodeGenModule::AddCXXDtorEntry(llvm::Constant *DtorFn, 171 llvm::Constant *Object) { 172 CXXGlobalDtors.push_back(std::make_pair(DtorFn, Object)); 173} 174 175void CodeGenModule::EmitCXXGlobalDtorFunc() { 176 if (CXXGlobalDtors.empty()) 177 return; 178 179 const llvm::FunctionType *FTy 180 = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 181 false); 182 183 // Create our global destructor function. 184 llvm::Function *Fn = 185 llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, 186 "_GLOBAL__D_a", &TheModule); 187 188 CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors); 189 AddGlobalDtor(Fn); 190} 191 192void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, 193 const VarDecl *D) { 194 StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), 195 SourceLocation()); 196 197 llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); 198 EmitCXXGlobalVarDeclInit(*D, DeclPtr); 199 200 FinishFunction(); 201} 202 203void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, 204 llvm::Constant **Decls, 205 unsigned NumDecls) { 206 StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), 207 SourceLocation()); 208 209 for (unsigned i = 0; i != NumDecls; ++i) 210 Builder.CreateCall(Decls[i]); 211 212 FinishFunction(); 213} 214 215void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn, 216 const std::vector<std::pair<llvm::Constant*, llvm::Constant*> > 217 &DtorsAndObjects) { 218 StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), 219 SourceLocation()); 220 221 // Emit the dtors, in reverse order from construction. 222 for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) 223 Builder.CreateCall(DtorsAndObjects[e - i - 1].first, 224 DtorsAndObjects[e - i - 1].second); 225 226 FinishFunction(); 227} 228 229static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) { 230 // int __cxa_guard_acquire(__int64_t *guard_object); 231 232 const llvm::Type *Int64PtrTy = 233 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 234 235 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 236 237 const llvm::FunctionType *FTy = 238 llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy), 239 Args, /*isVarArg=*/false); 240 241 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); 242} 243 244static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) { 245 // void __cxa_guard_release(__int64_t *guard_object); 246 247 const llvm::Type *Int64PtrTy = 248 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 249 250 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 251 252 const llvm::FunctionType *FTy = 253 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 254 Args, /*isVarArg=*/false); 255 256 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); 257} 258 259static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) { 260 // void __cxa_guard_abort(__int64_t *guard_object); 261 262 const llvm::Type *Int64PtrTy = 263 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 264 265 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 266 267 const llvm::FunctionType *FTy = 268 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 269 Args, /*isVarArg=*/false); 270 271 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); 272} 273 274void 275CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, 276 llvm::GlobalVariable *GV) { 277 bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; 278 279 llvm::SmallString<256> GuardVName; 280 CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); 281 282 // Create the guard variable. 283 const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext); 284 llvm::GlobalValue *GuardVariable = 285 new llvm::GlobalVariable(CGM.getModule(), Int64Ty, 286 false, GV->getLinkage(), 287 llvm::Constant::getNullValue(Int64Ty), 288 GuardVName.str()); 289 290 // Load the first byte of the guard variable. 291 const llvm::Type *PtrTy 292 = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); 293 llvm::Value *V = 294 Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp"); 295 296 llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check"); 297 llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); 298 299 // Check if the first byte of the guard variable is zero. 300 Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"), 301 InitCheckBlock, EndBlock); 302 303 EmitBlock(InitCheckBlock); 304 305 if (ThreadsafeStatics) { 306 // Call __cxa_guard_acquire. 307 V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable); 308 309 llvm::BasicBlock *InitBlock = createBasicBlock("init"); 310 311 Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), 312 InitBlock, EndBlock); 313 314 EmitBlock(InitBlock); 315 316 if (Exceptions) { 317 EHCleanupBlock Cleanup(*this); 318 319 // Call __cxa_guard_abort. 320 Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); 321 } 322 } 323 324 if (D.getType()->isReferenceType()) { 325 QualType T = D.getType(); 326 // We don't want to pass true for IsInitializer here, because a static 327 // reference to a temporary does not extend its lifetime. 328 RValue RV = EmitReferenceBindingToExpr(D.getInit(), 329 /*IsInitializer=*/false); 330 EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); 331 332 } else 333 EmitDeclInit(*this, D, GV); 334 335 if (ThreadsafeStatics) { 336 // Call __cxa_guard_release. 337 Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); 338 } else { 339 llvm::Value *One = 340 llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1); 341 Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy)); 342 } 343 344 EmitBlock(EndBlock); 345} 346