From 355bba72ca52c4a70ca3c3802412c03a6ec31f24 Mon Sep 17 00:00:00 2001 From: John McCall Date: Fri, 30 Mar 2012 21:00:39 +0000 Subject: [PATCH] Make sure we unique static-local decls across multiple emissions of the function body, but do so in a way that doesn't make any assumptions about the static local actually having a proper, unique mangling, since apparently we don't do that correctly at all. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@153776 91177308-0d34-0410-b5e6-96231b3b80d8 --- lib/CodeGen/CGDecl.cpp | 42 ++++++++++-------- lib/CodeGen/CodeGenModule.h | 9 ++++ lib/CodeGen/ItaniumCXXABI.cpp | 76 ++++++++++++++++++--------------- test/CodeGenCXX/static-init.cpp | 71 ++++++++++++++++++++++++++++++ 4 files changed, 147 insertions(+), 51 deletions(-) diff --git a/lib/CodeGen/CGDecl.cpp b/lib/CodeGen/CGDecl.cpp index 970f0b2389..8c154f0708 100644 --- a/lib/CodeGen/CGDecl.cpp +++ b/lib/CodeGen/CGDecl.cpp @@ -273,11 +273,23 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, llvm::Value *&DMEntry = LocalDeclMap[&D]; assert(DMEntry == 0 && "Decl already exists in localdeclmap!"); - llvm::GlobalVariable *GV = CreateStaticVarDecl(D, ".", Linkage); + // Check to see if we already have a global variable for this + // declaration. This can happen when double-emitting function + // bodies, e.g. with complete and base constructors. + llvm::Constant *addr = + CGM.getStaticLocalDeclAddress(&D); + + llvm::GlobalVariable *var; + if (addr) { + var = cast(addr->stripPointerCasts()); + } else { + addr = var = CreateStaticVarDecl(D, ".", Linkage); + } // Store into LocalDeclMap before generating initializer to handle // circular references. - DMEntry = GV; + DMEntry = addr; + CGM.setStaticLocalDeclAddress(&D, addr); // We can't have a VLA here, but we can have a pointer to a VLA, // even though that doesn't really make any sense. @@ -285,42 +297,38 @@ void CodeGenFunction::EmitStaticVarDecl(const VarDecl &D, if (D.getType()->isVariablyModifiedType()) EmitVariablyModifiedType(D.getType()); - // Local static block variables must be treated as globals as they may be - // referenced in their RHS initializer block-literal expresion. - CGM.setStaticLocalDeclAddress(&D, GV); + // Save the type in case adding the initializer forces a type change. + llvm::Type *expectedType = addr->getType(); // If this value has an initializer, emit it. if (D.getInit()) - GV = AddInitializerToStaticVarDecl(D, GV); + var = AddInitializerToStaticVarDecl(D, var); - GV->setAlignment(getContext().getDeclAlign(&D).getQuantity()); + var->setAlignment(getContext().getDeclAlign(&D).getQuantity()); if (D.hasAttr()) - CGM.AddGlobalAnnotations(&D, GV); + CGM.AddGlobalAnnotations(&D, var); if (const SectionAttr *SA = D.getAttr()) - GV->setSection(SA->getName()); + var->setSection(SA->getName()); if (D.hasAttr()) - CGM.AddUsedGlobal(GV); + CGM.AddUsedGlobal(var); // We may have to cast the constant because of the initializer // mismatch above. // // FIXME: It is really dangerous to store this in the map; if anyone // RAUW's the GV uses of this constant will be invalid. - llvm::Type *LTy = CGM.getTypes().ConvertTypeForMem(D.getType()); - llvm::Type *LPtrTy = - LTy->getPointerTo(CGM.getContext().getTargetAddressSpace(D.getType())); - llvm::Constant *CastedVal = llvm::ConstantExpr::getBitCast(GV, LPtrTy); - DMEntry = CastedVal; - CGM.setStaticLocalDeclAddress(&D, CastedVal); + llvm::Constant *castedAddr = llvm::ConstantExpr::getBitCast(var, expectedType); + DMEntry = castedAddr; + CGM.setStaticLocalDeclAddress(&D, castedAddr); // Emit global variable debug descriptor for static vars. CGDebugInfo *DI = getDebugInfo(); if (DI) { DI->setLocation(D.getLocation()); - DI->EmitGlobalVariable(static_cast(GV), &D); + DI->EmitGlobalVariable(var, &D); } } diff --git a/lib/CodeGen/CodeGenModule.h b/lib/CodeGen/CodeGenModule.h index 5719afb612..38f5008d89 100644 --- a/lib/CodeGen/CodeGenModule.h +++ b/lib/CodeGen/CodeGenModule.h @@ -280,6 +280,7 @@ class CodeGenModule : public CodeGenTypeCache { llvm::StringMap CFConstantStringMap; llvm::StringMap ConstantStringMap; llvm::DenseMap StaticLocalDeclMap; + llvm::DenseMap StaticLocalDeclGuardMap; llvm::DenseMap AtomicSetterHelperFnMap; llvm::DenseMap AtomicGetterHelperFnMap; @@ -405,6 +406,14 @@ public: StaticLocalDeclMap[D] = C; } + llvm::GlobalVariable *getStaticLocalDeclGuardAddress(const VarDecl *D) { + return StaticLocalDeclGuardMap[D]; + } + void setStaticLocalDeclGuardAddress(const VarDecl *D, + llvm::GlobalVariable *C) { + StaticLocalDeclGuardMap[D] = C; + } + llvm::Constant *getAtomicSetterHelperFnMap(QualType Ty) { return AtomicSetterHelperFnMap[Ty]; } diff --git a/lib/CodeGen/ItaniumCXXABI.cpp b/lib/CodeGen/ItaniumCXXABI.cpp index 6fcf83d5ac..98f67f34df 100644 --- a/lib/CodeGen/ItaniumCXXABI.cpp +++ b/lib/CodeGen/ItaniumCXXABI.cpp @@ -1064,8 +1064,8 @@ namespace { /// just special-case it at particular places. void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, const VarDecl &D, - llvm::GlobalVariable *GV, - bool PerformInit) { + llvm::GlobalVariable *var, + bool shouldPerformInit) { CGBuilderTy &Builder = CGF.Builder; // We only need to use thread-safe statics for local variables; @@ -1073,35 +1073,44 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, bool threadsafe = (getContext().getLangOpts().ThreadsafeStatics && D.isLocalVarDecl()); - llvm::IntegerType *GuardTy; - // 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. - bool useInt8GuardVariable = !threadsafe && GV->hasInternalLinkage(); + bool useInt8GuardVariable = !threadsafe && var->hasInternalLinkage(); + + llvm::IntegerType *guardTy; if (useInt8GuardVariable) { - GuardTy = CGF.Int8Ty; + guardTy = CGF.Int8Ty; } else { // Guard variables are 64 bits in the generic ABI and 32 bits on ARM. - GuardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty); + guardTy = (IsARM ? CGF.Int32Ty : CGF.Int64Ty); + } + llvm::PointerType *guardPtrTy = guardTy->getPointerTo(); + + // Create the guard variable if we don't already have it (as we + // might if we're double-emitting this function body). + llvm::GlobalVariable *guard = CGM.getStaticLocalDeclGuardAddress(&D); + if (!guard) { + // Mangle the name for the guard. + SmallString<256> guardName; + { + llvm::raw_svector_ostream out(guardName); + getMangleContext().mangleItaniumGuardVariable(&D, out); + out.flush(); + } + + // Create the guard variable with a zero-initializer. + // Just absorb linkage and visibility from the guarded variable. + guard = new llvm::GlobalVariable(CGM.getModule(), guardTy, + false, var->getLinkage(), + llvm::ConstantInt::get(guardTy, 0), + guardName.str()); + guard->setVisibility(var->getVisibility()); + + CGM.setStaticLocalDeclGuardAddress(&D, guard); } - llvm::PointerType *GuardPtrTy = GuardTy->getPointerTo(); - - // Create the guard variable. - SmallString<256> GuardVName; - llvm::raw_svector_ostream Out(GuardVName); - getMangleContext().mangleItaniumGuardVariable(&D, Out); - Out.flush(); - - // Just absorb linkage and visibility from the variable. - llvm::GlobalVariable *GuardVariable = - new llvm::GlobalVariable(CGM.getModule(), GuardTy, - false, GV->getLinkage(), - llvm::ConstantInt::get(GuardTy, 0), - GuardVName.str()); - GuardVariable->setVisibility(GV->getVisibility()); // Test whether the variable has completed initialization. - llvm::Value *IsInitialized; + llvm::Value *isInitialized; // ARM C++ ABI 3.2.3.1: // To support the potential use of initialization guard variables @@ -1115,9 +1124,9 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // ... // } if (IsARM && !useInt8GuardVariable) { - llvm::Value *V = Builder.CreateLoad(GuardVariable); + llvm::Value *V = Builder.CreateLoad(guard); V = Builder.CreateAnd(V, Builder.getInt32(1)); - IsInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); + isInitialized = Builder.CreateIsNull(V, "guard.uninitialized"); // Itanium C++ ABI 3.3.2: // The following is pseudo-code showing how these functions can be used: @@ -1135,9 +1144,8 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, // } } else { // Load the first byte of the guard variable. - llvm::Type *PtrTy = Builder.getInt8PtrTy(); llvm::LoadInst *LI = - Builder.CreateLoad(Builder.CreateBitCast(GuardVariable, PtrTy)); + Builder.CreateLoad(Builder.CreateBitCast(guard, CGM.Int8PtrTy)); LI->setAlignment(1); // Itanium ABI: @@ -1149,14 +1157,14 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, if (threadsafe) LI->setAtomic(llvm::Acquire); - IsInitialized = Builder.CreateIsNull(LI, "guard.uninitialized"); + isInitialized = Builder.CreateIsNull(LI, "guard.uninitialized"); } llvm::BasicBlock *InitCheckBlock = CGF.createBasicBlock("init.check"); llvm::BasicBlock *EndBlock = CGF.createBasicBlock("init.end"); // Check if the first byte of the guard variable is zero. - Builder.CreateCondBr(IsInitialized, InitCheckBlock, EndBlock); + Builder.CreateCondBr(isInitialized, InitCheckBlock, EndBlock); CGF.EmitBlock(InitCheckBlock); @@ -1164,7 +1172,7 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, if (threadsafe) { // Call __cxa_guard_acquire. llvm::Value *V - = Builder.CreateCall(getGuardAcquireFn(CGM, GuardPtrTy), GuardVariable); + = Builder.CreateCall(getGuardAcquireFn(CGM, guardPtrTy), guard); llvm::BasicBlock *InitBlock = CGF.createBasicBlock("init"); @@ -1172,22 +1180,22 @@ void ItaniumCXXABI::EmitGuardedInit(CodeGenFunction &CGF, InitBlock, EndBlock); // Call __cxa_guard_abort along the exceptional edge. - CGF.EHStack.pushCleanup(EHCleanup, GuardVariable); + CGF.EHStack.pushCleanup(EHCleanup, guard); CGF.EmitBlock(InitBlock); } // Emit the initializer and add a global destructor if appropriate. - CGF.EmitCXXGlobalVarDeclInit(D, GV, PerformInit); + CGF.EmitCXXGlobalVarDeclInit(D, var, shouldPerformInit); if (threadsafe) { // Pop the guard-abort cleanup if we pushed one. CGF.PopCleanupBlock(); // Call __cxa_guard_release. This cannot throw. - Builder.CreateCall(getGuardReleaseFn(CGM, GuardPtrTy), GuardVariable); + Builder.CreateCall(getGuardReleaseFn(CGM, guardPtrTy), guard); } else { - Builder.CreateStore(llvm::ConstantInt::get(GuardTy, 1), GuardVariable); + Builder.CreateStore(llvm::ConstantInt::get(guardTy, 1), guard); } CGF.EmitBlock(EndBlock); diff --git a/test/CodeGenCXX/static-init.cpp b/test/CodeGenCXX/static-init.cpp index a96cb7ac8e..7e840f5622 100644 --- a/test/CodeGenCXX/static-init.cpp +++ b/test/CodeGenCXX/static-init.cpp @@ -3,6 +3,7 @@ // CHECK: @_ZZ1hvE1i = internal global i32 0, align 4 // CHECK: @base_req = global [4 x i8] c"foo\00", align 1 +// CHECK: @_ZZN5test31BC1EvE1u = internal global { i8, [3 x i8] } { i8 97, [3 x i8] undef }, align 4 // CHECK: @_ZZN5test1L6getvarEiE3var = internal constant [4 x i32] [i32 1, i32 0, i32 2, i32 4], align 16 // CHECK: @_ZZ2h2vE1i = linkonce_odr global i32 0 // CHECK: @_ZGVZ2h2vE1i = linkonce_odr global i64 0 @@ -79,3 +80,73 @@ namespace union_static_local { c::main(); } } + +// rdar://problem/11091093 +// Static variables should be consistent across constructor +// or destructor variants. +namespace test2 { + struct A { + A(); + ~A(); + }; + + struct B : virtual A { + B(); + ~B(); + }; + + // If we ever implement this as a delegate ctor call, just change + // this to take variadic arguments or something. + extern int foo(); + B::B() { + static int x = foo(); + } + // CHECK: define void @_ZN5test21BC1Ev + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) + + // CHECK: define void @_ZN5test21BC2Ev + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BC1EvE1x to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BC1EvE1x) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BC1EvE1x, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BC1EvE1x) + + // This is just for completeness, because we actually emit this + // using a delegate dtor call. + B::~B() { + static int y = foo(); + } + // CHECK: define void @_ZN5test21BD1Ev( + // CHECK: call void @_ZN5test21BD2Ev( + + // CHECK: define void @_ZN5test21BD2Ev( + // CHECK: load atomic i8* bitcast (i64* @_ZGVZN5test21BD1EvE1y to i8*) acquire, + // CHECK: call i32 @__cxa_guard_acquire(i64* @_ZGVZN5test21BD1EvE1y) + // CHECK: [[T0:%.*]] = call i32 @_ZN5test23fooEv() + // CHECK: store i32 [[T0]], i32* @_ZZN5test21BD1EvE1y, + // CHECK: call void @__cxa_guard_release(i64* @_ZGVZN5test21BD1EvE1y) +} + +// This shouldn't error out. +namespace test3 { + struct A { + A(); + ~A(); + }; + + struct B : virtual A { + B(); + ~B(); + }; + + B::B() { + union U { char x; int i; }; + static U u = { 'a' }; + } + // CHECK: define void @_ZN5test31BC1Ev( + // CHECK: define void @_ZN5test31BC2Ev( +} -- 2.40.0