summaryrefslogtreecommitdiffstats
path: root/lib/CodeGen/ItaniumCXXABI.cpp
diff options
context:
space:
mode:
authordim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
committerdim <dim@FreeBSD.org>2013-06-10 20:45:12 +0000
commitea266cad53e3d49771fa38103913d3ec7a166694 (patch)
tree8f7776b7310bebaf415ac5b69e46e9f928c37144 /lib/CodeGen/ItaniumCXXABI.cpp
parentc72c57c9e9b69944e3e009cd5e209634839581d3 (diff)
downloadFreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.zip
FreeBSD-src-ea266cad53e3d49771fa38103913d3ec7a166694.tar.gz
Vendor import of clang tags/RELEASE_33/final r183502 (effectively, 3.3
release): http://llvm.org/svn/llvm-project/cfe/tags/RELEASE_33/final@183502
Diffstat (limited to 'lib/CodeGen/ItaniumCXXABI.cpp')
-rw-r--r--lib/CodeGen/ItaniumCXXABI.cpp192
1 files changed, 180 insertions, 12 deletions
diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp
index e25d422..e117e28 100644
--- a/lib/CodeGen/ItaniumCXXABI.cpp
+++ b/lib/CodeGen/ItaniumCXXABI.cpp
@@ -41,6 +41,20 @@ public:
ItaniumCXXABI(CodeGen::CodeGenModule &CGM, bool IsARM = false) :
CGCXXABI(CGM), IsARM(IsARM) { }
+ bool isReturnTypeIndirect(const CXXRecordDecl *RD) const {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ return !RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor();
+ }
+
+ RecordArgABI getRecordArgABI(const CXXRecordDecl *RD) const {
+ // Structures with either a non-trivial destructor or a non-trivial
+ // copy constructor are always indirect.
+ if (!RD->hasTrivialDestructor() || RD->hasNonTrivialCopyConstructor())
+ return RAA_Indirect;
+ return RAA_Default;
+ }
+
bool isZeroInitializable(const MemberPointerType *MPT);
llvm::Type *ConvertMemberPointerType(const MemberPointerType *MPT);
@@ -130,8 +144,16 @@ public:
void EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D,
llvm::GlobalVariable *DeclPtr, bool PerformInit);
- void registerGlobalDtor(CodeGenFunction &CGF, llvm::Constant *dtor,
- llvm::Constant *addr);
+ void registerGlobalDtor(CodeGenFunction &CGF, const VarDecl &D,
+ llvm::Constant *dtor, llvm::Constant *addr);
+
+ llvm::Function *getOrCreateThreadLocalWrapper(const VarDecl *VD,
+ llvm::GlobalVariable *Var);
+ void EmitThreadLocalInitFuncs(
+ llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ llvm::Function *InitFunc);
+ LValue EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+ const DeclRefExpr *DRE);
};
class ARMCXXABI : public ItaniumCXXABI {
@@ -177,7 +199,7 @@ public:
}
CodeGen::CGCXXABI *CodeGen::CreateItaniumCXXABI(CodeGenModule &CGM) {
- switch (CGM.getContext().getTargetInfo().getCXXABI().getKind()) {
+ switch (CGM.getTarget().getCXXABI().getKind()) {
// For IR-generation purposes, there's no significant difference
// between the ARM and iOS ABIs.
case TargetCXXABI::GenericARM:
@@ -1042,10 +1064,10 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
bool shouldPerformInit) {
CGBuilderTy &Builder = CGF.Builder;
- // We only need to use thread-safe statics for local variables;
+ // We only need to use thread-safe statics for local non-TLS variables;
// global initialization is always single-threaded.
- bool threadsafe =
- (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl());
+ bool threadsafe = getContext().getLangOpts().ThreadsafeStatics &&
+ D.isLocalVarDecl() && !D.getTLSKind();
// If we have a global variable with internal linkage and thread-safe statics
// are disabled, we can just let the guard variable be of type i8.
@@ -1080,6 +1102,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
llvm::ConstantInt::get(guardTy, 0),
guardName.str());
guard->setVisibility(var->getVisibility());
+ // If the variable is thread-local, so is its guard variable.
+ guard->setThreadLocalMode(var->getThreadLocalMode());
CGM.setStaticLocalDeclGuardAddress(&D, guard);
}
@@ -1180,7 +1204,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF,
/// Register a global destructor using __cxa_atexit.
static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::Constant *dtor,
- llvm::Constant *addr) {
+ llvm::Constant *addr,
+ bool TLS) {
+ const char *Name = "__cxa_atexit";
+ if (TLS) {
+ const llvm::Triple &T = CGF.getTarget().getTriple();
+ Name = T.isMacOSX() ? "_tlv_atexit" : "__cxa_thread_atexit";
+ }
+
// We're assuming that the destructor function is something we can
// reasonably call with the default CC. Go ahead and cast it to the
// right prototype.
@@ -1193,8 +1224,7 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
llvm::FunctionType::get(CGF.IntTy, paramTys, false);
// Fetch the actual function.
- llvm::Constant *atexit =
- CGF.CGM.CreateRuntimeFunction(atexitTy, "__cxa_atexit");
+ llvm::Constant *atexit = CGF.CGM.CreateRuntimeFunction(atexitTy, Name);
if (llvm::Function *fn = dyn_cast<llvm::Function>(atexit))
fn->setDoesNotThrow();
@@ -1212,12 +1242,15 @@ static void emitGlobalDtorWithCXAAtExit(CodeGenFunction &CGF,
/// Register a global destructor as best as we know how.
void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
+ const VarDecl &D,
llvm::Constant *dtor,
llvm::Constant *addr) {
// Use __cxa_atexit if available.
- if (CGM.getCodeGenOpts().CXAAtExit) {
- return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr);
- }
+ if (CGM.getCodeGenOpts().CXAAtExit)
+ return emitGlobalDtorWithCXAAtExit(CGF, dtor, addr, D.getTLSKind());
+
+ if (D.getTLSKind())
+ CGM.ErrorUnsupported(&D, "non-trivial TLS destruction");
// In Apple kexts, we want to add a global destructor entry.
// FIXME: shouldn't this be guarded by some variable?
@@ -1228,3 +1261,138 @@ void ItaniumCXXABI::registerGlobalDtor(CodeGenFunction &CGF,
CGF.registerGlobalDtorWithAtExit(dtor, addr);
}
+
+/// Get the appropriate linkage for the wrapper function. This is essentially
+/// the weak form of the variable's linkage; every translation unit which wneeds
+/// the wrapper emits a copy, and we want the linker to merge them.
+static llvm::GlobalValue::LinkageTypes getThreadLocalWrapperLinkage(
+ llvm::GlobalValue::LinkageTypes VarLinkage) {
+ if (llvm::GlobalValue::isLinkerPrivateLinkage(VarLinkage))
+ return llvm::GlobalValue::LinkerPrivateWeakLinkage;
+ // For internal linkage variables, we don't need an external or weak wrapper.
+ if (llvm::GlobalValue::isLocalLinkage(VarLinkage))
+ return VarLinkage;
+ return llvm::GlobalValue::WeakODRLinkage;
+}
+
+llvm::Function *
+ItaniumCXXABI::getOrCreateThreadLocalWrapper(const VarDecl *VD,
+ llvm::GlobalVariable *Var) {
+ // Mangle the name for the thread_local wrapper function.
+ SmallString<256> WrapperName;
+ {
+ llvm::raw_svector_ostream Out(WrapperName);
+ getMangleContext().mangleItaniumThreadLocalWrapper(VD, Out);
+ Out.flush();
+ }
+
+ if (llvm::Value *V = Var->getParent()->getNamedValue(WrapperName))
+ return cast<llvm::Function>(V);
+
+ llvm::Type *RetTy = Var->getType();
+ if (VD->getType()->isReferenceType())
+ RetTy = RetTy->getPointerElementType();
+
+ llvm::FunctionType *FnTy = llvm::FunctionType::get(RetTy, false);
+ llvm::Function *Wrapper = llvm::Function::Create(
+ FnTy, getThreadLocalWrapperLinkage(Var->getLinkage()), WrapperName.str(),
+ &CGM.getModule());
+ // Always resolve references to the wrapper at link time.
+ Wrapper->setVisibility(llvm::GlobalValue::HiddenVisibility);
+ return Wrapper;
+}
+
+void ItaniumCXXABI::EmitThreadLocalInitFuncs(
+ llvm::ArrayRef<std::pair<const VarDecl *, llvm::GlobalVariable *> > Decls,
+ llvm::Function *InitFunc) {
+ for (unsigned I = 0, N = Decls.size(); I != N; ++I) {
+ const VarDecl *VD = Decls[I].first;
+ llvm::GlobalVariable *Var = Decls[I].second;
+
+ // Mangle the name for the thread_local initialization function.
+ SmallString<256> InitFnName;
+ {
+ llvm::raw_svector_ostream Out(InitFnName);
+ getMangleContext().mangleItaniumThreadLocalInit(VD, Out);
+ Out.flush();
+ }
+
+ // If we have a definition for the variable, emit the initialization
+ // function as an alias to the global Init function (if any). Otherwise,
+ // produce a declaration of the initialization function.
+ llvm::GlobalValue *Init = 0;
+ bool InitIsInitFunc = false;
+ if (VD->hasDefinition()) {
+ InitIsInitFunc = true;
+ if (InitFunc)
+ Init =
+ new llvm::GlobalAlias(InitFunc->getType(), Var->getLinkage(),
+ InitFnName.str(), InitFunc, &CGM.getModule());
+ } else {
+ // Emit a weak global function referring to the initialization function.
+ // This function will not exist if the TU defining the thread_local
+ // variable in question does not need any dynamic initialization for
+ // its thread_local variables.
+ llvm::FunctionType *FnTy = llvm::FunctionType::get(CGM.VoidTy, false);
+ Init = llvm::Function::Create(
+ FnTy, llvm::GlobalVariable::ExternalWeakLinkage, InitFnName.str(),
+ &CGM.getModule());
+ }
+
+ if (Init)
+ Init->setVisibility(Var->getVisibility());
+
+ llvm::Function *Wrapper = getOrCreateThreadLocalWrapper(VD, Var);
+ llvm::LLVMContext &Context = CGM.getModule().getContext();
+ llvm::BasicBlock *Entry = llvm::BasicBlock::Create(Context, "", Wrapper);
+ CGBuilderTy Builder(Entry);
+ if (InitIsInitFunc) {
+ if (Init)
+ Builder.CreateCall(Init);
+ } else {
+ // Don't know whether we have an init function. Call it if it exists.
+ llvm::Value *Have = Builder.CreateIsNotNull(Init);
+ llvm::BasicBlock *InitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
+ llvm::BasicBlock *ExitBB = llvm::BasicBlock::Create(Context, "", Wrapper);
+ Builder.CreateCondBr(Have, InitBB, ExitBB);
+
+ Builder.SetInsertPoint(InitBB);
+ Builder.CreateCall(Init);
+ Builder.CreateBr(ExitBB);
+
+ Builder.SetInsertPoint(ExitBB);
+ }
+
+ // For a reference, the result of the wrapper function is a pointer to
+ // the referenced object.
+ llvm::Value *Val = Var;
+ if (VD->getType()->isReferenceType()) {
+ llvm::LoadInst *LI = Builder.CreateLoad(Val);
+ LI->setAlignment(CGM.getContext().getDeclAlign(VD).getQuantity());
+ Val = LI;
+ }
+
+ Builder.CreateRet(Val);
+ }
+}
+
+LValue ItaniumCXXABI::EmitThreadLocalDeclRefExpr(CodeGenFunction &CGF,
+ const DeclRefExpr *DRE) {
+ const VarDecl *VD = cast<VarDecl>(DRE->getDecl());
+ QualType T = VD->getType();
+ llvm::Type *Ty = CGF.getTypes().ConvertTypeForMem(T);
+ llvm::Value *Val = CGF.CGM.GetAddrOfGlobalVar(VD, Ty);
+ llvm::Function *Wrapper =
+ getOrCreateThreadLocalWrapper(VD, cast<llvm::GlobalVariable>(Val));
+
+ Val = CGF.Builder.CreateCall(Wrapper);
+
+ LValue LV;
+ if (VD->getType()->isReferenceType())
+ LV = CGF.MakeNaturalAlignAddrLValue(Val, T);
+ else
+ LV = CGF.MakeAddrLValue(Val, DRE->getType(),
+ CGF.getContext().getDeclAlign(VD));
+ // FIXME: need setObjCGCLValueClass?
+ return LV;
+}
OpenPOWER on IntegriCloud