CGDeclCXX.cpp revision 203955
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 if (Init->isLvalue(getContext()) == Expr::LV_Valid) { 84 RValue RV = EmitReferenceBindingToExpr(Init, /*IsInitializer=*/true); 85 EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, T); 86 return; 87 } 88 ErrorUnsupported(Init, 89 "global variable that binds reference to a non-lvalue"); 90} 91 92void 93CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn, 94 llvm::Constant *DeclPtr) { 95 const llvm::Type *Int8PtrTy = 96 llvm::Type::getInt8Ty(VMContext)->getPointerTo(); 97 98 std::vector<const llvm::Type *> Params; 99 Params.push_back(Int8PtrTy); 100 101 // Get the destructor function type 102 const llvm::Type *DtorFnTy = 103 llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false); 104 DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy); 105 106 Params.clear(); 107 Params.push_back(DtorFnTy); 108 Params.push_back(Int8PtrTy); 109 Params.push_back(Int8PtrTy); 110 111 // Get the __cxa_atexit function type 112 // extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d ); 113 const llvm::FunctionType *AtExitFnTy = 114 llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false); 115 116 llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy, 117 "__cxa_atexit"); 118 119 llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy, 120 "__dso_handle"); 121 llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy), 122 llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy), 123 llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) }; 124 Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args)); 125} 126 127void 128CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) { 129 const llvm::FunctionType *FTy 130 = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 131 false); 132 133 // Create a variable initialization function. 134 llvm::Function *Fn = 135 llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, 136 "__cxx_global_var_init", &TheModule); 137 138 CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D); 139 140 CXXGlobalInits.push_back(Fn); 141} 142 143void 144CodeGenModule::EmitCXXGlobalInitFunc() { 145 if (CXXGlobalInits.empty()) 146 return; 147 148 const llvm::FunctionType *FTy 149 = llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), 150 false); 151 152 // Create our global initialization function. 153 // FIXME: Should this be tweakable by targets? 154 llvm::Function *Fn = 155 llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage, 156 "__cxx_global_initialization", &TheModule); 157 158 CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn, 159 &CXXGlobalInits[0], 160 CXXGlobalInits.size()); 161 AddGlobalCtor(Fn); 162} 163 164void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn, 165 const VarDecl *D) { 166 StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), 167 SourceLocation()); 168 169 llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D); 170 EmitCXXGlobalVarDeclInit(*D, DeclPtr); 171 172 FinishFunction(); 173} 174 175void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn, 176 llvm::Constant **Decls, 177 unsigned NumDecls) { 178 StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(), 179 SourceLocation()); 180 181 for (unsigned i = 0; i != NumDecls; ++i) 182 Builder.CreateCall(Decls[i]); 183 184 FinishFunction(); 185} 186 187static llvm::Constant *getGuardAcquireFn(CodeGenFunction &CGF) { 188 // int __cxa_guard_acquire(__int64_t *guard_object); 189 190 const llvm::Type *Int64PtrTy = 191 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 192 193 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 194 195 const llvm::FunctionType *FTy = 196 llvm::FunctionType::get(CGF.ConvertType(CGF.getContext().IntTy), 197 Args, /*isVarArg=*/false); 198 199 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_acquire"); 200} 201 202static llvm::Constant *getGuardReleaseFn(CodeGenFunction &CGF) { 203 // void __cxa_guard_release(__int64_t *guard_object); 204 205 const llvm::Type *Int64PtrTy = 206 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 207 208 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 209 210 const llvm::FunctionType *FTy = 211 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 212 Args, /*isVarArg=*/false); 213 214 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_release"); 215} 216 217static llvm::Constant *getGuardAbortFn(CodeGenFunction &CGF) { 218 // void __cxa_guard_abort(__int64_t *guard_object); 219 220 const llvm::Type *Int64PtrTy = 221 llvm::Type::getInt64PtrTy(CGF.getLLVMContext()); 222 223 std::vector<const llvm::Type*> Args(1, Int64PtrTy); 224 225 const llvm::FunctionType *FTy = 226 llvm::FunctionType::get(llvm::Type::getVoidTy(CGF.getLLVMContext()), 227 Args, /*isVarArg=*/false); 228 229 return CGF.CGM.CreateRuntimeFunction(FTy, "__cxa_guard_abort"); 230} 231 232void 233CodeGenFunction::EmitStaticCXXBlockVarDeclInit(const VarDecl &D, 234 llvm::GlobalVariable *GV) { 235 bool ThreadsafeStatics = getContext().getLangOptions().ThreadsafeStatics; 236 237 llvm::SmallString<256> GuardVName; 238 CGM.getMangleContext().mangleGuardVariable(&D, GuardVName); 239 240 // Create the guard variable. 241 const llvm::Type *Int64Ty = llvm::Type::getInt64Ty(VMContext); 242 llvm::GlobalValue *GuardVariable = 243 new llvm::GlobalVariable(CGM.getModule(), Int64Ty, 244 false, GV->getLinkage(), 245 llvm::Constant::getNullValue(Int64Ty), 246 GuardVName.str()); 247 248 // Load the first byte of the guard variable. 249 const llvm::Type *PtrTy 250 = llvm::PointerType::get(llvm::Type::getInt8Ty(VMContext), 0); 251 llvm::Value *V = 252 Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy), "tmp"); 253 254 llvm::BasicBlock *InitCheckBlock = createBasicBlock("init.check"); 255 llvm::BasicBlock *EndBlock = createBasicBlock("init.end"); 256 257 // Check if the first byte of the guard variable is zero. 258 Builder.CreateCondBr(Builder.CreateIsNull(V, "tobool"), 259 InitCheckBlock, EndBlock); 260 261 EmitBlock(InitCheckBlock); 262 263 if (ThreadsafeStatics) { 264 // Call __cxa_guard_acquire. 265 V = Builder.CreateCall(getGuardAcquireFn(*this), GuardVariable); 266 267 llvm::BasicBlock *InitBlock = createBasicBlock("init"); 268 269 Builder.CreateCondBr(Builder.CreateIsNotNull(V, "tobool"), 270 InitBlock, EndBlock); 271 272 EmitBlock(InitBlock); 273 274 if (Exceptions) { 275 EHCleanupBlock Cleanup(*this); 276 277 // Call __cxa_guard_abort. 278 Builder.CreateCall(getGuardAbortFn(*this), GuardVariable); 279 } 280 } 281 282 if (D.getType()->isReferenceType()) { 283 QualType T = D.getType(); 284 // We don't want to pass true for IsInitializer here, because a static 285 // reference to a temporary does not extend its lifetime. 286 RValue RV = EmitReferenceBindingToExpr(D.getInit(), 287 /*IsInitializer=*/false); 288 EmitStoreOfScalar(RV.getScalarVal(), GV, /*Volatile=*/false, T); 289 290 } else 291 EmitDeclInit(*this, D, GV); 292 293 if (ThreadsafeStatics) { 294 // Call __cxa_guard_release. 295 Builder.CreateCall(getGuardReleaseFn(*this), GuardVariable); 296 } else { 297 llvm::Value *One = 298 llvm::ConstantInt::get(llvm::Type::getInt8Ty(VMContext), 1); 299 Builder.CreateStore(One, Builder.CreateBitCast(GuardVariable, PtrTy)); 300 } 301 302 EmitBlock(EndBlock); 303} 304