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