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