llvm-project/clang/lib/CodeGen/CGDeclCXX.cpp
Fariborz Jahanian 1518a5eca7 Do the guarding of instantiated static data members
on if its linkage is weak. Currently this is the
case but may change in the future. (part of radar 
8562966).

llvm-svn: 117452
2010-10-27 16:21:54 +00:00

339 lines
12 KiB
C++

//===--- CGDeclCXX.cpp - Emit LLVM Code for C++ declarations --------------===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
//
// This contains code dealing with code generation of C++ declarations
//
//===----------------------------------------------------------------------===//
#include "CodeGenFunction.h"
#include "CGCXXABI.h"
#include "clang/Frontend/CodeGenOptions.h"
#include "llvm/Intrinsics.h"
using namespace clang;
using namespace CodeGen;
static void EmitDeclInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::Constant *DeclPtr) {
assert(D.hasGlobalStorage() && "VarDecl must have global storage!");
assert(!D.getType()->isReferenceType() &&
"Should not call EmitDeclInit on a reference!");
ASTContext &Context = CGF.getContext();
const Expr *Init = D.getInit();
QualType T = D.getType();
bool isVolatile = Context.getCanonicalType(T).isVolatileQualified();
unsigned Alignment = Context.getDeclAlign(&D).getQuantity();
if (!CGF.hasAggregateLLVMType(T)) {
llvm::Value *V = CGF.EmitScalarExpr(Init);
CGF.EmitStoreOfScalar(V, DeclPtr, isVolatile, Alignment, T);
} else if (T->isAnyComplexType()) {
CGF.EmitComplexExprIntoAddr(Init, DeclPtr, isVolatile);
} else {
CGF.EmitAggExpr(Init, AggValueSlot::forAddr(DeclPtr, isVolatile, true));
}
}
/// Emit code to cause the destruction of the given variable with
/// static storage duration.
static void EmitDeclDestroy(CodeGenFunction &CGF, const VarDecl &D,
llvm::Constant *DeclPtr) {
CodeGenModule &CGM = CGF.CGM;
ASTContext &Context = CGF.getContext();
QualType T = D.getType();
// Drill down past array types.
const ConstantArrayType *Array = Context.getAsConstantArrayType(T);
if (Array)
T = Context.getBaseElementType(Array);
/// If that's not a record, we're done.
/// FIXME: __attribute__((cleanup)) ?
const RecordType *RT = T->getAs<RecordType>();
if (!RT)
return;
CXXRecordDecl *RD = cast<CXXRecordDecl>(RT->getDecl());
if (RD->hasTrivialDestructor())
return;
CXXDestructorDecl *Dtor = RD->getDestructor();
llvm::Constant *DtorFn;
if (Array) {
DtorFn =
CodeGenFunction(CGM).GenerateCXXAggrDestructorHelper(Dtor, Array,
DeclPtr);
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8PtrTy(CGM.getLLVMContext());
DeclPtr = llvm::Constant::getNullValue(Int8PtrTy);
} else
DtorFn = CGM.GetAddrOfCXXDestructor(Dtor, Dtor_Complete);
CGF.EmitCXXGlobalDtorRegistration(DtorFn, DeclPtr);
}
void CodeGenFunction::EmitCXXGlobalVarDeclInit(const VarDecl &D,
llvm::Constant *DeclPtr) {
const Expr *Init = D.getInit();
QualType T = D.getType();
if (!T->isReferenceType()) {
EmitDeclInit(*this, D, DeclPtr);
EmitDeclDestroy(*this, D, DeclPtr);
return;
}
unsigned Alignment = getContext().getDeclAlign(&D).getQuantity();
RValue RV = EmitReferenceBindingToExpr(Init, &D);
EmitStoreOfScalar(RV.getScalarVal(), DeclPtr, false, Alignment, T);
}
void
CodeGenFunction::EmitCXXGlobalDtorRegistration(llvm::Constant *DtorFn,
llvm::Constant *DeclPtr) {
// Generate a global destructor entry if not using __cxa_atexit.
if (!CGM.getCodeGenOpts().CXAAtExit) {
CGM.AddCXXDtorEntry(DtorFn, DeclPtr);
return;
}
const llvm::Type *Int8PtrTy =
llvm::Type::getInt8Ty(VMContext)->getPointerTo();
std::vector<const llvm::Type *> Params;
Params.push_back(Int8PtrTy);
// Get the destructor function type
const llvm::Type *DtorFnTy =
llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext), Params, false);
DtorFnTy = llvm::PointerType::getUnqual(DtorFnTy);
Params.clear();
Params.push_back(DtorFnTy);
Params.push_back(Int8PtrTy);
Params.push_back(Int8PtrTy);
// Get the __cxa_atexit function type
// extern "C" int __cxa_atexit ( void (*f)(void *), void *p, void *d );
const llvm::FunctionType *AtExitFnTy =
llvm::FunctionType::get(ConvertType(getContext().IntTy), Params, false);
llvm::Constant *AtExitFn = CGM.CreateRuntimeFunction(AtExitFnTy,
"__cxa_atexit");
llvm::Constant *Handle = CGM.CreateRuntimeVariable(Int8PtrTy,
"__dso_handle");
llvm::Value *Args[3] = { llvm::ConstantExpr::getBitCast(DtorFn, DtorFnTy),
llvm::ConstantExpr::getBitCast(DeclPtr, Int8PtrTy),
llvm::ConstantExpr::getBitCast(Handle, Int8PtrTy) };
Builder.CreateCall(AtExitFn, &Args[0], llvm::array_endof(Args));
}
void CodeGenFunction::EmitCXXStaticLocalInit(const VarDecl &D,
llvm::GlobalVariable *DeclPtr) {
CGM.getCXXABI().EmitStaticLocalInit(*this, D, DeclPtr);
}
static llvm::Function *
CreateGlobalInitOrDestructFunction(CodeGenModule &CGM,
const llvm::FunctionType *FTy,
llvm::StringRef Name) {
llvm::Function *Fn =
llvm::Function::Create(FTy, llvm::GlobalValue::InternalLinkage,
Name, &CGM.getModule());
// Set the section if needed.
if (const char *Section =
CGM.getContext().Target.getStaticInitSectionSpecifier())
Fn->setSection(Section);
if (!CGM.getLangOptions().Exceptions)
Fn->setDoesNotThrow();
return Fn;
}
void
CodeGenModule::EmitCXXGlobalVarDeclInitFunc(const VarDecl *D) {
const llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
// Create a variable initialization function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "__cxx_global_var_init");
CodeGenFunction(*this).GenerateCXXGlobalVarDeclInitFunc(Fn, D);
if (D->hasAttr<InitPriorityAttr>()) {
unsigned int order = D->getAttr<InitPriorityAttr>()->getPriority();
OrderGlobalInits Key(order, PrioritizedCXXGlobalInits.size());
PrioritizedCXXGlobalInits.push_back(std::make_pair(Key, Fn));
DelayedCXXInitPosition.erase(D);
}
else {
llvm::DenseMap<const Decl *, unsigned>::iterator I =
DelayedCXXInitPosition.find(D);
if (I == DelayedCXXInitPosition.end()) {
CXXGlobalInits.push_back(Fn);
} else {
assert(CXXGlobalInits[I->second] == 0);
CXXGlobalInits[I->second] = Fn;
DelayedCXXInitPosition.erase(I);
}
}
}
void
CodeGenModule::EmitCXXGlobalInitFunc() {
while (!CXXGlobalInits.empty() && !CXXGlobalInits.back())
CXXGlobalInits.pop_back();
if (CXXGlobalInits.empty() && PrioritizedCXXGlobalInits.empty())
return;
const llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
// Create our global initialization function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__I_a");
if (!PrioritizedCXXGlobalInits.empty()) {
llvm::SmallVector<llvm::Constant*, 8> LocalCXXGlobalInits;
llvm::array_pod_sort(PrioritizedCXXGlobalInits.begin(),
PrioritizedCXXGlobalInits.end());
for (unsigned i = 0; i < PrioritizedCXXGlobalInits.size(); i++) {
llvm::Function *Fn = PrioritizedCXXGlobalInits[i].second;
LocalCXXGlobalInits.push_back(Fn);
}
LocalCXXGlobalInits.append(CXXGlobalInits.begin(), CXXGlobalInits.end());
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&LocalCXXGlobalInits[0],
LocalCXXGlobalInits.size());
}
else
CodeGenFunction(*this).GenerateCXXGlobalInitFunc(Fn,
&CXXGlobalInits[0],
CXXGlobalInits.size());
AddGlobalCtor(Fn);
}
void CodeGenModule::EmitCXXGlobalDtorFunc() {
if (CXXGlobalDtors.empty())
return;
const llvm::FunctionType *FTy
= llvm::FunctionType::get(llvm::Type::getVoidTy(VMContext),
false);
// Create our global destructor function.
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(*this, FTy, "_GLOBAL__D_a");
CodeGenFunction(*this).GenerateCXXGlobalDtorFunc(Fn, CXXGlobalDtors);
AddGlobalDtor(Fn);
}
void CodeGenFunction::GenerateCXXGlobalVarDeclInitFunc(llvm::Function *Fn,
const VarDecl *D) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
llvm::Constant *DeclPtr = CGM.GetAddrOfGlobalVar(D);
if (D->isStaticDataMember() &&
D->getInstantiatedFromStaticDataMember() && D->getInit()){
llvm::GlobalVariable *GV = dyn_cast<llvm::GlobalVariable>(DeclPtr);
assert(GV && "GenerateCXXGlobalVarDeclInitFunc - GV is null");
llvm::GlobalValue::LinkageTypes Linkage =
CGM.GetLLVMLinkageVarDefinition(D, GV);
if (Linkage == llvm::GlobalVariable::WeakAnyLinkage) {
GV->setConstant(false);
EmitCXXStaticLocalInit(*D, GV);
FinishFunction();
return;
}
}
EmitCXXGlobalVarDeclInit(*D, DeclPtr);
FinishFunction();
}
void CodeGenFunction::GenerateCXXGlobalInitFunc(llvm::Function *Fn,
llvm::Constant **Decls,
unsigned NumDecls) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
for (unsigned i = 0; i != NumDecls; ++i)
if (Decls[i])
Builder.CreateCall(Decls[i]);
FinishFunction();
}
void CodeGenFunction::GenerateCXXGlobalDtorFunc(llvm::Function *Fn,
const std::vector<std::pair<llvm::WeakVH, llvm::Constant*> >
&DtorsAndObjects) {
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, FunctionArgList(),
SourceLocation());
// Emit the dtors, in reverse order from construction.
for (unsigned i = 0, e = DtorsAndObjects.size(); i != e; ++i) {
llvm::Value *Callee = DtorsAndObjects[e - i - 1].first;
llvm::CallInst *CI = Builder.CreateCall(Callee,
DtorsAndObjects[e - i - 1].second);
// Make sure the call and the callee agree on calling convention.
if (llvm::Function *F = dyn_cast<llvm::Function>(Callee))
CI->setCallingConv(F->getCallingConv());
}
FinishFunction();
}
/// GenerateCXXAggrDestructorHelper - Generates a helper function which when
/// invoked, calls the default destructor on array elements in reverse order of
/// construction.
llvm::Function *
CodeGenFunction::GenerateCXXAggrDestructorHelper(const CXXDestructorDecl *D,
const ArrayType *Array,
llvm::Value *This) {
FunctionArgList Args;
ImplicitParamDecl *Dst =
ImplicitParamDecl::Create(getContext(), 0,
SourceLocation(), 0,
getContext().getPointerType(getContext().VoidTy));
Args.push_back(std::make_pair(Dst, Dst->getType()));
const CGFunctionInfo &FI =
CGM.getTypes().getFunctionInfo(getContext().VoidTy, Args,
FunctionType::ExtInfo());
const llvm::FunctionType *FTy = CGM.getTypes().GetFunctionType(FI, false);
llvm::Function *Fn =
CreateGlobalInitOrDestructFunction(CGM, FTy, "__cxx_global_array_dtor");
StartFunction(GlobalDecl(), getContext().VoidTy, Fn, Args, SourceLocation());
QualType BaseElementTy = getContext().getBaseElementType(Array);
const llvm::Type *BasePtr = ConvertType(BaseElementTy)->getPointerTo();
llvm::Value *BaseAddrPtr = Builder.CreateBitCast(This, BasePtr);
EmitCXXAggrDestructorCall(D, Array, BaseAddrPtr);
FinishFunction();
return Fn;
}